From f5b285833a3c5dd4578133b636dc6addf132c638 Mon Sep 17 00:00:00 2001 From: Maximilian Gerhardt Date: Wed, 18 Sep 2024 19:32:36 +0200 Subject: [PATCH] Add PDF_DataLogger example --- .github/workflows/examples.yml | 1 + .../usb-pdf-logger-none-os-ch592/.gitignore | 2 + .../usb-pdf-logger-none-os-ch592/README.md | 26 + .../include/README | 39 + .../include/peripheral.h | 97 +++ .../lib/FLASH/flash_info.c | 182 +++++ .../lib/FLASH/include/flash_info.h | 134 ++++ .../lib/FLASH/include/internal_flash.h | 34 + .../lib/FLASH/include/spi_flash.h | 104 +++ .../lib/FLASH/internal_flash.c | 35 + .../lib/FLASH/spi_flash.c | 447 +++++++++++ .../lib/PDF/include/pdfFile.h | 32 + .../lib/PDF/include/pdfTempe.h | 18 + .../lib/PDF/pdfFile.c | 252 +++++++ .../lib/PDF/pdfTempe.c | 274 +++++++ .../lib/PDF_LIB/libpdf.a | Bin 0 -> 95634 bytes .../lib/PDF_LIB/library.json | 11 + .../lib/PDF_LIB/pdf.h | 114 +++ .../lib/PDF_LIB/pdflib.h | 190 +++++ .../usb-pdf-logger-none-os-ch592/lib/README | 46 ++ .../lib/USB/include/sw_udisk.h | 158 ++++ .../lib/USB/include/usb_connect.h | 59 ++ .../lib/USB/include/usb_desc.h | 72 ++ .../lib/USB/include/usbfs_device.h | 90 +++ .../lib/USB/sw_udisk.c | 709 ++++++++++++++++++ .../lib/USB/usb_connect.c | 44 ++ .../lib/USB/usb_desc.c | 88 +++ .../lib/USB/usbfs_device.c | 529 +++++++++++++ .../lib/USB_LIB/CH592UFI.c | 330 ++++++++ .../lib/USB_LIB/CHRV3UFI.h | 346 +++++++++ .../lib/USB_LIB/CHRV3UF_README.TXT | 9 + .../lib/USB_LIB/libRV3UFI.a | Bin 0 -> 88222 bytes .../lib/USB_LIB/library.json | 11 + .../platformio.ini | 18 + .../src/peripheral_main.c | 194 +++++ .../usb-pdf-logger-none-os-ch592/test/README | 11 + 36 files changed, 4706 insertions(+) create mode 100644 examples/usb-pdf-logger-none-os-ch592/.gitignore create mode 100644 examples/usb-pdf-logger-none-os-ch592/README.md create mode 100644 examples/usb-pdf-logger-none-os-ch592/include/README create mode 100644 examples/usb-pdf-logger-none-os-ch592/include/peripheral.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/FLASH/flash_info.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/flash_info.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/internal_flash.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/spi_flash.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/FLASH/internal_flash.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/FLASH/spi_flash.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfFile.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfTempe.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfFile.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfTempe.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/libpdf.a create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/library.json create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdf.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdflib.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/README create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/include/sw_udisk.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_connect.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_desc.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usbfs_device.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/sw_udisk.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_connect.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_desc.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB/usbfs_device.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CH592UFI.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UFI.h create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UF_README.TXT create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/libRV3UFI.a create mode 100644 examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/library.json create mode 100644 examples/usb-pdf-logger-none-os-ch592/platformio.ini create mode 100644 examples/usb-pdf-logger-none-os-ch592/src/peripheral_main.c create mode 100644 examples/usb-pdf-logger-none-os-ch592/test/README diff --git a/.github/workflows/examples.yml b/.github/workflows/examples.yml index 9cd3adb..cb6ac38 100644 --- a/.github/workflows/examples.yml +++ b/.github/workflows/examples.yml @@ -34,6 +34,7 @@ jobs: - "examples/ble-usb-cdc-ch58x" - "examples/ble-hid-ch59x" - "examples/usb-pd-none-os" + - "examples/usb-pdf-logger-none-os-ch592" - "examples/zephyr-blink" runs-on: ${{ matrix.os }} steps: diff --git a/examples/usb-pdf-logger-none-os-ch592/.gitignore b/examples/usb-pdf-logger-none-os-ch592/.gitignore new file mode 100644 index 0000000..3b8da3a --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/.gitignore @@ -0,0 +1,2 @@ +.pio +.vscode \ No newline at end of file diff --git a/examples/usb-pdf-logger-none-os-ch592/README.md b/examples/usb-pdf-logger-none-os-ch592/README.md new file mode 100644 index 0000000..934e148 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/README.md @@ -0,0 +1,26 @@ +How to build PlatformIO based project +===================================== + +Project converted from https://github.com/openwch/ch592/blob/main/Application/PDF_DataLogger/CH592_PDF_Logger_USB. + +1. [Install PlatformIO Core](https://docs.platformio.org/page/core.html) +2. Download [development platform with examples](https://github.com/Community-PIO-CH32V/platform-ch32v/archive/develop.zip) +3. Extract ZIP archive +4. Run these commands: + +```shell +# Change directory to example +$ cd platform-ch32v/examples/usb-pdf-logger-none-os-ch592 + +# Build project +$ pio run + +# Upload firmware +$ pio run --target upload + +# Upload firmware for the specific environment +$ pio run -e genericCH592F --target upload + +# Clean build files +$ pio run --target clean +``` diff --git a/examples/usb-pdf-logger-none-os-ch592/include/README b/examples/usb-pdf-logger-none-os-ch592/include/README new file mode 100644 index 0000000..194dcd4 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/include/README @@ -0,0 +1,39 @@ + +This directory is intended for project header files. + +A header file is a file containing C declarations and macro definitions +to be shared between several project source files. You request the use of a +header file in your project source file (C, C++, etc) located in `src` folder +by including it, with the C preprocessing directive `#include'. + +```src/main.c + +#include "header.h" + +int main (void) +{ + ... +} +``` + +Including a header file produces the same results as copying the header file +into each source file that needs it. Such copying would be time-consuming +and error-prone. With a header file, the related declarations appear +in only one place. If they need to be changed, they can be changed in one +place, and programs that include the header file will automatically use the +new version when next recompiled. The header file eliminates the labor of +finding and changing all the copies as well as the risk that a failure to +find one copy will result in inconsistencies within a program. + +In C, the usual convention is to give header files names that end with `.h'. +It is most portable to use only letters, digits, dashes, and underscores in +header file names, and at most one dot. + +Read more about using header files in official GCC documentation: + +* Include Syntax +* Include Operation +* Once-Only Headers +* Computed Includes + +https://gcc.gnu.org/onlinedocs/cpp/Header-Files.html diff --git a/examples/usb-pdf-logger-none-os-ch592/include/peripheral.h b/examples/usb-pdf-logger-none-os-ch592/include/peripheral.h new file mode 100644 index 0000000..516c649 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/include/peripheral.h @@ -0,0 +1,97 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : peripheral.h + * Author : WCH + * Version : V1.0 + * Date : 2018/12/11 + * Description : + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ + +#ifndef PERIPHERAL_H +#define PERIPHERAL_H + +#ifdef __cplusplus +extern "C" { +#endif + +/********************************************************************* + * INCLUDES + */ + +/********************************************************************* + * CONSTANTS + */ + +// Peripheral Task Events +#define SBP_START_DEVICE_EVT 0x0001 +#define SBP_PERIODIC_EVT 0x0002 +#define SBP_READ_RSSI_EVT 0x0004 +#define SBP_PARAM_UPDATE_EVT 0x0008 +#define SBP_PHY_UPDATE_EVT 0x0010 +#define SBP_ENABLE_ADV_EVT 0x0020 +#define SBP_DISABLE_ADV_EVT 0x0040 + +/********************************************************************* + * MACROS + */ +typedef struct +{ + uint16_t connHandle; // Connection handle of current connection + uint16_t connInterval; + uint16_t connSlaveLatency; + uint16_t connTimeout; +} peripheralConnItem_t; + +extern uint8_t Peripheral_TaskID; // Task ID for internal task/event processing + + +//#include "CONFIG.h" +#include "pdfFile.h" +#include "sw_udisk.h" +#include "CHRV3UFI.h" + +typedef struct +{ + uint8_t pdf_data_buf[PDF_TMP_BUF_LEN_MAX+PDF_TMP_BUF_LEN_EXT]; + uint8_t UDisk_Down_Buffer[DEF_FLASH_SECTOR_SIZE]; + uint8_t UDisk_Pack_Buffer[DEF_UDISK_PACK_64]; + uint8_t DISK_BASE_BUF[DISK_BASE_BUF_LEN]; /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ + uint8_t DISK_FAT_BUF[ DISK_BASE_BUF_LEN ]; /* 外部RAM的磁盘FAT数据缓冲区,缓冲区长度为一个扇区的长度 */ +}PDF_BUFFER_t; + + +typedef union +{ +// uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4]; + PDF_BUFFER_t PDF_BUFFER; + +}RAM_BUFFER_t; + +extern RAM_BUFFER_t RAM_BUFFER; + + +/********************************************************************* + * FUNCTIONS + */ + +/* + * Task Initialization for the BLE Application + */ +extern void Peripheral_Init(void); + +/* + * Task Event Processor for the BLE Application + */ +extern uint16_t Peripheral_ProcessEvent(uint8_t task_id, uint16_t events); + +/********************************************************************* +*********************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/flash_info.c b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/flash_info.c new file mode 100644 index 0000000..7f13b39 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/flash_info.c @@ -0,0 +1,182 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : flash_info.c +* Author : WCH +* Version : V1.0 +* Date : 2021/10/19 +* Description : +*******************************************************************************/ + +/******************************************************************************/ +#include "flash_info.h" +#include "spi_flash.h" + +//#define CONFIG_FLASH_INFO_DEBUG +#ifdef CONFIG_FLASH_INFO_DEBUG +#define LOG_INFO(...) PRINT(__VA_ARGS__) +#else +#define LOG_INFO(...) +#endif + +/************************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************************/ +DEVICE_INFO_t DeviceInfo; //Device Information + +/************************************************************************************************** + * FUNCTIONS - Local + **************************************************************************************************/ +/************************************************************************************************** + * @fn HAL_SaveBondInfo + * + * @brief Save bond information in flash + * + * @param None + * + * @return SUCCESS or FAILURE + **************************************************************************************************/ +uint8_t HAL_SaveDeviceInfo(void) +{ + uint32_t StartAddr; + + if (DeviceInfo.InfoNum == DEVICEINFO_MAX) //flash已经存储满 + { + if (EEPROM_ERASE(DEVICEINFO_ADDR, DEVICEINFO_FLASH_SIZE) != SUCCESS) + { + LOG_INFO("ERROR1\n"); + return FAILURE; + } + DeviceInfo.InfoNum = 0; + } + + StartAddr = DEVICEINFO_ADDR + DEVICEINFO_LEN * DeviceInfo.InfoNum; + ++DeviceInfo.InfoNum; //Add in advance and need to save it in flash + DeviceInfo.Checksum = HAL_FlashChecksumCalculate((uint8_t*)&DeviceInfo, DEVICEINFO_LEN-1); + if (EEPROM_WRITE(StartAddr, &DeviceInfo, DEVICEINFO_LEN) != SUCCESS) //写flash + { + --DeviceInfo.InfoNum; + LOG_INFO("ERROR2\n"); + return FAILURE; + } + + return SUCCESS; +} + +/************************************************************************************************** + * @fn HAL_ReadBondInfo + * + * @brief Read the bond information in the flash + * + * @param None + * + * @return SUCCESS or FAILURE + **************************************************************************************************/ +uint8_t HAL_ReadDeviceInfo(void) +{ + uint32_t StartAddr; + uint16_t BufNum = 1; + + do + { + StartAddr = DEVICEINFO_ADDR + BufNum * DEVICEINFO_LEN; + EEPROM_READ(StartAddr, &DeviceInfo, 1); + ++BufNum; + } while ((DeviceInfo.CheckFlag != 0xFF) && (BufNum <= DEVICEINFO_MAX)); //Poll flash until find where the device information is stored + + if (BufNum > (DEVICEINFO_MAX + 1)) + { + LOG_INFO("ERROR3\n"); + return FAILURE; + } + + StartAddr = DEVICEINFO_ADDR + (BufNum - 2) * DEVICEINFO_LEN; + EEPROM_READ(StartAddr, &DeviceInfo, DEVICEINFO_LEN); //Read device information in flash + if ((DeviceInfo.CheckFlag != CHECK_VALUE) || (HAL_FlashChecksumCheck((uint8_t*)&DeviceInfo, DEVICEINFO_LEN-1))) //If device information has not been saved + { + memset((uint8_t*)&DeviceInfo, 0, DEVICEINFO_LEN); + DeviceInfo.CheckFlag = CHECK_VALUE; + DeviceInfo.InfoNum = DEVICEINFO_MAX; + DeviceInfo.PdfParam.MeasureInterval = DEFAULT_MEASURE_INTERVAL; //6min + DeviceInfo.PdfParam.TempUnit = CELSIUS_UNIT; + DeviceInfo.PdfParam.MaxTempAlarm = DEFAULT_TEMP_UPPER_LIMIT; + DeviceInfo.PdfParam.MinTempAlarm = DEFAULT_TEMP_LOWER_LIMIT; + DeviceInfo.PdfParam.MaxHumiAlarm = DEFAULT_HUMI_UPPER_LIMIT; + DeviceInfo.PdfParam.MinHumiAlarm = DEFAULT_HUMI_LOWER_LIMIT; + DeviceInfo.StartTime.Year = DEFAULT_START_YAER; + DeviceInfo.StartTime.Month = DEFAULT_START_MONTH; + DeviceInfo.StartTime.Day = DEFAULT_START_DAY; +// DeviceInfo.StartTime.Hour = DEFAULT_START_HOUR; +// DeviceInfo.StartTime.Minute = DEFAULT_START_MINUTE; +// DeviceInfo.StartTime.Second = DEFAULT_START_SECOND; + + if (HAL_SaveDeviceInfo() != SUCCESS) + { + LOG_INFO("ERROR4\n"); + return FAILURE; + } + + FLASH_ROM_ERASE(MEASURENT_DATA_ADDR, MEASURENT_DATA_FLASH_SIZE); + + for(uint16_t i=0; i<20; ++i) + { + LOG_INFO("%d\n", i); + FLASH_Erase_Sector(4096*i); + } + } + + return SUCCESS; +} + +/************************************************************************************************** + * @fn HAL_ChecksumCalculate + * + * @brief Calculate buffer checksum + * + * @param p_buf - address of buffer + * len - length of buffer + * + * @return Checksum value + **************************************************************************************************/ +uint8_t HAL_FlashChecksumCalculate(uint8_t *p_buf, uint16_t len) +{ + uint16_t i; + uint8_t check_sum = 0; + + for (i = 0; i < len; ++i) + { + check_sum = (uint8_t)(check_sum + p_buf[i]); + } + + return check_sum; +} + +/************************************************************************************************** + * @fn HAL_FlashChecksumCheck + * + * @brief Check buffer checksum + * + * @param p_buf - address of buffer + * len - length of buffer + * + * @return SUCCESS or FAILURE + **************************************************************************************************/ +uint8_t HAL_FlashChecksumCheck(uint8_t *p_buf, uint16_t len) +{ + uint16_t i; + uint8_t check_sum = 0; + + for (i = 0; i < len; ++i) + { + check_sum = (uint8_t)(check_sum + p_buf[i]); + } + + if (check_sum == p_buf[i]) + { + return SUCCESS; + } + else + { + return FAILURE; + } +} + +/******************************** endfile @ bond ******************************/ diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/flash_info.h b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/flash_info.h new file mode 100644 index 0000000..c790003 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/flash_info.h @@ -0,0 +1,134 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : flash_info.h +* Author : WCH +* Version : V1.0 +* Date : 2021/10/19 +* Description : +*******************************************************************************/ + +/******************************************************************************/ +#ifndef __FLASH_INFO_H_ +#define __FLASH_INFO_H_ + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "CH59x_common.h" + +/************************************************************************************************** + * MACROS + **************************************************************************************************/ +/* Save the number of saved temperature and humidity data and PDF parameters */ +#define CHECK_VALUE 0x5A //Detection value of whether the information saved in flash is valid +#define DEVICEINFO_ADDR (0x00070000-FLASH_ROM_MAX_SIZE) //Starting address of information saving in flash (DataFlash) +#define DEVICEINFO_FLASH_SIZE (8*1024) //Size used to save information in flash(8k) +#define DEVICEINFO_LEN 44 //Single information size +#define DEVICEINFO_MAX (DEVICEINFO_FLASH_SIZE/DEVICEINFO_LEN) //Number of information that can be saved in flash + +/* FLASH to save temperature and humidity data */ +#define MEASURENT_DATA_ADDR (268*1024) //Starting address of measurement data saving in flash (CodeFlash) +#define MEASURENT_DATA_FLASH_SIZE (180*1024) //Size used to save information in flash(100k) +#define TEMP_DATA_LEN 2 //Temperature data size +#define HUMI_DATA_LEN 2 //Humidity data size +#define MEASURENT_DATA_MAX (MEASURENT_DATA_FLASH_SIZE/(TEMP_DATA_LEN+HUMI_DATA_LEN)) //Number of measurement data that can be saved in flash + +/* Default device information parameters */ +#define CELSIUS_UNIT 0x00 //Celsius +#define FAHRENHEIT_UNIT 0x01 //Fahrenheit +#define DEFAULT_MEASURE_INTERVAL 6 //Measurement interval +#define DEFAULT_TEMP_UPPER_LIMIT (float)(35.0) //Temperature upper limit +#define DEFAULT_TEMP_LOWER_LIMIT (float)(-10.0) //Temperature lower limit +#define DEFAULT_HUMI_UPPER_LIMIT (float)(90.0) //Humidity upper limit +#define DEFAULT_HUMI_LOWER_LIMIT (float)(30.0) //Humidity lower limit +#define DEFAULT_START_YAER 2023 //Year +#define DEFAULT_START_MONTH 9 //Month +#define DEFAULT_START_DAY 20 //Day +#define DEFAULT_START_HOUR 0 //Hour +#define DEFAULT_START_MINUTE 0 //Minute +#define DEFAULT_START_SECOND 0 //Second + +#ifndef SUCCESS +#define SUCCESS 0x00 +#endif +#ifndef FAILURE +#define FAILURE 0x01 +#endif + +/************************************************************************************************** + * TYPEDEFS + **************************************************************************************************/ +/* define PDF parameters structure */ +typedef struct PDF_PARAM +{ + uint16_t MeasureInterval; //Measurement interval, units of 1min + uint8_t TempUnit; //Temperature unit, 0:°C, 1:°F + float MaxTempAlarm; //Alarm temperature upper limit + float MinTempAlarm; //Alarm temperature lower limit + float MaxHumiAlarm; //Alarm humidity upper limit + float MinHumiAlarm; //Alarm humidity lower limit +} PDF_PARAM_t; + +/* define PDF parameters structure */ +typedef struct START_TIME +{ + uint16_t Year; + uint8_t Month; + uint8_t Day; + uint8_t Hour; + uint8_t Minute; + uint8_t Second; +} START_TIME_t; + +/* define device information structure */ +typedef struct DEVICE_INFO +{ + uint8_t CheckFlag; //Message valid flag + uint16_t InfoNum; //Number of information stored in flash. Erase the flash once when it is full. + uint8_t StatusFlag; //0-factory setting state(enable few functions), 1-normal operation state + PDF_PARAM_t PdfParam; //PDF related parameters + uint32_t MeasureNum; //Number of saved measurement data + START_TIME_t StartTime; //System startup time + uint8_t Reserve[3]; //Reserve + uint8_t Checksum; //Checksum of the information +} DEVICE_INFO_t; + +/************************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************************/ +extern DEVICE_INFO_t DeviceInfo; //Device Information + +/********************************************************************* + * FUNCTIONS + */ + +/* + * Save device information in flash + */ +uint8_t HAL_SaveDeviceInfo(void); + +/* + * Read the device information in the flash + */ +uint8_t HAL_ReadDeviceInfo(void); + +/* + * Calculate buffer checksum + */ +uint8_t HAL_FlashChecksumCalculate(uint8_t *p_buf, uint16_t len); + +/* + * Check buffer checksum + */ +uint8_t HAL_FlashChecksumCheck(uint8_t *p_buf, uint16_t len); + + +/************************************************************************************************** +**************************************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif /* __FLASH_INFO_H_ */ diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/internal_flash.h b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/internal_flash.h new file mode 100644 index 0000000..5fadb89 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/internal_flash.h @@ -0,0 +1,34 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : Internal_Flash.h + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/08 + * Description : header file for Internal_Flash.c +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#ifndef USER_INTERNAL__FLASH_C_ +#define USER_INTERNAL__FLASH_C_ + +#ifdef __cplusplus + extern "C" { +#endif + +#include "CH59x_common.h" + +#define INTERNAL_FLASH_PAGE_SIZE 512 +#define IFLASH_UDISK_START_ADDR (128*1024) +#define IFLASH_UDISK_END_ADDR 0x6FFFF +#define IFLASH_UDISK_SIZE (IFLASH_UDISK_END_ADDR - IFLASH_UDISK_START_ADDR + 1 ) + +extern void IFlash_Prog_512(uint32_t address,uint32_t *pbuf); +extern void IFlash_Prog_512_Without_Erase(uint32_t address,uint32_t *pbuf); + +#ifdef __cplusplus +} +#endif + +#endif /* USER_INTERNAL__FLASH_C_ */ diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/spi_flash.h b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/spi_flash.h new file mode 100644 index 0000000..475947c --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/include/spi_flash.h @@ -0,0 +1,104 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : spi_flash.h + * Author : WCH + * Version : V1.0.1 + * Date : 2022/11/24 + * Description : SPI FLASH Chip operation file + ********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +/******************************************************************************/ + +#ifndef __SPI_FLASH_H_ +#define __SPI_FLASH_H_ + +#ifdef __cplusplus + extern "C" { +#endif + + /* header files */ + #include "CH59x_common.h" + +/************************************************************************************************** + * MACROS + **************************************************************************************************/ +/* SPI Pins */ +#define PIN_FLASH_CS_LOW( ) (R32_PA_CLR |= GPIO_Pin_12 ) +#define PIN_FLASH_CS_HIGH( ) (R32_PA_OUT |= GPIO_Pin_12 ) + +/******************************************************************************/ +/* SPI Serial Flash OPERATION INSTRUCTIONS */ +#define CMD_FLASH_READ 0x03 /* Read Memory at 25 MHz */ +#define CMD_FLASH_SECTOR_ERASE 0x20 /* Erase 4 KByte of memory array */ +#define CMD_FLASH_BYTE_PROG 0x02 /* To Program One Data Byte */ +#define CMD_FLASH_RDSR 0x05 /* Read-Status-Register */ +#define CMD_FLASH_EWSR 0x50 /* Enable-Write-Status-Register */ +#define CMD_FLASH_WREN 0x06 /* Write-Enable */ +#define CMD_FLASH_WRDI 0x04 /* Write-Disable */ +#define CMD_FLASH_JEDEC_ID 0x9F /* JEDEC ID read */ + +/******************************************************************************/ +#define DEF_DUMMY_BYTE 0xFF + +/******************************************************************************/ +/* FLASH Parameter Definition */ +#define SPI_FLASH_SectorSize 4096 +#define SPI_FLASH_PageSize 256 +#define SPI_FLASH_PerWritePageSize 256 + +/******************************************************************************/ +/* SPI FLASH Type */ +#define DEF_TYPE_W25XXX 0 /* W25XXX */ + +/******************************************************************************/ +/* SPI FLASH Type Define */ + +/* W25XXX*/ +#define W25X10_FLASH_ID 0xEF3011 /* 1M bit */ +#define W25X20_FLASH_ID 0xEF3012 /* 2M bit */ +#define W25X40_FLASH_ID 0xEF3013 /* 4M bit */ +#define W25X80_FLASH_ID 0xEF4014 /* 8M bit */ +#define W25Q16_FLASH_ID1 0xEF3015 /* 16M bit */ +#define W25Q16_FLASH_ID2 0xEF4015 /* 16M bit */ +#define W25Q32_FLASH_ID1 0xEF4016 /* 32M bit */ +#define W25Q32_FLASH_ID2 0xEF6016 /* 32M bit */ +#define W25Q64_FLASH_ID1 0xEF4017 /* 64M bit */ +#define W25Q64_FLASH_ID2 0xEF6017 /* 64M bit */ +#define W25Q128_FLASH_ID1 0xEF4018 /* 128M bit */ +#define W25Q128_FLASH_ID2 0xEF6018 /* 128M bit */ +#define W25Q256_FLASH_ID1 0xEF4019 /* 256M bit */ +#define W25Q256_FLASH_ID2 0xEF6019 /* 256M bit */ + +/******************************************************************************/ +/* Variable Definition */ +extern volatile uint8_t Flash_Type; /* FLASH chip: 0: W25XXXseries */ +extern volatile uint32_t Flash_ID; /* FLASH ID */ +extern volatile uint32_t Flash_Sector_Count; /* FLASH sector number */ +extern volatile uint16_t Flash_Sector_Size; /* FLASH sector size */ + +/******************************************************************************/ +/* external functions */ +extern void FLASH_Port_Init( void ); +extern uint8_t SPI_FLASH_SendByte( uint8_t byte ); +extern uint8_t SPI_FLASH_ReadByte( void ); +extern uint32_t FLASH_ReadID( void ); +extern void FLASH_WriteEnable( void ); +extern void FLASH_WriteDisable( void ); +extern uint8_t FLASH_ReadStatusReg( void ); +extern void FLASH_IC_Check( void ); +extern void FLASH_Erase_Sector( uint32_t address ); +extern void FLASH_RD_Block_Start( uint32_t address ); +extern void FLASH_RD_Block( uint8_t *pbuf, uint32_t len ); +extern void FLASH_RD_Block_End( void ); +extern void W25XXX_WR_Block( uint8_t *pbuf, uint32_t address, uint32_t len ); + +void W25XXX_WR_512B( uint8_t *pbuf, uint32_t address, uint32_t len ); + +#ifdef __cplusplus +} +#endif + +#endif /* __SPI_FLASH_H_ */ diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/internal_flash.c b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/internal_flash.c new file mode 100644 index 0000000..27881f3 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/internal_flash.c @@ -0,0 +1,35 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : Internal_Flash.c + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/08 + * Description : Internal Flash program +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#include "Internal_Flash.h" +#include "CH59x_common.h" +#include "pdfFile.h" +#include "sw_udisk.h" + +#if (STORAGE_MEDIUM == MEDIUM_INTERAL_FLASH) + +__attribute__ ((aligned(4))) uint8_t TempBuf[ EEPROM_BLOCK_SIZE ]; + + +void IFlash_Prog_512(uint32_t address,uint32_t *pbuf) +{ + if (address < IFLASH_UDISK_START_ADDR || (address + 511) > IFLASH_UDISK_END_ADDR ) + { + PRINT("Error Address %x\n",address); + return; + } + + FLASH_ROM_READ(address/EEPROM_BLOCK_SIZE*EEPROM_BLOCK_SIZE, TempBuf, EEPROM_BLOCK_SIZE); + pdf_memcpy(&TempBuf[address%EEPROM_BLOCK_SIZE], pbuf, INTERNAL_FLASH_PAGE_SIZE); + FLASH_ROM_ERASE(address/EEPROM_BLOCK_SIZE*EEPROM_BLOCK_SIZE, EEPROM_BLOCK_SIZE); + FLASH_ROM_WRITE(address/EEPROM_BLOCK_SIZE*EEPROM_BLOCK_SIZE, TempBuf, EEPROM_BLOCK_SIZE); +} +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/spi_flash.c b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/spi_flash.c new file mode 100644 index 0000000..799cb25 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/FLASH/spi_flash.c @@ -0,0 +1,447 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : SPI_FLAH.c + * Author : WCH + * Version : V1.0.1 + * Date : 2022/11/24 + * Description : SPI FLASHChip operation file +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + + +/******************************************************************************/ +/* Header Files */ +#include "spi_flash.h" +#include "sw_udisk.h" +#include "peripheral.h" + + +//#define CONFIG_SPI_FLASH_DEBUG +#ifdef CONFIG_SPI_FLASH_DEBUG +#define LOG_INFO(...) PRINT(__VA_ARGS__) +#else +#define LOG_INFO(...) +#endif + +/******************************************************************************/ +volatile uint8_t Flash_Type = 0x00; /* FLASH chip: 0: W25XXXseries */ +volatile uint32_t Flash_ID = 0x00; /* FLASH ID */ +volatile uint32_t Flash_Sector_Count = 0x00; /* FLASH sector number */ +volatile uint16_t Flash_Sector_Size = 0x00; /* FLASH sector size */ + +/******************************************************************************* +* Function Name : FLASH_Port_Init +* Description : FLASH chip operation related pins and hardware initialization +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_Port_Init( void ) +{ + GPIOA_SetBits(GPIO_Pin_12); + GPIOA_ModeCfg(GPIO_Pin_12 | GPIO_Pin_13 | GPIO_Pin_14, GPIO_ModeOut_PP_5mA); + GPIOA_ModeCfg(GPIO_Pin_15, GPIO_ModeIN_Floating); + + R8_SPI0_CLOCK_DIV = 4; // System clock divided by 4 + R8_SPI0_CTRL_MOD = RB_SPI_ALL_CLEAR; + R8_SPI0_CTRL_MOD = RB_SPI_MOSI_OE | RB_SPI_SCK_OE; //Mode0 + R8_SPI0_CTRL_CFG |= RB_SPI_AUTO_IF; // Automatically clear IF_BYTE_END flag when accessing BUFFER/FIFO + R8_SPI0_CTRL_CFG &= ~RB_SPI_DMA_ENABLE; // DMA not enabled +} + +/********************************************************************* + * @fn SPI_ReadWriteByte + * + * @brief SPIx read or write one byte. + * + * @param TxData - write one byte data. + * + * @return Read one byte data. + */ +uint8_t SPI_ReadWriteByte(uint8_t TxData) +{ + uint8_t i = 0; + + R8_SPI0_CTRL_MOD &= ~RB_SPI_FIFO_DIR; + R8_SPI0_BUFFER = TxData; + while(!(R8_SPI0_INT_FLAG & RB_SPI_FREE)) + { + i++; + if(i > 200) + return 0; + } + return (R8_SPI0_BUFFER); +} + +/******************************************************************************* +* Function Name : SPI_FLASH_SendByte +* Description : SPI send a byte +* Input : byte: byte to send +* Output : None +* Return : None +*******************************************************************************/ +uint8_t SPI_FLASH_SendByte( uint8_t byte ) +{ + return SPI_ReadWriteByte( byte ); +} + +/******************************************************************************* +* Function Name : SPI_FLASH_ReadByte +* Description : SPI receive a byte +* Input : None +* Output : None +* Return : byte received +*******************************************************************************/ +uint8_t SPI_FLASH_ReadByte( void ) +{ + return SPI_ReadWriteByte( 0xFF ); +} + +/******************************************************************************* +* Function Name : FLASH_ReadID +* Description : Read FLASH ID +* Input : None +* Output : None +* Return : chip id +*******************************************************************************/ +uint32_t FLASH_ReadID( void ) +{ + uint32_t dat; + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_JEDEC_ID ); + dat = ( uint32_t )SPI_FLASH_SendByte( DEF_DUMMY_BYTE ) << 16; + dat |= ( uint32_t )SPI_FLASH_SendByte( DEF_DUMMY_BYTE ) << 8; + dat |= SPI_FLASH_SendByte( DEF_DUMMY_BYTE ); + PIN_FLASH_CS_HIGH( ); + return( dat ); +} + +/******************************************************************************* +* Function Name : FLASH_WriteEnable +* Description : FLASH Write Enable +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_WriteEnable( void ) +{ + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_WREN ); + PIN_FLASH_CS_HIGH( ); +} + +/******************************************************************************* +* Function Name : FLASH_WriteDisable +* Description : FLASH Write Disable +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_WriteDisable( void ) +{ + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_WRDI ); + PIN_FLASH_CS_HIGH( ); +} + +/******************************************************************************* +* Function Name : FLASH_ReadStatusReg +* Description : FLASH Read Status +* Input : None +* Output : None +* Return : status +*******************************************************************************/ +uint8_t FLASH_ReadStatusReg( void ) +{ + uint8_t status; + + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_RDSR ); + status = SPI_FLASH_ReadByte( ); + PIN_FLASH_CS_HIGH( ); + return( status ); +} + +/******************************************************************************* +* Function Name : FLASH_Erase_Sector +* Description : FLASH Erase Sector +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_Erase_Sector( uint32_t address ) +{ + uint8_t temp; + FLASH_WriteEnable( ); + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_SECTOR_ERASE ); + SPI_FLASH_SendByte( (uint8_t)( address >> 16 ) ); + SPI_FLASH_SendByte( (uint8_t)( address >> 8 ) ); + SPI_FLASH_SendByte( (uint8_t)address ); + PIN_FLASH_CS_HIGH( ); + do + { + temp = FLASH_ReadStatusReg( ); + }while( temp & 0x01 ); +} + +/******************************************************************************* +* Function Name : FLASH_RD_Block_Start +* Description : FLASH start block read +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_RD_Block_Start( uint32_t address ) +{ + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_READ ); + SPI_FLASH_SendByte( (uint8_t)( address >> 16 ) ); + SPI_FLASH_SendByte( (uint8_t)( address >> 8 ) ); + SPI_FLASH_SendByte( (uint8_t)address ); +} + +/******************************************************************************* +* Function Name : FLASH_RD_Block +* Description : FLASH read block +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_RD_Block( uint8_t *pbuf, uint32_t len ) +{ + while( len-- ) + { + *pbuf++ = SPI_FLASH_ReadByte( ); + } +} + +/******************************************************************************* +* Function Name : FLASH_RD_Block_End +* Description : FLASH end block read +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_RD_Block_End( void ) +{ + PIN_FLASH_CS_HIGH( ); +} + +/******************************************************************************* +* Function Name : W25XXX_WR_Page +* Description : Flash page program +* Input : address +* len +* *pbuf +* Output : None +* Return : None +*******************************************************************************/ +void W25XXX_WR_Page( uint8_t *pbuf, uint32_t address, uint32_t len ) +{ + uint8_t temp; + FLASH_WriteEnable( ); + PIN_FLASH_CS_LOW( ); + SPI_FLASH_SendByte( CMD_FLASH_BYTE_PROG ); + SPI_FLASH_SendByte( (uint8_t)( address >> 16 ) ); + SPI_FLASH_SendByte( (uint8_t)( address >> 8 ) ); + SPI_FLASH_SendByte( (uint8_t)address ); + if( len > SPI_FLASH_PerWritePageSize ) + { + len = SPI_FLASH_PerWritePageSize; + } + while( len-- ) + { + SPI_FLASH_SendByte( *pbuf++ ); + } + PIN_FLASH_CS_HIGH( ); + do + { + temp = FLASH_ReadStatusReg( ); + }while( temp & 0x01 ); +} + +//__attribute__ ((aligned(4))) uint8_t TempBuffer[ EEPROM_BLOCK_SIZE ]; +void W25XXX_WR_512B( uint8_t *pbuf, uint32_t address, uint32_t len ) +{ + __attribute__ ((aligned(4))) uint8_t TempBuffer[ EEPROM_BLOCK_SIZE ]; + + FLASH_RD_Block_Start( address/EEPROM_BLOCK_SIZE*EEPROM_BLOCK_SIZE ); + FLASH_RD_Block(TempBuffer, 4096); + FLASH_RD_Block_End(); + + pdf_memcpy(&TempBuffer[address%EEPROM_BLOCK_SIZE], pbuf, 512); + FLASH_Erase_Sector(address/EEPROM_BLOCK_SIZE*EEPROM_BLOCK_SIZE); +// FLASH_ROM_WRITE(address/EEPROM_BLOCK_SIZE*EEPROM_BLOCK_SIZE, TempBuf, EEPROM_BLOCK_SIZE); + + for(uint8_t i=0; i count ) + { + temp = NumOfSingle - count; + W25XXX_WR_Page( pbuf, address, count ); + address += count; + pbuf += count; + W25XXX_WR_Page( pbuf, address, temp ); + } + else + { + W25XXX_WR_Page( pbuf, address, len ); + } + } + else + { + len -= count; + NumOfPage = len / SPI_FLASH_PageSize; + NumOfSingle = len % SPI_FLASH_PageSize; + W25XXX_WR_Page( pbuf, address, count ); + address += count; + pbuf += count; + while( NumOfPage-- ) + { + W25XXX_WR_Page( pbuf, address, SPI_FLASH_PageSize ); + address += SPI_FLASH_PageSize; + pbuf += SPI_FLASH_PageSize; + } + if( NumOfSingle != 0 ) + { + W25XXX_WR_Page( pbuf, address, NumOfSingle ); + } + } + } +} + + + +/******************************************************************************* +* Function Name : FLASH_IC_Check +* Description : check flash type +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void FLASH_IC_Check( void ) +{ + uint32_t count; + + /* Read FLASH ID */ + Flash_ID = FLASH_ReadID( ); + LOG_INFO("Flash_ID: %08x\n",(uint32_t)Flash_ID); + + Flash_Type = 0x00; + Flash_Sector_Count = 0x00; + Flash_Sector_Size = 0x00; + + switch( Flash_ID ) + { + /* W25XXX */ + case W25X10_FLASH_ID: /* 0xEF3011-----1M bit */ + count = 1; + break; + + case W25X20_FLASH_ID: /* 0xEF3012-----2M bit */ + count = 2; + break; + + case W25X40_FLASH_ID: /* 0xEF3013-----4M bit */ + count = 4; + break; + + case W25X80_FLASH_ID: /* 0xEF4014-----8M bit */ + count = 8; + break; + + case W25Q16_FLASH_ID1: /* 0xEF3015-----16M bit */ + case W25Q16_FLASH_ID2: /* 0xEF4015-----16M bit */ + count = 16; + break; + + case W25Q32_FLASH_ID1: /* 0xEF4016-----32M bit */ + case W25Q32_FLASH_ID2: /* 0xEF6016-----32M bit */ + count = 32; + break; + + case W25Q64_FLASH_ID1: /* 0xEF4017-----64M bit */ + case W25Q64_FLASH_ID2: /* 0xEF6017-----64M bit */ + count = 64; + break; + + case W25Q128_FLASH_ID1: /* 0xEF4018-----128M bit */ + case W25Q128_FLASH_ID2: /* 0xEF6018-----128M bit */ + count = 128; + break; + + case W25Q256_FLASH_ID1: /* 0xEF4019-----256M bit */ + case W25Q256_FLASH_ID2: /* 0xEF6019-----256M bit */ + count = 256; + break; + default: + if( ( Flash_ID != 0xFFFFFFFF ) && ( Flash_ID != 0x00000000 ) ) + { + count = 16; + } + else + { + count = 0x00; + } + break; + } + count = ( (uint32_t)count * 1024 ) * ( (uint32_t)1024 / 8 ); + + if( count ) + { + Flash_Sector_Count = count / DEF_UDISK_SECTOR_SIZE; + Flash_Sector_Size = DEF_UDISK_SECTOR_SIZE; + } + else + { + LOG_INFO("External Flash not connected\r\n"); + while(1); + } +} + diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfFile.h b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfFile.h new file mode 100644 index 0000000..b6e7c7e --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfFile.h @@ -0,0 +1,32 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : pdfFile.h +* Author : WCH +* Version : V1.0.0 +* Date : 2021/06/06 +* Description : +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __PDF_FILE_H +#define __PDF_FILE_H + +#include "CH59x_common.h" + +#define PDF_TMP_BUF_LEN_MAX 512 +#define PDF_TMP_BUF_LEN_EXT 256 +//#define PDF_SAVE_ADDRESS ((uint32_t)(128*1024)) +#define PDF_FILE_MAX_LEN (2*1024*1024) + +uint32_t pdf_data_proces( void *buf, uint32_t length ); + +void open_file( char *filename ); + +void write_file( uint8_t *pData ); + +void close_file( void ); + +void pdf_memcpy( void *pDst, const void *pSrc, uint32_t len ); +#endif + diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfTempe.h b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfTempe.h new file mode 100644 index 0000000..3f1b0c3 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/include/pdfTempe.h @@ -0,0 +1,18 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : pdfTemp.h +* Author : WCH +* Version : V1.0.0 +* Date : 2021/06/06 +* Description : +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __PDF_TEMP_H +#define __PDF_TEMP_H + + +int pdf_create( char *file_name ); + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfFile.c b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfFile.c new file mode 100644 index 0000000..e256213 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfFile.c @@ -0,0 +1,252 @@ +#include "string.h" +#include "pdfFile.h" +#include "SW_UDISK.h" +#include "Internal_Flash.h" +#include "CHRV3UFI.h" +#include "usbfs_device.h" +#include "spi_flash.h" +#include "peripheral.h" +#include "usb_connect.h" + +//#define CONFIG_PDFFILE_DEBUG +#ifdef CONFIG_PDFFILE_DEBUG +#define LOG_INFO(...) PRINT(__VA_ARGS__) +#else +#define LOG_INFO(...) +#endif + +uint32_t data_len; +uint32_t data_tollen; + +//__attribute__ ((aligned(4))) uint8_t data_buf[PDF_TMP_BUF_LEN_MAX+PDF_TMP_BUF_LEN_EXT]; + +const uint8_t sec0[] ={ + 0xeb,0x3c,0x90,0x4d,0x53,0x44,0x4f,0x53,0x35,0x2e,0x30,0x00,0x02,0x01,0x04,0x00, + 0x02,0x00,0x02,0x80,0x02,0xf8,0x02,0x00,0x01,0x00,0x01,0x00,0x00,0x00,0x00,0x00, + 0x00,0x00,0x00,0x00,0x80,0x00,0x29,0xff,0x32,0xc6,0x0c,0x4e,0x4f,0x20,0x4e,0x41, + 0x4d,0x45,0x20,0x20,0x20,0x20,0x46,0x41,0x54,0x31,0x32,0x20,0x20,0x20,0x33,0xc9, + 0x8e,0xd1,0xbc,0xf0,0x7b,0x8e,0xd9,0xb8,0x00,0x20,0x8e,0xc0,0xfc,0xbd,0x00,0x7c, + 0x38,0x4e,0x24,0x7d,0x24,0x8b,0xc1,0x99,0xe8,0x3c,0x01,0x72,0x1c,0x83,0xeb,0x3a, + 0x66,0xa1,0x1c,0x7c,0x26,0x66,0x3b,0x07,0x26,0x8a,0x57,0xfc,0x75,0x06,0x80,0xca, + 0x02,0x88,0x56,0x02,0x80,0xc3,0x10,0x73,0xeb,0x33,0xc9,0x8a,0x46,0x10,0x98,0xf7, + 0x66,0x16,0x03,0x46,0x1c,0x13,0x56,0x1e,0x03,0x46,0x0e,0x13,0xd1,0x8b,0x76,0x11, + 0x60,0x89,0x46,0xfc,0x89,0x56,0xfe,0xb8,0x20,0x00,0xf7,0xe6,0x8b,0x5e,0x0b,0x03, + 0xc3,0x48,0xf7,0xf3,0x01,0x46,0xfc,0x11,0x4e,0xfe,0x61,0xbf,0x00,0x00,0xe8,0xe6, + 0x00,0x72,0x39,0x26,0x38,0x2d,0x74,0x17,0x60,0xb1,0x0b,0xbe,0xa1,0x7d,0xf3,0xa6, + 0x61,0x74,0x32,0x4e,0x74,0x09,0x83,0xc7,0x20,0x3b,0xfb,0x72,0xe6,0xeb,0xdc,0xa0, + 0xfb,0x7d,0xb4,0x7d,0x8b,0xf0,0xac,0x98,0x40,0x74,0x0c,0x48,0x74,0x13,0xb4,0x0e, + 0xbb,0x07,0x00,0xcd,0x10,0xeb,0xef,0xa0,0xfd,0x7d,0xeb,0xe6,0xa0,0xfc,0x7d,0xeb, + 0xe1,0xcd,0x16,0xcd,0x19,0x26,0x8b,0x55,0x1a,0x52,0xb0,0x01,0xbb,0x00,0x00,0xe8, + 0x3b,0x00,0x72,0xe8,0x5b,0x8a,0x56,0x24,0xbe,0x0b,0x7c,0x8b,0xfc,0xc7,0x46,0xf0, + 0x3d,0x7d,0xc7,0x46,0xf4,0x29,0x7d,0x8c,0xd9,0x89,0x4e,0xf2,0x89,0x4e,0xf6,0xc6, + 0x06,0x96,0x7d,0xcb,0xea,0x03,0x00,0x00,0x20,0x0f,0xb6,0xc8,0x66,0x8b,0x46,0xf8, + 0x66,0x03,0x46,0x1c,0x66,0x8b,0xd0,0x66,0xc1,0xea,0x10,0xeb,0x5e,0x0f,0xb6,0xc8, + 0x4a,0x4a,0x8a,0x46,0x0d,0x32,0xe4,0xf7,0xe2,0x03,0x46,0xfc,0x13,0x56,0xfe,0xeb, + 0x4a,0x52,0x50,0x06,0x53,0x6a,0x01,0x6a,0x10,0x91,0x8b,0x46,0x18,0x96,0x92,0x33, + 0xd2,0xf7,0xf6,0x91,0xf7,0xf6,0x42,0x87,0xca,0xf7,0x76,0x1a,0x8a,0xf2,0x8a,0xe8, + 0xc0,0xcc,0x02,0x0a,0xcc,0xb8,0x01,0x02,0x80,0x7e,0x02,0x0e,0x75,0x04,0xb4,0x42, + 0x8b,0xf4,0x8a,0x56,0x24,0xcd,0x13,0x61,0x61,0x72,0x0b,0x40,0x75,0x01,0x42,0x03, + 0x5e,0x0b,0x49,0x75,0x06,0xf8,0xc3,0x41,0xbb,0x00,0x00,0x60,0x66,0x6a,0x00,0xeb, + 0xb0,0x42,0x4f,0x4f,0x54,0x4d,0x47,0x52,0x20,0x20,0x20,0x20,0x0d,0x0a,0x52,0x65, + 0x6d,0x6f,0x76,0x65,0x20,0x64,0x69,0x73,0x6b,0x73,0x20,0x6f,0x72,0x20,0x6f,0x74, + 0x68,0x65,0x72,0x20,0x6d,0x65,0x64,0x69,0x61,0x2e,0xff,0x0d,0x0a,0x44,0x69,0x73, + 0x6b,0x20,0x65,0x72,0x72,0x6f,0x72,0xff,0x0d,0x0a,0x50,0x72,0x65,0x73,0x73,0x20, + 0x61,0x6e,0x79,0x20,0x6b,0x65,0x79,0x20,0x74,0x6f,0x20,0x72,0x65,0x73,0x74,0x61, + 0x72,0x74,0x0d,0x0a,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xac,0xcb,0xd8,0x55,0xaa, +}; + +// SEC4/6 +const uint8_t BPB_Media[] = +{ + 0xf8,0xff,0xff,0xff,0xff,0xff +}; + + +__HIGH_CODE +void pdf_memcpy( void *pDst, const void *pSrc, uint32_t len ) +{ + uint8_t *dst; + const uint8_t *src; + if( pDst == 0 || pSrc == 0 || len == 0 ){ + return; + } + + src = (uint8_t *)pSrc; + dst = (uint8_t *)pDst; + do{ + *dst++ = *src++; + }while( --len ); +} + + +void udisk_enable( void ) +{ +#if FUN_UDISK + /* USBOTG_FS device init */ + USBFS_Device_Init( ); +#endif +} + + +void udisk_format( void ) +{ + uint32_t addr = 0; + + for( int sec=0;sec<40;sec++ ) + { + memset(pDISK_FAT_BUF, 0, DEF_UDISK_SECTOR_SIZE); + if( sec == 0 ) { + pdf_memcpy( pDISK_FAT_BUF,sec0,sizeof(sec0) ); + } + else if( sec == 4 || sec == 6 ) { + pdf_memcpy( pDISK_FAT_BUF,BPB_Media,sizeof(BPB_Media) ); + } + W25XXX_WR_512B(pDISK_FAT_BUF, addr, 512); +// IFlash_Prog_512( addr, (uint32_t*)pDISK_FAT_BUF); + addr += DEF_UDISK_SECTOR_SIZE; + } +} + + +/********************************************************************* + * @fn mStopIfError + * + * @brief Checking the operation status, displaying the error code and stopping if there is an error + * input : iError - Error code input + * + * @return none + */ +#if FUN_FILE_CREATE +static void mStopIfError( uint8_t iError ) +{ + if ( iError == ERR_SUCCESS ) + { + /* operation success, return */ + return; + } + /* Display the errors */ + LOG_INFO( "Error:%02x\r\n", iError ); + /* After encountering an error, you should analyze the error code and CH103DiskReday status, for example, + * call CH103DiskReday to check whether the current USB disk is connected or not, + * if the disk is disconnected then wait for the disk to be plugged in again and operate again, + * Suggested steps to follow after an error: + * 1,call CH103DiskReday once, if successful, then continue the operation, such as Open, Read/Write, etc. + * 2,If CH103DiskReday is not successful, then the operation will be forced to start from the beginning. + */ + while(1); +} +#endif + + +void open_file( char *filename ) +{ +#if FUN_FILE_CREATE + uint8_t s; + + LOG_INFO( "Open\r\n" ); + strcpy( mCmdParam.Open.mPathName,filename ); + s = CHRV3FileOpen( ); //open file + LOG_INFO("open file. s=%x\n",s); + if( s == 0x91 ) //disk is not formatted + { + udisk_format( ); + s = ERR_MISS_FILE; + } + + if ( s == ERR_MISS_DIR || s == ERR_MISS_FILE ) //file not found on disk + { + LOG_INFO( "Create new file\n" ); + strcpy( mCmdParam.Create.mPathName, filename ); //File name, create a file in the root directory + s = CHRV3FileCreate( ); //Create a new file and open it, if the file already exists, delete it first and then create a new one + mStopIfError( s ); + } + else //file found on disk + { + udisk_enable(); //USB peripheral initialization, simulate U disk + while(1) + { + if(USB_CONNECT_CHECK() == 0) + { + DelayMs(10); + SYS_ResetExecute(); + } + } + } +#endif + + /* Storage Data Count Clear */ + data_len = 0; + data_tollen = 0; +} + + +void write_file( uint8_t *pData ) +{ +#if FUN_FILE_CREATE + uint8_t s; + + mCmdParam.Write.mSectorCount = 1; //写入所有扇区的数据 + mCmdParam.Write.mDataBuffer = pData; //指向文件数据缓冲区的起始地址 + s = CHRV3FileWrite( ); //向文件写入数据 + mStopIfError( s ); +#endif +} + + +void close_file( void ) +{ + LOG_INFO( "Close\r\n" ); +#if FUN_FILE_CREATE + uint8_t s; + uint32_t file_len; + + if( data_len ) + { + write_file( RAM_BUFFER.PDF_BUFFER.pdf_data_buf ); + s = CHRV3FileQuery( ); // Query current file information + mStopIfError( s ); + file_len = CHRV3vFileSize - CHRV3vSectorSize + data_len; + LOG_INFO( "Modify\r\n" ); + mCmdParam.Modify.mFileAttr = ATTR_READ_ONLY; // Input parameter: new file attribute, if it is 0FFH, it will not be modified + mCmdParam.Modify.mFileTime = MAKE_FILE_TIME( 8,8,8 ); // Input parameters: the new file time, if it is 0FFFFH, it will not be modified, and the default time generated by the new file will be used + mCmdParam.Modify.mFileDate = MAKE_FILE_DATE( 2023, 8, 1 ); // Input parameters: New file date: 2015.05.18 + mCmdParam.Modify.mFileSize = file_len; // Input parameters: new file length, the length of the file written in bytes should be automatically updated by the program library when the file is closed, so it is not modified here + s = CHRV3FileModify( ); // Modify the information of the current file, the modification date + mStopIfError( s ); + } + mCmdParam.Close.mUpdateLen = 0; + s = CHRV3FileClose( ); + mStopIfError( s ); + + /* file created */ + udisk_enable( ); //USB peripheral initialization, simulate U disk +#endif +} + + +uint32_t pdf_data_proces( void *buf, uint32_t length ) +{ + if( length > PDF_TMP_BUF_LEN_EXT ){ + LOG_INFO("max length error.len= %d > %d\n",length,PDF_TMP_BUF_LEN_MAX); + return 1; + } + + if( data_tollen + length > PDF_FILE_MAX_LEN ){ + LOG_INFO( "file error len=%d\r\n",data_tollen + length ); + return 2; + } + + pdf_memcpy( &RAM_BUFFER.PDF_BUFFER.pdf_data_buf[data_len], buf, length ); + data_len += length; + + if( data_len >= PDF_TMP_BUF_LEN_MAX ){ + data_len -= PDF_TMP_BUF_LEN_MAX; + write_file( RAM_BUFFER.PDF_BUFFER.pdf_data_buf ); + if( data_len ){ + pdf_memcpy( RAM_BUFFER.PDF_BUFFER.pdf_data_buf,&RAM_BUFFER.PDF_BUFFER.pdf_data_buf[PDF_TMP_BUF_LEN_MAX],data_len); + } + } + data_tollen += length; + + return 0; +} diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfTempe.c b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfTempe.c new file mode 100644 index 0000000..d1c159b --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF/pdfTempe.c @@ -0,0 +1,274 @@ +/* +*生成pdf模板代码: +*Created on: 2023-07-26 +*Author: WCH +*/ +#include +#include +#include +#include "pdfFile.h" +#include "pdf.h" +#include "flash_info.h" + +//#define CONFIG_PDFTEMPE_DEBUG +#ifdef CONFIG_PDFTEMPE_DEBUG +#define LOG_INFO(...) PRINT(__VA_ARGS__) +#else +#define LOG_INFO(...) +#endif + +// 首条记录时间 +uint8_t timeStart[6] = { 23, 7, 27, 12, 12, 12}; +#define YEAR_OFFSET 0 +#define MONTH_OFFSET 1 +#define DAY_OFFSET 2 +#define HOUR_OFFSET 3 +#define MINUTE_OFFSET 4 +#define SECOND_OFFSET 5 + +const char centigrade[3] ={ 0xA1, 0xE6,'\0' }; // ℃, temperature unit + +const char *device_info[] = { + "Device Information", + "Model#:", + "Serial#:", + "IP Grade:", + "Probe Type:", + "Storage:", + NULL, // MeauRange: +}; + +const char *trip_info[] = { + "Trip Information", + "Order:", + "Shipper:", + "City:", + "Carrier:", + "Receiver:", + "Signature:", +}; + +const char *logger_conf[] = { + "Logger Configuration", + "Start Mode:", + "Stop Mode:", + "Key Stop:", + "Warning Tone:", + NULL, // Temp Limit: + "Start Delay:", + NULL, // Interval: + NULL, // Temp Unit: + "Alarm Tone:", + "NULL", // Humi Limit: +}; + + +#define PDF_BUF_LEN 256 +#define DATA_MAX_LEN 256 + +static LPDF_Doc_Rec pdf; +static LPDF_INT8 PdfBuf[PDF_BUF_LEN] = { 0 }; +static LPDF_REAL DataBuf[DATA_MAX_LEN]; + +#define IFLASH_TEMP_START_ADDR (268*1024) +LPDF_REAL *pdf_get_temperature_data( LPDF_REAL *pBuf,LPDF_UINT offset, LPDF_UINT *num ) +{ + int16_t temp; + +// EEPROM_READ( IFLASH_TEMP_START_ADDR + offset*sizeof(LPDF_REAL), pBuf, *num * sizeof(LPDF_REAL) ); + FLASH_ROM_READ(IFLASH_TEMP_START_ADDR + offset*sizeof(LPDF_REAL), pBuf, *num * sizeof(LPDF_REAL) ); + for(uint16_t i=0; i<*num; ++i) + { + temp = ((int16_t *)pBuf)[2*i]; + pBuf[i] = ((float)temp)/10.0; + LOG_INFO("T:%f\n", pBuf[i]); + } + + return pBuf; +} + +#define IFLASH_HUMI_START_ADDR (268*1024) +LPDF_REAL *pdf_get_humidity_data( LPDF_REAL *pBuf,LPDF_UINT offset, LPDF_UINT *num ) +{ + int16_t temp; + +// EEPROM_READ( IFLASH_HUMI_START_ADDR + offset*sizeof(LPDF_REAL), pBuf, *num * sizeof(LPDF_REAL) ); + FLASH_ROM_READ(IFLASH_HUMI_START_ADDR + offset*sizeof(LPDF_REAL), pBuf, *num * sizeof(LPDF_REAL) ); + for(uint16_t i=0; i<*num; ++i) + { + temp = ((int16_t *)pBuf)[2*i+1]; + pBuf[i] = ((float)temp)/10.0; + LOG_INFO("H:%f\n", pBuf[i]); + } + + return pBuf; +} + + +void pdf_temperature_init( LPDF_Info info ) +{ + memset( info, 0, sizeof(LPDF_Info)); + strcpy(info->FileName,"template.pdf"); //header + strcpy(info->FileVersion, "v1.4"); + strcpy(info->WebUrl, "www.wch.cn"); + + info->HumiTotalDataNum = info->TempTotalDataNum = DeviceInfo.MeasureNum; //total number of data + info->tempGetDataCb = pdf_get_temperature_data; //data read callback function + info->humiGetDataCb = pdf_get_humidity_data; //data read callback function + info->pDataBuf = DataBuf; //Used to cache temperature and humidity data read from Flash (pdf_get_temperature_data/pdf_get_humidity_data) + info->DataBufLen = DATA_MAX_LEN; + + info->isGraphEnable = LPDF_TRUE; //Show graph in PDF + info->isTableEnable = LPDF_TRUE; //Show all data in PDF + + // Device Information + info->DeviceInfo.pInfo = device_info; //Displayed in the first column (Device Information), Items set to NULL cannot be modified + strcpy(info->DeviceInfo.ProductType, "ZZ-10A"); + strcpy(info->DeviceInfo.SerialNumber, "ABCD1234"); + strcpy(info->DeviceInfo.ProtectionGrade, "IP67"); + strcpy(info->DeviceInfo.ProbeType, "temperature&humidity" ); + info->DeviceInfo.StorageSpace = 10000; //Maximum amount of data stored + info->DeviceInfo.MinMeauRange = -40; //Measuring range + info->DeviceInfo.MaxMeauRange = 70; + + // Trip Information + info->TripInfo.pInfo = trip_info; //Displayed in the second column (Trip Information), Items set to NULL cannot be modified + strcpy(info->TripInfo.Order, "A-0-B-1-001"); + strcpy(info->TripInfo.Shipper, "anonymity"); + strcpy(info->TripInfo.City, "NanJing"); + strcpy(info->TripInfo.Carrier, "lobster"); + strcpy(info->TripInfo.Receiver, "abc"); + strcpy(info->TripInfo.Signature, "xxx"); + + // Logger Configuration + info->ConfigInfo.pInfo = logger_conf; //Displayed in the third column (Logger Configuration), Items set to NULL cannot be modified + strcpy(info->ConfigInfo.StartMode, "Key Start"); + strcpy(info->ConfigInfo.StopMode, "Key Stop + Full Stop"); + info->ConfigInfo.IsKeyStop = LPDF_TRUE; + info->ConfigInfo.IsTone = LPDF_FALSE; + info->ConfigInfo.MaxTempAlarm = DeviceInfo.PdfParam.MaxTempAlarm; //temperature safe range + info->ConfigInfo.MinTempAlarm = DeviceInfo.PdfParam.MinTempAlarm; + + info->ConfigInfo.StartDelayed = 60; + info->ConfigInfo.Interval = DeviceInfo.PdfParam.MeasureInterval*60; + strcpy(info->ConfigInfo.TempUint, centigrade ); + info->ConfigInfo.IsAlarmTone = LPDF_FALSE; + info->ConfigInfo.MaxHumiAlarm = DeviceInfo.PdfParam.MaxHumiAlarm; //humidity safe range + info->ConfigInfo.MinHumiAlarm = DeviceInfo.PdfParam.MinHumiAlarm; + + // Statistical Information + info->StatisInfo.RecordNum = info->TempTotalDataNum + info->HumiTotalDataNum; //Displayed in the fourth column (Statistical Information) + info->StatisInfo.FirstRecordYear = (LPDF_UINT8)DeviceInfo.StartTime.Year - 2000; //timeStart[YEAR_OFFSET]; //Data recording start time + info->StatisInfo.FirstRecordMonth = DeviceInfo.StartTime.Month; //timeStart[MONTH_OFFSET]; + info->StatisInfo.FirstRecordDay = DeviceInfo.StartTime.Day; //timeStart[DAY_OFFSET]; + info->StatisInfo.FirstRecordHour = DeviceInfo.StartTime.Hour; //timeStart[HOUR_OFFSET]; + info->StatisInfo.FirstRecordMinute = DeviceInfo.StartTime.Minute; //timeStart[MINUTE_OFFSET]; + info->StatisInfo.FirstRecordSec = DeviceInfo.StartTime.Second; //timeStart[SECOND_OFFSET]; +} + +int pdf_create( char *file_name ) +{ + LPDF_Init param; + + LOG_INFO("file_name:%s\n",file_name); + open_file( file_name ); //Open file from internal Flash + + param.pPdfBuf = PdfBuf; //Used to cache generated file data (pdf_data_proces) + param.pdfProcessCb = pdf_data_proces; //Callback function to save file data to disk + LPDF_InitParam( ¶m ); + +#if 1 // Create a cold chain PDF template defined by Qinheng + { + static LPDF_Template_Info temperInfo; + + pdf_temperature_init( &temperInfo ); //Initialize the content displayed in the PDF + + memset( &pdf,0,sizeof(LPDF_Doc_Rec)); + temperInfo.pdf = LPDF_New( &pdf ); + pdf_template_creat( &temperInfo ); + LPDF_SaveToFile( temperInfo.pdf ); + } +#else //Customize a PDF template + { + LPDF_Doc pTemp; + LPDF_Page page[1] = { 0 }; //One page PDF array + + //draw a line + memset( &pdf,0,sizeof(LPDF_Doc_Rec)); + pTemp = LPDF_New( &pdf ); + page[0] = LPDF_AddPage( pTemp ); + LPDF_Page_SetLineWidth(page[0],1.0); + LPDF_Page_MoveTo(page[0], 25, 810); + LPDF_Page_LineTo(page[0], 575, 810); + LPDF_Page_MoveTo(page[0], 25, 20); + LPDF_Page_LineTo(page[0], 575, 20); + LPDF_Page_Stroke(page[0]); //The line drawing operation ends. Clear the relevant parameters of the configuration. + + //header + LPDF_Page_SetRGBFill(page[0], 0.0, 0.0, 0.0); + LPDF_Page_BeginText(page[0]); + LPDF_Page_MoveTextPos(page[0], 30, 815); + LPDF_Page_SetFontAndSize(page[0], "SimSun", 7); + LPDF_Page_ShowText(page[0], file_name ); + LPDF_Page_MoveTextPos(page[0], 480, 0); + LPDF_Page_ShowText(page[0], "v1.4"); + LPDF_Page_EndText(page[0]); //The text operation ends. Clear the relevant parameters of the configuration. + + //draw thick lines + LPDF_Page_SetRGBStroke(page[0], 0.8, 0.8, 0.8); + LPDF_Page_SetLineWidth(page[0], 24.0); + LPDF_Page_MoveTo(page[0], 30, 780); + LPDF_Page_LineTo(page[0], 565, 780); + LPDF_Page_Stroke(page[0]); //The line drawing operation ends. Clear the relevant parameters of the configuration. + + //display text + LPDF_Page_SetRGBFill(page[0], 0, 0.0, 0); + LPDF_Page_BeginText(page[0]); + LPDF_Page_MoveTextPos(page[0], (565/2), 780-3); + LPDF_Page_SetFontAndSize(page[0], "SimSun", 18); + LPDF_Page_ShowText(page[0], "demo"); + LPDF_Page_MoveTextPos(page[0], -200, -200 ); + LPDF_Page_SetRGBFill(page[0], 1.0, 0.0, 0.0); + LPDF_Page_SetFontAndSize(page[0], "SimSun", 28); + LPDF_Page_ShowText(page[0], "hello world"); + LPDF_Page_EndText(page[0]); //The text operation ends. Clear the relevant parameters of the configuration. + + //draw a rectangle + LPDF_Page_SetRGBStroke(page[0], 0, 0, 0); + LPDF_Page_SetLineWidth(page[0], 1.0); + LPDF_Page_MoveTo(page[0], 50, 45); + LPDF_Page_RectTo(page[0], 50, 45, 512, 400); + LPDF_Page_Stroke(page[0]); //The line drawing operation ends. Clear the relevant parameters of the configuration. + + //draw grid + LPDF_Page_SetLineWidth(page[0], 0.8); + for( int i=0;i<12;i++ ){ + if( (i%3) == 0)LPDF_Page_SetRGBStroke(page[0], 0.5, 0.0, 0.0); + if( (i%3) == 1)LPDF_Page_SetRGBStroke(page[0], 0.0, 0.5, 0.0); + if( (i%3) == 2)LPDF_Page_SetRGBStroke(page[0], 0.0, 0.0, 0.5); + LPDF_Page_SetLineWidth(page[0], 30.0); + LPDF_Page_MoveTo(page[0], 50, 80+30*i); + LPDF_Page_LineTo(page[0], 50+512, 80+30*i ); + LPDF_Page_Stroke(page[0]); //The line drawing operation ends. Clear the relevant parameters of the configuration. + } + + //footer + LPDF_Page_SetRGBFill(page[0], 0.0, 0.0, 0.0); + LPDF_Page_BeginText(page[0]); + LPDF_Page_MoveTextPos(page[0], 40, 10); + LPDF_Page_SetFontAndSize(page[0], "SimSun", 7); + LPDF_Page_ShowText(page[0], "www.wch.cn"); + LPDF_Page_MoveTextPos(page[0], 490, 0); + LPDF_Page_ShowText(page[0], "1/1"); + LPDF_Page_EndText(page[0]); //The text operation ends. Clear the relevant parameters of the configuration. + + //save + LPDF_Page_SaveContext(page[0]); //The PDF operation for this page is finished. Clear the relevant parameters of the configuration. + LPDF_SaveToFile( pTemp); //The entire PDF file operation ends. Clear the relevant parameters of the configuration. + } +#endif + + close_file( ); + return 0; +} + diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/libpdf.a b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/libpdf.a new file mode 100644 index 0000000000000000000000000000000000000000..16ff2467d2f12adf076d4c9b595e1fb9d1a0ba60 GIT binary patch literal 95634 zcmdSC3w%}8ng6|$lY|f=9unm2SfptJ5o3s)fDsrc4V(}HMvBNqsg+9t0)>Qzpy*Hw z5LxA)2>UOMmR z{r^AjR+8`fu4k{k_F8M-ch333^)nl4=9Xn#liPWUmky6#TUt^wG@hF~*vqni=H|u+ zU#B8>Muy`!amPt%_}~BgbFt(6-~U%Ld)|WS^XeL%>IoH<(-y z3ui8!zHnaM^qF_gZkTz;Yz?WH**J6h1W8Vx+AyziwzCLg(%p-MYUfOEoV{?-f|-r8 zr`I&hp4m9PaptTAU1r?TFmut|F6MAh07@UfWTCT2eov}zoVmbDc*|M1$nnaYSbvv7 zqJF`Wg>_Ct{as#l#@5x&Uh33Jm8_&xY{JZjnG1CVs%9>(sIPJ6+=c2-U!ZdQ?7I|h zmX)1UUpY^z?X`$B2CAb8Z?$ip-B>ky-W_vIlhI9`SKBz(3LDc!n7D9QV(#pkuio4! zO=it2i>R!xYaCfud-J?|I%P=h5|T4}slD`3v+tN!H>tB5T~`}2H_xrVE2M6$mz9C%R?>uTz2=hfX|g<|IE6Y6FBOb@S^tm|~F z#B?tvoGWWMam=Wj8yo7s+G+hfEv;|5#cN!zmi5+BtLN28A6a7J?3%_-;-Z2p8fM-# zcA?*q)%7!LCmK`PP`@zf?{LnIv(2z!KV#w6+KjE6*QkSQ4pw%-yv3$xD#uojo?bP2 zWX0%-4hDL0y|ugfxIImL@Zi$Y(%jrq*$)l#_CPZ-zA?JGGASuZb~rjEIe&73l;aHi zgX5)#df5Y=Yn)5YEMuyCFBMohcOB!Eubgtw1@!63fHQA9nH~zM2#rT?6_9gwUYU}uZks)>c zA{REcU3%)H0blx{s;2&~DPOs`sjDVwWb1U3Y16+xZfw=CO1q`_l5X zKUWR;pOcZAoJ*x-Cui#$S&_EqUFVPKHLo5`+WJtxk!_LQ&X22VezVkRYtC|75-Bg{ zw=Z$>bB`qDx9?3VsmRa0!^v;&mh?nL(rB#X6o7P8u(9N0FvfppN!Uqnv zjPp}9H@7?c??2heq&nl)q^7*qtKx(F_UolS4yQ}oo{M;{O=NHF&(@ktW(n|J!oB7uy3R{DAXu7h8^RxeH8k6Zp1{_G`GMmQqbptN4_e=Xu(JR+uee&DC@8CDqE7H-; z=M9O-_q#hg_b_imV&`6q_gTE(;sao`X3fdh=Qm7UpCYL}Db5GI>0483&b&UiNouq8 z-1_9h4y3qWtVM*$WIzbIOiv7!{M!vr|)jUv{)_qG?d7lXOGbF}6w*TGi~8PEM9( zWlD|KWcse{mEKO-tLw3qJT7-f;1=;zV+SL zlex}rVs*D2>sKXMdSUD4R#{K8#h{Wl%Cfy%rcS(% zYg4vo<vomx-aDr2zI=Ns`mAYhn!|b8nqy7@TEw*e$1T?$5kYMbE&EMxi@mQUBkuAMxOp)7EndyGo zcx~$FA>*&}n8lb{aRZme@q>{W8J+61b^G&2HT(Y3zje${dN|8lQikmPi&Jul(ZRkv zdCJyb{LtzP%#V@XcO+YrW54XshLN#!$xTm}?I2yYgTA9K+FFjXt($%*TgxEX7yT&M z3eb*`G2NWk{`J&b*y8hA9{cA1&2hI|$K9SSI_`F_w8!19y<_V3&zB=)Fpli;a`C9k zZjD)c8@9umMCY+?ml2GWrrZ~^B65^#>OV3oa#d1R(^W6_iWIKs)l@jLSLEuXUQJiO z7>yLIh&C0Cj7A0}ML+yX(&))@d~EuD4<|LPX2sM9+BQG;C4axjo^ccFMor#|+T^#t zKakeziP{qaa4wU7tA8e)BW5-T&K>_M%q`M%tr^ zrUDsj-Z*rGc)B4?7=?!Ntr+g)mp`m^8sQ@B0e`{$d!)+XcQ_)8rRaJ09+ z^2Bd8{oDRuANW6;|NPAt>;ALsVAw!dY z{=<~Q9q`Yf`(eEYioKQT8e&eK` zw|+RbZrt&4<8Rn`Lvi)S>Yg`V_{u^#u0>?jB~`N}xCZMIh0WVrO8x7rgQ2r6ETg5V zX5{;QgClF3>V#Osu{K3Di>yloG@^HELWgFdO%%*}rAfj;Zak&A0B*Kaqx z-;Xt!)_U<$woJ*JGH%tuRehrc_dU^ayT7#rOHb|o%YR~jW7|m{z1H6%=)+rY;p$l} z!Bu(3nu9IDcG%G}$6pF-hW*EpmWdbn?8{S=vZrMvO>FJl(@1yf=ghJH6wJLTC`ZOS zj#_IHsTo`rf4525ZO1Z_ZmK+D^-y-&*&%lN#jSZQrF%F}PUT4}_KC{6*3&J)z73-) z>e>+)E1Z{Y6>Rn4kukp|^^y{QS;1Oh#ITgSN_(zM>k2yPvETg@quJj%l|e4X;H;LC zy^QI4IYDg;_XO+k#F&njvQJo}l1{Zl8Q24yZmHRSWzw0J`K>`)bzSq+%*VE7Cnfz_ z?kyF|eWK#xW;ue$9g>db^c=afR4n(Du9166gXDhFAi1A3NbVyIlDI)~FKJMI@sF>T zdrgC6-a%Y9ojd(=RyrL=qh$Ylh3mO4kzU@`BdLeIHxnaU zjE!}d{O;Wy?lFQbsZ+VTSj))ODNgd3*KTT$@(L8^2$cO!Y z)%9jf(+`?^M4oEC?4X}txF+&cMGr|!&D!qo?ypTp%Pc>JwPh)hf=s8WpxTdZ+BDXQ zYzpRO9Dlc6k(wm+`0XW0b+WDJM(ESay>xz%4oG_2Io!I%uR~}(euVYdb6L=8g}bmG zlIC91?9Eqp9_7aV)oYOBt--%{PZ}Ru121i_L8u)+wMU-n?nItSiE+*O`{EkjC~bU+ z-{y?t@3t6f_+nF;SHCiU1g#u{mdnjA^N;K4<(wzI{8L)lt6Rlqu3OtBNj+G0_;+?+ z)GzzC%%oYN7WC3q3kGK%dHbhv*?kM0zE_-FA9b{dJ0=bMUN!^d<8Y&658%- z?$hyL*{%PwIO`M)x82U75sXtw}@*x}6AWf^`hndA{E-!FGr` zr21{eB_w-SN`J*#_q*iJGB&;aJIiQ#DaDO+>`5ux-}F*%x9mXEOa0xlgH10Db>%Md zOBHU};ii`+xn(cEP*t<|f>XA->H8IZ+R{f}!9Bu|j0?$6jbV=tnRX#Ly}af-kB(&d zPmIC#m0m9Qlroa~(59CM=Z$ocmzv$Cy^U^UZ>`^t!O_s}$w&c8#E~bMcbm-nq|CeS zQ|1lYo_*5vj2unm-2HURxBTrafAbGNe67ztAH83ZdSlH!A7nNCP{+V=zi;|pQMRG% zu}ER&iHm^w(z(7*LvOhm!K`=K54PsCoPuy zq{VWdv{>$w4wCz%gXBKxAh}OENbZvs$$ioyxldXo_eqPI2EBN-oZ(#~cS@hibSAc> z`sEhxV!iCM{@h5gZ(KPBcOJjhz07aT{LMf3Q1(kWI{5qIn%=kmq5kZz-fS9>>5OP; z3Cj1+th42~H?nDm+|@jkJgsGfzuaUw?uq-{4!`^-DzP{0l~L-O{Nj!epBhuM@x9aa zXRmoPHDgo;u1`j9tMp63dg)%_TmF8$t35))n3I(g{r%%--52CdT{|Ut3iqmA&lU8} z#8uZvZ;AGfE=n&-uS#e8uB;lgbK8WP*I(&VdSsEDU3cC#v*pT^k)Lh5>1rIt%vo*U z#EKia|18_}{DdaiyB%*C^6q~pw_K9Zt#o~Q;;&oQ%F$Tb$dz&h{!n-S8^K`DMDYG(IZddsS{QQRTS(9Z<_@mFv?>}w*nB{*;{+jVzKK7@0|7gvqi`#pT ze^uF4Z>4-ZJk^pkQ^qRbsN27MTl{VMJNW?I|i#eEsM za!)jCvK{m3eW~+QTjh4{D^sSwJ%`uD%>OC*nSaGL%yo^*UNLA zN0@cF`Li$Mr1TE<+`)NAWI%A&4SS%9Sg;2=JZ6-4o+5jX(0;4)UIY8u+k>s)$~}E} zEPuS2bKd_t$=(+QM+!aCb}lJva&QG59_^8WiawuQ;>B~Me99ajvxn=&_HFthk37NJ zdi$|#Mj+L>EmAIHEkCUVaPL^>XK77WR($5UyQ*7cK(l`hfWF;xSzqYy z*{e-s`nyGLm0NbaY0OY}=dPwP74FX6O=BjxJNLZcpEb3PnKaRpK{90Pff}BUTW_gEXxt6wDqXUFF5D!o|->!TTXuAId}V* zo!?nj@!B8$a-m7KJlWp-d)X~xYO34i%0})=4oJyiYqVXN>f{%lbFZ)JT$}5w?Alyk z{h4aBu17_F@wvWIo7`=m&(Ay8&#p~MOlorlm&@8zh)waIrF*sMf36?yNQK9BaMz^i z2i!}I_xJc&lY={@S(EWBC^+}Fmy2iO7x#<3ueo^cpnm_Gxhwp&`|Ia!y0W>S?2qMW zS@Tf0k~QVQJ0V;L*-p)PxcJB+bLW`3S9cry$#ZL5r|ZuCIM+ry2G=-pZ1zV^=j(!C zjCXF!(3z1n^8R=82jlsFGk;UnBsWr3;YMT|Z>sDq?wO{6k-EBw=Hv~0p-FI7kL{C!~7Uv}RJflV7kcXZK`#95oFHo~7m&KI#7LPHeATlqY)@>?=a$$)3h5 z&)>>Am6!Kqzvp&7Tprv_VZZ(E$6eW9{8Tn3r}rqw$sH;GC|zIhbSZzWH?L;qg50rnbLtxwO1i$zkv}GszkbY>zd4;XyFr#IaSe^R_{-Q4 zT9+#M<4^Hg-}<}!I*!yolMT`fW;QGwp>-ZhEGWvuLzbd~(uCvi(8&cPTl)4XyI z%Io#FGuHfGUOoWBZNLCWe=nAPv&T8=W3~+4JfxU*nRj{loH=u3nVG1AjL{pV4zBPn zlq>!Oe#>-!x%X?va{cY}$9yuKmKaPYzL+aN(YuQWO{`xyv(CY&$sIg+g!jMX4IW&K zbn#%}o5xQYd*f*Q&h=n`Y|*mGI0FYPzDj<{@2i|1wa%DCVnpu1r4we>d^LB>_{q5w z$KIS6G$nVmjHue$*|oWnUz9tfWYDa6jaTIkD=zWM#{Bk_WF=CZKYnB-orw1rpMi-u z$w5LWBLCS_#7VJ}k}C%RYl=AX2Q1bUapZ=#HANhG9A!-rr>B*|@}i-1Rw$hvO7{+> zFAJsngwnB4+6|?1Lg~vx>Cc7IeM9Lh964RKrYkJQ`t@^qbu#@NmWY;3l6-rLIG=a= z+d|Uv=lpPiTr_!V~KDSeD#QB0Vp_BQ7Gp$qn7dqueoID4|l3>bn z7MX;WpBH2aMdaDZ-*qziol+55yOvI-^V&w70nWpn@?~dZO%bQS`Hq#Ab4KSWlh*na zbjpo5S2{oLWUlO#iZ}zE7dn}N&R&z&@&ElMEx&_4Npt=v=~~T{pJ~oJ^79!h{TJblRvMf19xI(H>1}>G-N}&j z<5v1oN#AazdrO*q>d5w-BWeAca0I10{Um*hAD`i+=Z4bqaTaFEaPlQSn6kb2mA=Su z21ZworO!DE)pYo#yY>b$xq=(tSed{#LrgFAFW!+iU+)D6Rtzkyah)~`I2 zo@Ax}R`RiL&`HPVYAb(~@v}OVJ`qay z^fwr-@6b@XA(UPgO0N#3+e7ISq4XP}^uX?&`>Q0B9uZ1chSK9h>Dxo;MWOV=q4cAn zwEQu=nY2ANhtk_a>7AkU-cb7GQ2JabJrJu3V3uS!S$KwV`Z?N_scS*WR{^^wAEEAq+_5TV<*IMaTNzb>^4@i1~ zwSRqB(l1!`{kEjjt@_|te#+V&|6bCYtol4DY3$=!pC1VKwYG=NlD4;(t&)Dmn*Vu8 z+uQ5UByI06cS}0m+8@0n>FcfaIUwnBEB$Lp7g^~elD7A!{~_sWEB}O~2V3diOWNN5 zy(#HK@{jBHKfBp_~)snWy_h3oe=R?;@x=j9YeMbmyv&O?0CB4H+S4jFv zD?L`yXXGE}A1}Pu%D-9CPg`m1PyOo2nZhmpyeQ#w-uYUYDGg^5-tpT?-!Acf^O^YN zRzBj}tu)T{g7X6{f47xCU-E;iYR!Ms%3mb;!PM8QPnO@`nGVhs{o(Cs{^eHwGRY5? zula+meAIWCm0l_Fx&8t*e!P{B_$gL;Rj2x0?$xi+%73U+{WSj(D<9=yo6$+z`%EbP zPADCmpJzHa7Y_PE%MZqvmN(6>qoz+->BohOxOmfk7p#2LFWKLJ>HN7?x?N&}r3sQRaXA6Gd1d+hOhPVxuJ zKjvdB+3PDed7S;$`lLx(KIYAj&y@5LE1e~2d;GhS?lhhyZI9>vl72@1>6Gad3g2VZ zf3T#FSox(sV~&`&{mNqxGxcIx{4Gpr5btu9ZJW@`LfE z`Qxno1(Kf|n*SCnzd`bY_He!S?6C5KZ5f4V{$4BpUYS2=56y4z$5T(IS@MJNs`Y!@ z%Ez^Ius_rMNqz_R^y;(AN|!Ib0WU+#~;p3WnZKiCh@@+z%-wC|Qs`kA_w$e{Xe6WAh<*l{yu{?PJ-Ap~5rzJjUFD?J1mA_f?a~bYven0Ff<*UuWP!$e?Fq=#!xyqf6@HIq5K8@2G!HqChHfB ze;qH&t$eiCTcPw&`I}#zwET)tx;m6TW~Fz?^4_r4cbBBAto7Y1>3!DtIw0w1to*~0 zUT2Muqmo``_1AGp2j`PLol}yYX!XaNl77N!|Fe>wW3>sKP_Bi8bV zNxIQW<5)P$N>@nwRcrmmN%~Q1{U%7d&dQ%6>2m)uQBUVKNuRX(Z5--``Jbe9-?H?GhjCU$wkuEB^(_501~8zun5;E&0LzN%MDE`B>i3P&zpOj(Yo&TvpH2cdl&H zIz^p>Qhu<$eZ2n1K8X1*cdDP}W1qnMW0K#WNk{Wb#W5fCJ0D8-^|$Y+b3*clG2GPe zEi3=D^S0!dvpBQ-$Nl|f)T?_iUUdG$ zR{n>b=GXjlR(^`COSNCVX&=AAqfUn8-xA8d*UCrxZMM=;zilv+miN4s-$(MLN@mjh z;C@BaLEA52wwb@TzrTul=h90<`N920ZSNgcJnFY6ls+FyC;P{*s54NO-yAA`nw5|8 z9=6iB7xZW-{s}7|@xk#f>I{|mXG8J9`9#ziA^E#P`4_D6$|e6mD8H|Ne26+YcRL!& zFSGKiCI3_?e}g2!g$R-zF>ncFE5S=?UZ)pBt|M+Q+hoSVn zp>%LO*7!{ScpY^fl=9bw>bK9z$9PG*lk#2Ud~8*ft5ZdY1gXX1xep#<>M8jqgFai((|qHgJ)?M zto$rV&$Y_Ky^%Mq{C<+2W6j@R($8D*g_1sKr3Xv;h}B-Dk}k3Gac`x{O5@qxlh*R8 zB)!tgA1~=gt@I>Gmss_gCh2w7c%C8Y!&aItjo%UHYG;n*bHcD)97?YUrSA`=zh%-@ zGH;d~sUA0J>@%~Z@t+RG|2UNXX(+whq@VZZPj_Ak<^MjEJ`+m68%o!I|+q4X1>^!8BtSE2NO zgwm%%=|6_j7fc%W5VGXVH{0JfO?!mW*M-s*q4bwS>EPL_me&-@Ul&S06-sXpr4NMC zFNe}6O}aw1fh@T`{fkMTl5HeQ_D4PaeT~*9Ka?&sY3u@f$@^WUoznfCgh^}v<~!A$ z@(Z2Gozho1Gdsl(aOyjy<$XSU2}g}nTs?ApqUuW%OMJRkzAxtP;vvK0!+kZ_sa?`A z6R!h{FB#(dQfF@ck_NcJzPrwm@5ouwI2$(Z+o8@v`96@jD0Y}Hg9XHc#m9r0hB=Gn z<>R_q6lDbj%OB$0J$ojWAHU8oG?+b(N+F3QVp%F+yyeAF&=4d`hT=ylejs)TW*nR= zKN6q>LK3Jz0&^t1`4WguV6h3zl0f+hZvhE!4HDiW64yeb^r0wZC<+;hLWUuEE#|xq zi?|NS>ySGP$!k&WP|P+Q$)QMIi=wW@Qioz$!@crQz_ngcnD<(ge63f2H?Oxe%r+bu zrHCuVyrl>!g&U5zQpA-at`xO{lAU-}=f9hN)KRy_B zh|X5{}R`FHTSwZ;SGd@*Xs#yv?Q+e>f?1!-0QQr*FJHtW#V4T#Jv`X>$-dG6ZhIG z?$tc*)jaOCf847{+^bdGYx%g>l5wvu;$Hj5y_S!A?HTvhH}0)z+*{MQx2AD#9phd* z#Jx3&d+Q$e)+_F>scV z$}eyB_+YOdI_N}tHPN9dDQ|8aezHgL#+ey_@xk86^jaY9t$W;S!??HZajzxgUJJy% zmW+EX8TVQ;?zKtWTkE*D)^Tqg*OxYZ3R>BJS0{#H)9SSKqkTl5wvM<6hgw zz1E0(?GX3cr^FjAB{Bl1PoFby>5{s|i{~t!hs1*VnT?X1w|I`EW`Aw*oD%uHpb@`6 z=BwAHPoG&^yLiqJiMzv#n?AjE-klI#ekq%jy0me2oy<||mA!Duf?988DMexNl35Ck z4NK~3YUgMjyqcMM$vi0E`@*yE_q#2ey>Rht``gCsFAWR6{LPz}-;ou3ec0kf4f5q+ zbFA;`>f&q2F8;2vuD;PM^rdK~Z5Pk0MaxPH={job%Sxj4WzDf(a^Rod-f9q+d4s2ewx!2-mi`Rh7Uk%~8 zGvl8Dm&*^CcE~^SDB-NxT2C*ap+jf;a00re6+k+6PRJ`efaq<%8)3ouZNW z>3DyYQiO%ebc_6pCOmZJgDaF9z@wF`qYg3iCpTdFJB4$q;c`*HH;h4GE4yJ!oIOj|9Lnbi&+rqH|SjPd=zayN3 zK`IlN{zKu|<*<$ercaiOxtyCk?SSbsgk!nt!Sp>5KT$oHz7OK_)r0BrK3UGq>cRAR zh`&ZXn7#nF#Y3*H|-Cm--vkZ7-Ry|Z$kWV^cRB85kFl$nEtGAR-=vwF#Y?&u|XOSrgtRNouM8~pC-(H2h(RDex}BQ>3bsH z^gEb73-Plw9!%dynEei>zg*a@(ReU@f5e;mgX!^JSWd0RgXv2VKU+PReuS_)M?ILn zTsUiq{E!JuUk!h!dNBQM@MeDnrmq#|dV%TZ3cGjca>4XDv*H1EWk} zdi)&~w=XdLHpDN~crg77!dYlYnZWe>gt;FB(;pCaaS|jGm>%yya=QT2&d?@nHHQVYg8|m>%yia{Pno%Y|8gFnxt^&JryLOkX9;?FCGacMiGV1JmCk z?B1#6fa&K8XWb@HIerr#!-Y`-Nj)*K)x02Zh~x z)r0Ae3A3JHdc4~e`-aAY=`RSo%hiMFGvy{W#|fC;g*WvC)8`4tuGVtE^mwPsU7;RK zUx@gX>cRBIh;LF4rXL~9`he+23CEf>9!y^;?6#-}(@zv;`+(_hhd1j5rpG&89G_tN zMZ(-(!1Q?ME2mYL3#MO+cyn9>(=S8(eHss@Ux|3L{{hptB7T*|gXvcz-n2iM{vl!a zevJpy<6S0hM_~Hrg;`H9J>FGvS8F+7`rU{(#|1F`Uc^73@nHHxh&Sy3rpLQRIcqc? zOn(~j=J*b#e^c0fP~*Y$XN5UV!1V9KoBjpUG2K=_lIEm62w2O@nCwqLz0CP1ew6}Q{d~>gX!nMoAVPeeVs6m?_l}{VfS0Q zTrfS}?cn(gn0^`J*J?bNemUYzzk}(U5#OfqVEQ$PH|Hl{`iBv}PUFG!8xWtX9!%ek z_;0HR(?5y$eDz@ZrxE{%dNBQF#GCVfF#Q(9uh)1m{cd5NpMdG{4g;?X!1M=&-AA;6A3y1=Hi*1s?Cf^mw1#eO%+g z^mvzn;|fflC(Pp=n7%;R{f?FcrY{oa@eWKs0^V$oVER$QJl=unD}~(+T0WS5qA=?T zrpMng^LPiQZxD9BtL1>{R|<2#0j7Tl-qaIJ|EMtcw_y4W!tO>bA57nlcyqi1(?5y$ zzt?y${bpg-2TZ?Rn8!OX{SINbUCRN}?-geIfawpzoAm2E>&CXENvYVL9!x)9IQF!9Fnyh{`vdi0 z`bJ@n2Qd9|c+-zy`qjd`ZUWOkB33KjOn(sGTt|cHPYCn82uzQ6 zO>%yy%LUWFACeNP;~JPAf3MH;A~1cHu=|Xb52nZ8^Rpem^uvU6ex&hWdi?!0 z_qSkrysN_T2ByDL*xjt6at^A2l9KzZ&u8ya-JHkZ{hk8V{y#NBnH{ zVEQM8-5;w5({~87zrgf(hlcGBrr!^5+8<1R6yBT{f$2{O^SlU5e@fWhqV)mOyW4cRV0wHW1N#w7 zUyAtWG#*Tk&uid*08C$o`0W}GrpNo$+|PjN$07bF8V{x)k9cz)1*V^f_~$hqOpnil z;C>ZMKMV0c)p#)dBE*~XA~1a;;&*5~n0}cs&x^qH4-0cVgXz}^=lqkF1E$C4P_SRX z^c#fT7c?GBkI$*#dV%Tj_c!j(G#*Tkzhh#3!1P;$b9QPxn0`CrO*??;@&3E}&l(S= z--&p0{t2evjrd&}52oLX_+0g1`u&K1Q9YRcWyC+N9!!4}@w?T7>5mI@dk53M32%-U zVES{yv8%KkF#UO9_vh-t^u05r9P>O2OfMg)>w7T$FnDvk0Mq01KX|+V(~lR<*`vz^ z(@zv;{lWCJ;LY|9re7+|;{}+0nXvl{Egwve&l_Pofa&pf2RVB+9!!tVBjLCL)9*+8 zOBxTR$LBdP9!!4>@%uC$Opnhq;Wz}-pA>d~sqtWXeBKGiA(;M6#P8R5Fg^ahlH(9e z|F*FEFB%V~e;@H?9D?bc9uj{*GAn1JdS|rtAyQu)$+mg)xsQC zV0wIR3&$0hewJ{~K`jSNkH3TDxB}DP32(*~nEn}IjuSBbv%)#Q((=LduZk)YP+kT8opPoeyNgaL_XEGC zTp%1hrCcUF==aK%@TZk0z`w3M3;c%iT<{;1n}wrqDxU-Ym+`WX8uXU(8sX@FD?bB& zM)_^<|0v%nW4P$7@+$BjmGO5-(YKYK79R8`6?Y!6!l>GhlN>xF#V(Orv701c46LQ0njkDi32%bUKqJZhqg;~pz#mMKs2-9Z?$1=1WFnu3kw}*N#{pG?j z^9OHW`hLRhCGtZiFnxdFtmV2~F#TZRSWo#O6PSLeu!|2Rl?hBgOqk0B(_b&_M&*Z0 zV0!Gsxm+;)c;Q$t`5_aSexk6829OC%KSh|!1=CLxcC+P&OknyM!dxzxegXW~wH?6p zjl!|s@Dz@_KA8Slc=KKv zn0}At!SqLjxjzBZ9}{+6`5_aS{){ls3BmMl3+LcNXk`M^zat#G+SA_W$dTi=kE|`8byjd=o{&Dyg`5_aSehYl7 zdNBPScoPq%KLUTB{E!Jue?pk!0Ze~N*!{e&7nuHxFxLxAe?d5wtMOp^4~5+?s0Y(0 zMsm1g1YF%<&ASKO@Zk0@J@O>|U$ofa%W* zb3B9TqbcGS$%ZHsnErBjy!0d!n7%+bR;uNL=?jHjd`PoQV0wI}1JO$r0&nUGravwm8?NmGravj{j!+M#e^Z$40H%K% z-n^d=rcak^Rn{L&@4}n)8qL&_lNeg__gq+U%-sV^K|x${cIi2$Jx&I zv-0im4LUx-EN3_To$A5#2jI^oMb%e9|<_mz0}i|WBFrvT-c^1<{&;m!67roUb| zR<7lM>C1)Pk?O(pmBQ?IFg^aBpZx-+zfG9$5`*by2)npIkqJz{NSNapOur1?^e>pc z72fnOnErVwI-1b(4}dF_KLn3fu9e{utyF#kj1Q%k=>^%JN2`=ifX6ELm+gAcIOTod z8Fb1J6SPb)eS@%z z56G7ZOutf?=f+_AweaTL7)<}Ta10lPGJ)wg3cEL}2h(p7j!jYzrpNsUcd~l>Uc@%U zPf-tM{PT#%2lmSZrpKd~*e&Y8^t*)JTh)W<_X~5M1Ezl&-fSaa`cv?8WFW`{ravnj zo2KQ1>CXwfUseyMKacp^)Pw19E6v3h4afwhkBZ{G9WXsEkKNlf9!!tR$k=rCV0v7h zxii#*>2bQxb^z1k^pWiVrXL1x+5t?Dp&y$mKV$;aV~D%6)Pw175su-D3uFS*qiNh) z^371L zza0b9?-h>SAwOgS)9)8{=c)(O9~9;}5}5utJT7Ww0@I&?H-9GurpG-2-dh9He+X~R zNx<}dq-dU#fawe1%{d8}elUEq{E!JuKMLOT3z&Wayy+J({VaH%dsrTa^VmG8piE%K zV|VY)R}ZGYN0{Y+>2Z3^egV@z3~$aw!SwC$rk%m`&%&E_2Gc(eZ|-4&>36}Kb_UZQ zg*WG}V0s*D*v?@3w}oS0)%69_za#7}P!FcZeE{~0eNVu`^j8nD)nB}|;Z`uJ&e*xaK1DHNJ zMZ9STFuixpXxhQPW-LU!*-pWXFNHVl0H&{kH{$_JKS?--FOHB2On-~8Tc;jO?_C?3 zcC)Vy>m-K#1!nvz_*NODGJ)wIx8lL{&%m4Y0@H7YH|qta-zCg*buj%NVYgoE52p97 z4VP+t>}x|@_wn4-z6N{?-duBmSBcgXw1pXWg&mgXx#T zoBcVMz8T)^Pr&pW;Z6I4>G5te$03*=*LQBC*5{&YJsc=x+HJ)jL^*%wX$Q=54x^kU zS`L`ry9PAdF#QF1vz>zJQ{>$Yt}mD#?}zaC3#QM7 zH^*NveYr5}52mjW&RMDT2h&#zv;JWEDe$KLVEP&Grv701`S4~x1E$A2z^uRhKJXfN zb36qz{&9G7JO$Hlfj9jQrpG(C>|Zeb5qQ(TVEXgIY#%WF`@%U*+CE_VGAm+PO}}6Co}{Ud z{hs6mlw+0)W;xT~&2qu?4e(~UVESfwQ$Cpf5qMJ{F#YrJ=KKLne*oT`4}j^93iCJu zrhiq~Z87^9%byVDaRkhG@4ZBG9J%Pd#8xfmZ7cpf$}#uk!7K;wUvYm9rtbr9>JO&x zFU;czn0}zJd!H^BOkXU_<$~!)z?^d0bKyn*R=!kh61rr#^f`(|KzywB#| zuk{DhN&I7u>VEU!PS$LTO{cd@DZ%J&8#)BE(EbKn0 z9!&qRFy9#i({F?~=g(kze2zD-ufg;?;LY_ln0_C;xqboDT;m!RYFnxb` zGd{ue_#AAGPcZ#kvRy^nw4RmnE4og3lw4y*zpXqU{D|@}xi*QeSH2VcsB$~_G37aO zJ{-kOahdAC-%&mQ-k`ir&ds9VRo(>NsEogjivGPa{>~-Zu3Rq1xadD9R|xldLitJf z?5m}(pVfouj|uagNih9M zVLtx?)1MZ0cWF6bdha>oi|Q|W&bV8B_&Fo5zwGCX=@QE02$We#iu-$1M_fzj`ozt1#OcOpo0z+Zjy%G`wkNFg-RE#)Ijx zNXCQdk6H0x`nRljF#Y>hJeagOrI;vegxB(z&|KI zWCGJ)4{xs5!1NWuv47R_!Sq$a?m_in`tgYWm3lD!M8qFb52l|c%goiMKl!Su`E&Gi(R9+&8`!&(lQewDEMZ|cGH>x5ZPF#Qwo56KUi!1SBp z&2qu?+l6B_jf^?a=lp1Ukp=X2;S5m zOux~J2h%@e#e?bbz7xv_)8iRv>{YFg{XBHPc=xyJ!HmbVQP#(PPI?U9oF{`B|EA@^ z^zRGDj%)c~dVE=l`=9E;^y$L9?*XRo2XFcXOz%BEHSHFDei}QW<(FFVBZS@GsRy&1 za$znPOg{nMEEi1gJwG+ewV$6Zu;RgtzX#sLgXz~;@nHJLt#~kfhZPT|$7gD>eEajY z_F3^@#vifb!Srug@nHJ%!rXqr^zRG1Cr$ra-obM;^Bf1vc<*zuOgq@0i`7?RSU#BX zxx(&iT0WS*zc9-O)8lV1Hzc0-81k-1v1?>r@zZ~9d zFJStCRy>#<*SU-b(^p#YVEQRmJea=LiU-p-TJd0d?{k^Vc(6a03C}=TANzSIuDdyY zz$|C8aO||U8<>8Ju=~1tF#YqwEFVn2N0{RuOutXqeM8Fu(;pD#_y^O!3UAg6O#g;3 z%Lmir*{J&mE#H1ldR9Ek2Q%K0dkd^Tm_7>6?b`CWRy>&TgROWleYq76rk`NNgXw2j z@nHHzRy>$~xfKtlUo9MaQ`-Sd|B$fzU+Tg1YlXSKVEV^}V>pqQ2~59H*!^$yVEU(p z*`8qf=iyCzg6a2J@nHJH!m%@2KA8T9u=_vi!Su(3Sw5KlO?b2Yg6Yo*$IfawVEXgI z?jO~I>E9P-`C$4?x$ngC!SsFM&H94ri>!DseW`HlZCx&yeuS|5C-q=@d?o z-j@K=P^y7rx57mR|CkS)7V0t{8=5p=l)OGM?xnRaGv*N+@4_onI`i)jRm>!>5 z#PaRWFWMoV;{?q3ox<)%x?W&jT52k+$p5w&w z=Y?5MFyr4Bc9V3uVEW{Ypq^m*G+{SccNbkBg}CHruUxLn|faKyx!E)eqN8yC*gSlnB}Y!c2jk^ zVERXed7c2Ke?mBxrtx6CSa&T4Oz*u{kf9z-@4Z)G+S7io;H<>3d@$oL2*-M8Ibiw^h22c`VESZvZo+l| z(`Uh(`h)55J<_pDv>Y&fuCUuvJ(#|~Fv|zi4}~}7gXznJW0z_Y%!o+Y_i>cRAQuEg@e^mtc+<=gKqtP~&1)^fm%ZxwcXs|VAs z7H0Wi`VH`={$Tn|!m-P=958){u-ivHn0~V`%Lmi%hBxJd=?@6UVp0cIR`C$4}@TPn){Tbm{j+O(ae_PnSTs@fn9buLarcaaSbSxiC9~F*$PRjw)_ZD{h zst41%!Ym(5KM>y3A54#TA!1i(IbixyVYi=pF#QN&mJg;M2XD#;)8l){W1rV@!1T8W zySeJY^mx9>^1<|Yw;}cgjR(_j7k2a1gXwn)bAJw|-w*$g#)Iio@LaoAJ(zy5a4cUv zm>%yQxc$}J?;(s3&*g#{UkPuP3#OkW%)e;`)88WO4$$(!^!VO&KF0^suN2NH(0DL? zt8ms_^j|bmE$m*Y@nCv<|2yjmrjH8e4AgiqeQ#mb z6HM=YC$Om}n0^}KO+CT%jqqk1g6WsTo8u0cew`H$rf;|6!Sv5s@nHHF;LZ67m>%DA zAG=D|7fgRZ*ex{eZ27~&96w;jABQ*f2h*Q{H|qAG^h`lK10~OTI&O* zj|#IsVEVrBraoZ$B6w3DF#RxiQy(yWg)rL(OkXAJ7HNIJ^y7tDA29ticvBxR{d{;+ zA25A0ym?Lsre7l*8>Gtx(?2Zi7OMx-KO)TKg6W@zH_HXn?}j(a1=H^r=5oRG2Zh~h zbh%*qmxZ}pF#TzGQ$Cpf0=%gYm_98k-t-HYzPE5}ur3!&?+Uwd^l9514+EFzW-RzeU(B(fWYtZx?2L!1VLsO?|-h_rRO_fazP|O?|-h z>x5Y!F#V&#?hvgHn0})$>jS3mfH(C4)9-*c^#Ri#6Xx*4Xx z;mvZv^zsGj{&KL!SqG&=KWhReJQ+oZVsj| z6XxHEgXu>JyVq%b!1Ps!zuP<9Ibix~#1GSWF#RN9wm+DDhA^+E!1T4k?r<#!Og~qc z*Hd8nJK;?`fa&iQj*ZZA!1ODH-M>)}rhiD7^#s#DA{@I~*B4CxxUhS@mIJ2Wi1@!% z52k+t@n!14^iK=3f5G(I;LUo0>371L{sq$?gnvNG2h$&e#|r{7f$86XzgIn&J~vCe zIUfMi4}&-74`BN7@a8>CF#R-m^WG+yei6JWA56ar-jolf-w1EY2h(@JoASZ*FTk7q zHkf{oaO{h^zF_)&!fv^GF#Ta+mIJ0gCd_ic^v8wWky;Lz9-lkfYn1x&!bJ(?iQo$5 zhb_NL?lBgPR=->B7Zp`1J92GaG)8&8oNq^~l<^L2(OBgu zMrFLGS~Ony9Q>D*bLBiIIzf3D_$KA?;EBr1;*H6VT=85{I;C;Ma+}tEu1}FzGT`C?(*Bd!!w4zt=r1) z;@hC5rVD1<%jhCTzcKm~%aIc5v3|u}ePMWU&EiJ+qWMpWkS}}xqzGxtcyUn5#ntS* zlrHi=wS?*3ihf!-K~zxVi{ish|rbcm@i)E;JgKlcWyvEsM>uP5& zmBFdbpBbHVr}3yo^1zw4s9ES_CcUssEQOH35LmmOb`9?W<5?3t)c{5py7 zMwz#wiTVXg7S?rA6YKACifif@E}UK0DEqX}I(<$8aVK9M?|Rcv^P9iS7VdmO1mfiN z9d8Q9>C*tmxl(dvH~Oh@aft~px5_J7e{i`)l9X3UoO0F9z6J8PDZ=!~lU=eiTK?JP z;l1fo@{beCD;HsxSH3VP4{gBmZWp%8n<0tk#c^VJw~DaKdtS=hCJyyOJFvWah3)ci z+Ya~gII%pO-r40XsB@fixmunahWzsIIZbwXr{oxdcNI9XyvIb?<<0n}d>%254dT&m ztlw^7ySzJl%e(M$%;CiH@bwpVdF$F8=V=*4C=cN*@3gR8-i|!!4>@LVVtKz4VV8IP z3-Z}QS7~{2O7EA4j~+*PETa8d`I~x4b3z&T_XP>E#<*X8#<+j~jB)?<8ROpnjB!1rLBj2V_TohD*F_xL z46)>r&lp$HMI4uf^2k%Vh~u*C<<5~f%pEx_S^2i+6ldI_!u$7?ua`IW+FDYbv?F;hPdqSX|FnI#@13=0&hGIC z*UK_rU+y^j%6~Sxdo5Gr*8ObEzViH{bKCOs-g8nbIY0CFmA9qlM%K&0sBLwIL)&y^ z^K-H+IRdq{rb&&jjCds!zn9#-%Mu<=&h9a`n>}~;aYr6#yKj9m=36g^rnWVi&hToK z+awQ(_m!t+-|g>!Y>-_f$KJiEsOk#A+tA%5p$`9(vYdo6qQ2ThxLL}XnG zhsXc+qFQvcbf9%i8|ZRwkZ7GdzhL;aBR|7D`^tY=Y39fqK78~=bD*^*bXw1S%LTCS#?C8K=dk zys>&ym#sfIV$Zu}!nl^U`>yjwXWpc>lag>>kVgx}faHfad2OydgEM;M=2Q?VsE>a%D`$eRgK1(=_#z z>fS*?GR-~rkr|?^Avm=C8MlVztveIwhQLbxbC$p zD#puto28%Fli5_z{G7}g>cy@~U`(*Yp!~7UcSkdY9^5iv?WFH|BQ7u014*ON16#Yz ziL|BkaSpEEkf?d=u1G=a$zZErt?ikbG0NZSu?E@GGLoivYn%N@O47)cOMbTXzDbc| zEiEa#Q(jztaQ&eKYfxxPU>b8z^yZYmmh6>xVBG&x-M7F;Rh|2;nIQ>`s3Eb;$Vu&( zK#aK|Z$j`;40(`;F?8UFCQbTC4Z}Uu%DRuh}H_wDz9+yDQmy{@?%m*0Ws571SC-fAs!c#$rEd7~2jxk3ES=gru;D~+ z%j<8b`X_l^NN7tk2nYj(4n^@D%fx*;ihBymD7&|*_Vu+6tb2Rd9s3qs+gJ7U zfmtWlAHMIuWms&TKgy<=LNNtx=g4JU$+Z5kE`J+x_0Z)RX6Q zI`P{*y-1^`tfl-nW0;5D=l^XFukESGMPK6CqnqQSrcCCd!O~kht#Rv!4LT)-Cu_FY zxCebd=TEy^hMkk>)$&ztt=5!%v+BZniQ9V#{5q?LZ|Zoxvwy>~*Zlb+f35~k$4f(e z+IIa*zqf^>wm0)B70MieR^!OTip4iWawK~t;yA8DyWGEfZ&_yLtiI1zCf1(1dhy)j zbIa%LnwLKR&iTOwr><rC*mA+IF$dok%t(I^YoD`H*%Y73 zrag0Y>-S!ATi{3k*0SlYb3&OT1HG9?6?`GDMdv&p6dy(B{5F_6@1NDl4N}e>ec6ZY zJa5{wtNLW$6zwrIZe&pGOm7lDQ@)U~^V54oS5x*(Rf5|#w0s8j^XJ{EBX0|R@!K_J zzj5dBnzFBZtqi-bYrD1kYs&s$**p?w^GMQL`#ldkZi_2Ddelqnm*~E<=ds?0MyP~y zTJG5p>V2p-*fRP|F!W%5@T9$ZjITSyHvMp*zd!WWV}Vh9nC09n!8$2lcK@WG+w;EE zLggH>;Qa0N-~Oc!-W7Ui!=7_dx;J*uui2b5|HvJ<9&nDV>+@#uz^FU^ucgQ9k3YTD z*ESx_-FQb8-w*JeLFVzgXB&=TE#uDQ*_*C?J@nAi0baRU0`HFOeWWhbxS_W?Np1b3 zyu&zBHb|eudgq8cmN8!L?tQ3#&wY1g>^!r(@8Mr0{d_~q;iTaSNelL;UjNSdFS%{a zHA;U~f_qKZ*T!M}dUS;n!;1RV??`>SwGDP_)yIa3Ea`1UyfeFdAF2yX*^;qiquMni zy=iV={CbZo4O!9AyZBD16mMkvs_w!XYhaVN#_C^sOtRO($D0?iv*W+sJG z-%UDiAW@BMiJVY<)h%E8&*8a!SgX97bUxVg$o5ya9Nss)uj=)E1MhA)KQ&36|LQ$& zyuZ2n)f4;P|6J2d*!p*ZYpd2)7bWdcp`;|${L^p#zUYQXpoo4Ge)7M5 zJ^Izu$KOw7AHMG0;E1IIiPeFY+fEE``Sm-)Qj?NLx2$<%c+0YPgYZ8Z{!e4Yb~;17 zqc-m!82)BbLQVVrztoJVxoZD+YtF4%y)X5KcS8&Ir6xTaY1!}w;=dAk_4YU38Ay8N z%v<{g5`PeA={qs3<#+GkD!+lL1ly9Je|sP)cIGev1K7I9m zq<3a2&aa$q-#3u7>daL*C!hH)nEW#j;9PcQ^ZrTKW}a+#zVW$P$LBtq_)_|dbuV0V zZ1K?@8w)pMSUC9SCay6Uu#*Ipc1N1%~;%Yys7-^U00{iy>o7G-l;1V z*I$el?yY`HWp8F-I+Va{=^uxb= zDxo=oyEsd6Z%1OkwLhVX@9{Wdx9Snwc$8xnBX(oS0ZD&H|G3}ZGVQ>e5;sTLhZ?Q1 znth1%n#MY+ zb7wm53VQZTW3Hh!?p)VjU2`Pu=-Km~sj2?>dDu$*;vrN2+vd6dYRV;tE_3_Fj{b{( zec!Y~_d0NAHOpVJLHhZw^>yn%YAyn!`ai-dqQ6S|v8-A~IIEU^tXhU%MPQ}$99Iuq zNn{?M^)y=?CGVfIN&KPgzh~L+a_$<2vNi_!u5Ry!!VM=;Zm9!bAAp5;kQ{k^pyo(M z`o>^mK$GJE+2e-Us2x=f*0r_my&1`;_on^0>?awYh~kb&dXsm>-dx4|5C3nj*mI_i`eEACgsQbak*+>FX; z+6#xUHpb+j^pu*%QP z&n@!Dtw0(*on5i47;fdq#&uun*$*B#EQ z>S*a~ZSPnb%bVTaF}0(+U5L2M`14`P@L%w6muS#>7{o`uoyVE&D`#HUVdt~De0L0Mr?sE^MAc=Drzg~gXJ1D`O4Wbd?*4{l@=5a!heLUA+3)P`|pX1;{9XOTo9W$ zu|TS80U8dUHM7mxi@MrZaaftb9L_^;n7O(e`&nu`mUPA@PY&lbwk>VP2wxq`nu_t+ zc4;_odRJ>(7Y9yOb$J2gnb)mawW5t1SYr9?es<3vqW^g*hjmUGnpa|GkRCskox3Mi zI$@IZ^d9uNV)Vg^=2bOq?Ms*S#7atw!g*J=cXuNrv)fxSAEA}tY(?|Z?$|`*wYNbohw@P zoPjtiIE|`t#kmET_Vl@_6?3h2jY*d}Nd};+EvzsxI8(AarP9XC-{V@niPOZDd0h%Q zXZqshZ7rBSO{3JV#59dq-fXHFv_am&K)Y35^IN_au(GS2iR1sUw< zf!q!6hG=Z-#vZX2Tyz+7MptLc%(kA`ygXdCVtGwfbDCm#x@_gnYlZV#i!Q_Q!f2?o zylHUg_+_xT&U+LnY_q%bZEPKcFEm{2q!w&Yx$mx6q>07I+;L{C?9`--+MEG5vX z+HY!O%)G|V&Yl=YTqA}j=N@-m(B0GA)uYpZ9dkVnp=$axy2kg!Kl)!=AU~KNToc+J zJfNlrrUz~f)CZ$@rDtmVf8^_f{L2r1fLPmuC-ApDxHOm?I)Rv{1KXjg22O^S9CbYJ z)7DF2!@n2ceY#HJv_6~EURE!w(}9;&bx6{k4v*BG4xGTjzZro<9QDCPU>Cube%{pf zeBG|4MS-QzQTwtk6>Z-PQGXg`+ZS4-^T~2bI*CBj1HTOR;I&?(>45>H!aAYV$91ht z4|D?8g!s1R%p zS9@ERa$d)qnG^e=3_pJQ;uY=JUf1Tz)C=d%!A>ks77Oe=rskzOomQ><0wYa&bo3`(L2xq*7<-wyJRIr9GOK6@+j%s*a!7jz9&BbR&h=sq1N{m}Mj-b#b~+aK8Oj8jt@ zmX>oKr8T;(^L2aYL#B>>f;!XwFCg9NDDi3MFfBpvr*R}>1e-s4Bhx&@qeniqT;ex){QfoTRt7D zZunHJv36#~_*t>4m5bY2TiaS=(C1(W+W5uoJ(tExa|?52R~=^$6TIDM+%xwUx7oTO zq--ts$JsmXC|euk5Gw=^`oap#y}&`pb_lt<%ncjTJ0LxakQ-a{_#oE`A??*8LUB8L znZE3*H8!ER9m3R)_96p?@KhQ*gwz;Ygg(tDU*wZxJ~`bdkM+r!J~_)LXZz$FpPcKH zJxEHMVu7U zyY@XQq^7A$JrQVHoD@>kKDovx*ZSl-pL~T+uJ_4T`s4KZ(Ay!T=Gh|R&sXs^FkiVT>iF}0 z_6yYVIA($B5n0y4hA31M|NK&yyOdWT&(toXf*L#}M%k8!6_lb;4l{wi#T zyRxxgIkAl|vT{s^?-J4+aL02~UaUKZ(ld#%{ zbE!M68++%gfLi|@oVWS(w_E-WLhnucCjLQ7e+269xD9IbeCD$WVRa1PSrL(+wZPu2 zJW?HZbp%&y{S=oQsa^mc>&ixdlPix@F9CbAs?pzW>0bkGb!DU9>B=M3Z-6UZ+2{|s z@<{b2u-oUI{H3_H72f`+4f0pudkQ9nMoR$lg^lS&fU6Q&cwO;bM;KZC;!_S`|Yc z>FT38y(U*4qb5P`g{!oFu}h56^1YUPd7M9E{|!sO7MOj^gfXfL_S-~6PpX5=K4QWc ztm%~UuF7Ln6J)PG#;B_yzbNL2e+}eoEV%{pgOO~Ud-Hp`N`c-RFSE4XTjixIey`G-kBr_M59!+8>+k96BG@Op`8Dn z1K#{*@;}zqk5$g&1RUl{T|RI9Ggi$+{PmVS+aueRGp)4)$xrF{-n)QI-M3d+_AT&N z=E_<6dw}1vWIh(coBy&@59EWE{wBzkmi#Y}z4`xqnsk1axJ0fR5B)us93MYl6~)D$>5HGQCdI|i z*ZOqVU!l4@E`Ed77h3u%=vP=W)A!;Rt1IH-*ZblZtE-^*+P_%qz4j?lv*Y4V*LrU} zm#78Md+Ui3t@q~lQq>X{f40_Vx%n+s?a(i>WadBLl`m7Baq(+){2EJt9rU+Y@@F7V zbLCH}wUFy9c?0BcSn_7b^DTJ*a=9hn4cVKo;14>lelAyEhTaQ}TJP1*eL583J9!& z6x`1{&ymm5@^HoP!!YoB#wmFJ7IS2B$vCona-Jh|U6F#B=W<8h1=|$d@2hv@n3j{( zqBuE4bvrWWtQ6#GL!3NX@pn@gOn#&4Umf{1a4A^N^Y>6BFn>REp1Ux5e6)K_T5 z1fmk2@Z6UA3OpvJz5fHO!u^?Z2$Y(|h z@^!p?7N{WKcPiLMsi1O>Xz3v?A0=z7J2519HyT_Rn- z1-fo4bo&;R>QbB9EY;n^Nric?n4rsR(kh{4MTzcCCdCqMuiL-Ev~@`d$33>?G_O?p zF?(@q^qwP&svg7)oZqZsSzF7eXZAGr_>$n(pQ#=I-7g0!=BdeC6HR%ukT(`WO<;^g)=%);|onCpxRfo zbyyato`o#;LT&1=DdYg#yJq%ub$;4cSD?{gD=bgC44oEH-`;^{wTMRSHj5+9a$MQf ze1qPZWn$HLHn%o9%(Sk~m0lO|Yp!f_I-YbFCT^9cwxhkrbk8L$>h=rd89Bse}fmrytz~Y}+ z_+`M6OK?IU7JdbA)cJUhSa`ioan=yT!gIY7nSm1mvG81%M4gZEh=tz*9AU;0h=u36 zCpwd?c^@mhUVl0DLo7Vs%SinY3x60m(u5NNvG7j=N1cxaiG_a+Sn7vZ_|xQ_@)8Tr z&!8f#U<6{}F9MD_A1e|IpAIbkiG}CAL-9{6JlDVCpIG=t;OHEaF0t^lfW<$t@U7&X z{1Xem1~}q;yh$wlI^ZZf2m-P2w*rfQV&Oke-tkW?{4U^#^YJIK@Oy!y^NoLE;lBke z{)vS@Lf-LDEd2Ap5pFm~AQt{4aP%6(6ARCulS`?=34vJnx5+#HiG}BV*T_QShgkST z;OHX56ARD#sN$bk_!xP|Ke6!qj8Oa&3ttEvZ8rXih39=u@lPx~AB8IZiG}B9jFH90 z53%sq07qL4Pb~a$VDV2Z{Eg(D{1Xe$`-YKL!xIa?4OrTjSa?3CO#BlI ze-Jpb#P}f={xEQKso{x*e;Qc)6AS+Wc_;tG!oLq3;e>}kEIfY~H`;D^V&N0{{@a;< zh=sp^yyKr(c;2&2UT*x1!HZlwh{fh2;OM7~4YBZ3fFqoA5r~B^2ac{JYwpnqKMk_v zjaYaNGszpV@HYWRI&eZD7XGuq(N41QbNKC$Bb@9Jh{c}scJx}ZXV2l1AI|4uzY{pp zMQii^S@=gGN4qtxh=tz`EcquE{t$4a2PXt#;g0}EuOn;jfeZfvWXTV)@V_GOv>mbV zDQLUM^&k+4g&z$Zy}|Ir!jAzK|HQ&)lXv_R3ts{pxzYF`7XC8e=xW0g3(sjw{1Xd5 zi@f8XSoqId_Qb;PuA(p&8w}uhPvM8+2*l!_c}}^?@OJ*2 zz)L+4i~Stn=&d**5DUK;IMPp6;rVtRzXUkShC(0~drnDG55&T=Ii((mg})bA)`!Hx zZwHQU!Uc z;btU+IvhE-Yp6btm+^NPyp#N$27ixuz~JZcGJcD}CyBQj{0m|yZVXu3kyz5r1(tjg z3ttEvW#S0L!j}R^?jmbGrxc!jAi7P{as9axlw6mI#lDezqOm6yo?SM=O;rfQ!n12e z?;&eG-x8kHB>jO{`0c=vFW`i*9f$Du14r2r5Qv3;7+CT{Ed1lZkuTzeKrH-sfTLd` zi~UPDgg*rw`7&9hh=qR#IJzAt1Y+U;1T6U{7M}Bx^jl)#M*>H`0z(91;gf+Q_Zgm8 zcz$*r{i@-Kg^vPDd5MMR)Fyt2g|7jQvceFEg|7#e{1Xd*4SA=1iG^Pd9C^U_Ar`&^ zIQpRBiG{xjSo#mK@axGt{)vVE5^&@p9|jix#KP|-@AxMc{vdGV z5#xtgcwR4}I}A@O{7Kq73 z{G2}esNso)zaLoq6AQnKypw-o;a>rceADdh zCl>xb^3MAOV&NaP?1_bc#j+9(c`4-fM6f`gSrmog!=_=A?`8 zJn{cFcs<%B`CA5m&ca84bG~hOzK2TY#EdW(>5l)d!Jj4O#S`I6#QP0CM0~*Dqrk~e z82p@t@mN1K{-EKL@gmn#VkuV|uv|}xg^vM8zmF3_42SSpz>z~ZArK3n0~~#lEXssK z_(EXmC&a>+k$2jiSokr(IfrpV_`CA_0~0rf7xAg{e8li)<@qVYf8;zrZTv9*QqRPa zhbh2P&&0x)14sW2Cj?^Qxu%L7C2Q7K!Z$#UKBH;9w_W%~P}2X2gnTGQ5AC5It^qd!29*>?J?M;y;Ie{@vIU3(tFl(dP_r-zO{vFZm}H`>`<1`LVI* zx-{9rlgU4C`0Md9{)E9d<0bh8gKr`K6N5Reca-8wQsU|H@$YpX6T~ zT#lFVzcIL;yyKJYB6t{EcpLE_4c<=tros0U zzh&@FVkceB1CpNu#HVmVIE+Iur!c|CiT?v91a|%8w>4C+5Ia6u?D0c<0n2>`V&OSX zBSGVbSomDvXvpxy!WRRJA7bHIuE;QBPb@sgNHoFl#KPAAiyva)X8=bka6%v!z6m&* zX#5ZhzZ^JnIZg<~!gl~ilZ-vF@aut7<{O?^_|E}H*eMW*g})Ox%8racEIj3$5r)qq z4jat*A%|b0L15p=;YAYR^Ek#kI0`KDDzW%v{mZ;+w?(PN6N`N%u*|o_!m~c3=bCiw zx@`b2{)xqY32=l16oFWH)@Ss5!~5%2=HU*@{ag&HA-L-I^4 zHu=DkXJX-by@>J)e+c%qgLM_jG`wAJ?32+;3~%?(M(|S4#NvN3c_+`r!n3V&vW%Y; z+VI9CUvY?yF4v`oXZ<8|0fN9jnd4yQZT$Z*JoA&xHz){maf}~tFw@P+HJEdw@D~6} zT@g#V9PctG6AS;LeKpVcKdY~Dp@eW&Uo9}a-B)?NkUF%l9Zlq&IwY3-Tm+m`X#9kM z*}lW@N=zH#^Ke{PWNe5fF3T(Z!7e+m1sC#78v?P|2Z3`Y7=Ac07ky3$Of;D3;o%vY zrA=Ux!6S(;GnnHj;H;6DZs4B{&$I$uJR)#R1wLtTjM!NVjU{&0Gg-t_j1BunfL|I# zVBZdu8C*;})nNRN;@|W8rGsxk_I}^g-l%B(f~Z8pZ+^Nzg{n=tebLWZTNnK**~RGR zWrv!xp>Zg+*}OKW*4ySdl=?#=TbmyTjg2jT_CCnLZLGbJgBp0-A_rB=4#`24?q#afYSByG` z)|>7!w4PI)vjO@;jN)dG54CeUz=v8n`;7mZjp@%HYUOUF{tzo?pZ14X=&jI0>;02Q z{I4hLZs}bz{BF+v`it|c)4tw4$ai5JL!-ID`SQ%)`fJ1g#A_}NXSrfMhXo`8*AWaC zIx3ALG*>>p=W11GfFmf;?FMTAVm#cx9Lje_YehAJ}NRa&TmZR-&jpdL1OZ@SztnKf}yY25b%OCF(h(9i; zZGYc@zrp%5m+!W}ZI(Z-(ZwHc<=XxZ!ryDqOOW!;@%g(S{*HiS`||yr_*?7q_h1sn z50y?3e>eO5t(bv(lCY&ezHbnJ_xb$oJjeddus08V(dX|wv%UVu_gCWY37@|-H0~-V zZ+wybeaGi-)f~@X40hu0C7(b15UT!uDSa`BKRyeDamq*{jJ?`C3yS4U$07bWR`Ku7 zyC=`JzjN>TcxF?M8oNEr0S`(r8v4y3Vt|)9v|-BBQpyMf1%bIQq-PA^E!; zc6R>WhCk;mzxEHc4%~NQ`^#CN)b9|H{`j6x{9WVoSBk;?xN)J+;_qsozbG8N1`GPj z#v%UJ`TV^JfA?xn<|O|3EDJk-@4*qNTfF{UX!$z_*8sbH z7pIzi+~N{$bl^U9JAbXMox?y$FBnwFh$&f9XDd+~>a=CTtJhClY@Z z{`_I`8*Kbe@%cMy`75>jE%f<24u9LAmmvA$J{7yXYnFKV<2@nC-)f(~WCt=dlNGYfVYB5sg$D}4SY!|qK{!kUo&=K1V$(u__V zirr^@cKNW2i4k7K?khgK8AJFx=(B5rUB)2({^+y25q2X6u{$5@IJ^GV!46ZU8zg_l zKD#YL_-pdnZ6Cs4kI(K=*gejSI6>0A+h?~77jaA-ZVYcz z#5|tx`Fjy|-xDLphUI+4v6Jy}?j*_hO~KNre+6f5TA;^eZlAq+0@@ zf$?Pr3Tw3wcqChgY2?f~YPMZo+TFVkiJ=2)=nwGxx)cThG7 U^uvJ5e4O33cBRU!1{S;j1CZB^)c^nh literal 0 HcmV?d00001 diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/library.json b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/library.json new file mode 100644 index 0000000..3038fb6 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/library.json @@ -0,0 +1,11 @@ +{ + "name": "PDF_LIB", + "version": "1.0.0", + "build": { + "includeDir": ".", + "flags": [ + "-L.", + "-lpdf" + ] + } +} \ No newline at end of file diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdf.h b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdf.h new file mode 100644 index 0000000..3f2292e --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdf.h @@ -0,0 +1,114 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : pdf.h +* Author : WCH +* Version : V1.0.0 +* Date : 2021/06/06 +* Description : +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __PDF_H +#define __PDF_H + + +#include "pdflib.h" + +typedef LPDF_REAL *(*pFnPdfGetData)( LPDF_REAL *pBuf,LPDF_UINT offset, LPDF_UINT *num ); + +typedef struct +{ + const char **pInfo; + char ProductType[16]; + char SerialNumber[16]; + char ProtectionGrade[8]; + char ProbeType[24]; + LPDF_UINT StorageSpace; + LPDF_REAL MaxMeauRange; //测量范围 + LPDF_REAL MinMeauRange; + LPDF_UINT RecodeInterval; +}LPDF_Device_Info; + +typedef struct +{ + const char **pInfo; + char Order[12]; + char Shipper[12]; + char City[12]; + char Carrier[12]; + char Receiver[12]; + char Signature[12]; +}LPDF_Trip_Info; + +typedef struct +{ + const char **pInfo; + char StartMode[32]; + char StopMode[32]; + LPDF_BOOL IsKeyStop; + LPDF_BOOL IsTone; + LPDF_REAL MaxTempAlarm; + LPDF_REAL MinTempAlarm; + LPDF_UINT StartDelayed; + LPDF_UINT Interval; + char TempUint[4]; + LPDF_BOOL IsAlarmTone; + LPDF_REAL MaxHumiAlarm; + LPDF_REAL MinHumiAlarm; +}LPDF_Config_Info; + +typedef struct +{ + const char **pInfo; + LPDF_UINT RecordNum; + LPDF_UINT8 FirstRecordYear; + LPDF_UINT8 FirstRecordMonth; + LPDF_UINT8 FirstRecordDay; + LPDF_UINT8 FirstRecordHour; + LPDF_UINT8 FirstRecordMinute; + LPDF_UINT8 FirstRecordSec; + LPDF_UINT8 LastRecordYear; + LPDF_UINT8 LastRecordMonth; + LPDF_UINT8 LastRecordDay; + LPDF_UINT8 LastRecordHour; + LPDF_UINT8 LastRecordMinute; + LPDF_UINT8 LastRecordSec; + LPDF_REAL MaxTemperature; + LPDF_REAL MinTemperature; + LPDF_REAL AverTemperature; + LPDF_BOOL IsTemperatureAlarm; + char RecordDuration[32]; + char LastRecordTime[32]; + LPDF_REAL MaxHumidity; + LPDF_REAL MinHumidity; + LPDF_REAL AverHumidity; + LPDF_BOOL IsHumidityAlarm; +}LPDF_Statistical_Info; + +typedef struct +{ + LPDF_Doc pdf; + char FileName[32]; //header + char FileVersion[8]; + char WebUrl[32]; + LPDF_UINT TempTotalDataNum; //total number of data + LPDF_UINT HumiTotalDataNum; //total number of data + + pFnPdfGetData tempGetDataCb; + pFnPdfGetData humiGetDataCb; + LPDF_REAL *pDataBuf; + LPDF_UINT DataBufLen; + LPDF_BOOL isGraphEnable; + LPDF_BOOL isTableEnable; + LPDF_Device_Info DeviceInfo; + LPDF_Trip_Info TripInfo; + LPDF_Config_Info ConfigInfo; + LPDF_Statistical_Info StatisInfo; +}LPDF_Template_Info; + +typedef LPDF_Template_Info* LPDF_Info; + +LPDF_STATUS pdf_template_creat( LPDF_Template_Info *pTemp ); + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdflib.h b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdflib.h new file mode 100644 index 0000000..28a36ca --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/PDF_LIB/pdflib.h @@ -0,0 +1,190 @@ +#ifndef __PDFLIB_H__ +#define __PDFLIB_H__ + + + +/* native OS integer types */ +typedef signed int LPDF_INT; +typedef unsigned int LPDF_UINT; + +/* 32bit integer types + */ +typedef signed int LPDF_INT32; +typedef unsigned int LPDF_UINT32; + + +/* 16bit integer types + */ +typedef signed short LPDF_INT16; +typedef unsigned short LPDF_UINT16; + + +/* 8bit integer types + */ +typedef signed char LPDF_INT8; +typedef unsigned char LPDF_UINT8; + + +/* 8bit binary types + */ +typedef unsigned char LPDF_BYTE; + + +/* float type (32bit IEEE754) + */ +typedef float LPDF_REAL; + + +/* boolean type (0: False, !0: True) + */ +typedef signed int LPDF_BOOL; + +/* error-no type (32bit unsigned integer) + */ +typedef unsigned long LPDF_STATUS; + + +typedef uint32_t (*pFnPdfProcessData)( void *pBuf,uint32_t len ); + + +#define LPDF_OK 0 +#define LPDF_FAILED 1 +#define LPDF_TRUE 1 +#define LPDF_FALSE 0 +#define LPDF_NOERROR 0 +#define LPDF_INVALID_OBJECT 0x1033 +#define LPDF_INVALID_IMAGE 0x1030 +#define LPDF_INVALID_COLOR_SPACE 0x1020 +#define LPDF_INVALID_IMAGE_WIDTH 0x1031 +#define LPDF_PAGE_INVALID_SIZE 0x1054 +#define LPDF_INVALID_DOCUMENT 0x1025 +#define LPDF_PAGE_INVALID_FONT 0x104F + +/*----- font state -----------------------------------------------------------*/ +#define LPDF_FONT_INVALID 0x00FF +#define LPDF_FONT_COURIER 0x0000 +#define LPDF_FONT_COURIER_B 0x0001 +#define LPDF_FONT_COURIER_O 0x0002 +#define LPDF_FONT_COURIER_OB 0x0003 +#define LPDF_FONT_HELVETICA 0x0004 +#define LPDF_FONT_HELVETICA_B 0x0005 +#define LPDF_FONT_HELVETICA_O 0x0006 +#define LPDF_FONT_HELVETICA_BO 0x0007 +#define LPDF_FONT_TIMES_R 0x0008 +#define LPDF_FONT_TIMES_B 0x0009 +#define LPDF_FONT_TIMES_I 0x000A +#define LPDF_FONT_TIMES_BI 0x000B +#define LPDF_FONT_SYMBOL 0x000C +#define LPDF_FONT_ZAP 0x000D +/*----- Graphis mode ---------------------------------------------------------*/ +#define LPDF_GMODE_PAGE_DESCRIPTION 0x0001 +#define LPDF_GMODE_PATH_OBJECT 0x0002 +#define LPDF_GMODE_TEXT_OBJECT 0x0004 +#define LPDF_GMODE_CLIPPING_PATH 0x0008 +#define LPDF_GMODE_SHADING 0x0010 +#define LPDF_GMODE_INLINE_IMAGE 0x0020 +#define LPDF_GMODE_EXTERNAL_OBJECT 0x0040 +#define LPDF_GMODE_INVALID 0x0080 +#define LPDF_GMODE_OVER 0x0100 + +#define OBJ_MAX_NUM 125 + +typedef struct +{ + pFnPdfProcessData pdfProcessCb; + LPDF_INT8 *pPdfBuf; +}LPDF_Init; + +typedef enum +{ + LPDF_OBJ_INFO = 0, + LPDF_OBJ_STREAM, + LPDF_OBJ_FONT, + LPDF_OBJ_PAGE, + LPDF_OBJ_CATALOG, + LPDF_OBJ_PAGES, + LPDF_OBJ_IMAGE, + LPDF_OBJ_EOF +}LPDF_ObjType; + +typedef struct +{ + LPDF_ObjType type; + LPDF_UINT32 offset; + LPDF_UINT16 number; + LPDF_UINT32 attr[10]; + void *doc; +}LPDF_Obj; + +typedef struct +{ + LPDF_Obj obj[OBJ_MAX_NUM]; + LPDF_UINT32 offset; + LPDF_UINT16 pagesNumber; + LPDF_UINT16 objNumber; + LPDF_UINT16 imageNumber; + LPDF_STATUS error; +}LPDF_Doc_Rec; + +typedef LPDF_Obj *LPDF_Page; +typedef LPDF_Doc_Rec *LPDF_Doc; + + +/*----- LPDF Interfaces-------------------------------------------------------*/ +LPDF_STATUS LPDF_InitParam( LPDF_Init *pParam ); + +LPDF_Doc LPDF_New( LPDF_Doc pdf ); + +LPDF_STATUS LPDF_SaveToFile(LPDF_Doc pdf); + +LPDF_STATUS LPDF_Page_SetFontAndSize(LPDF_Page page,const char *font_name, LPDF_UINT8 size); + +LPDF_STATUS LPDF_Page_Get_Font_Text_Width(LPDF_Page page, const char* font_name, + const char* text, LPDF_UINT8 size, LPDF_REAL* text_width); + +LPDF_STATUS LPDF_Page_SetWordSpace(LPDF_Page page, LPDF_REAL value); + +LPDF_UINT16 LPDF_Page_GetHeight(LPDF_Page page); + +LPDF_UINT16 LPDF_Page_GetWidth(LPDF_Page page); + +LPDF_STATUS LPDF_Page_SetHeight(LPDF_Page page, LPDF_UINT16 value); + +LPDF_STATUS LPDF_Page_SetWidth(LPDF_Page page, LPDF_UINT16 value); + +LPDF_STATUS LPDF_Page_SetLineWidth(LPDF_Page page,LPDF_REAL line_width); + + +LPDF_STATUS LPDF_Page_SetRGBFill(LPDF_Page page, + LPDF_REAL r, + LPDF_REAL g, + LPDF_REAL b); + +LPDF_STATUS LPDF_Page_BeginText(LPDF_Page page); + +LPDF_STATUS LPDF_Page_MoveTextPos(LPDF_Page page, LPDF_REAL x, LPDF_REAL y); + +LPDF_STATUS LPDF_Page_ShowText(LPDF_Page page, const char *text); + +LPDF_STATUS LPDF_Page_EndText(LPDF_Page page); + +LPDF_STATUS LPDF_Page_SaveContext(LPDF_Page page); + + +LPDF_STATUS LPDF_Page_MoveTo (LPDF_Page page,LPDF_UINT16 x,LPDF_UINT16 y); + +LPDF_STATUS LPDF_Page_LineTo (LPDF_Page page,LPDF_UINT16 x,LPDF_UINT16 y); + +LPDF_STATUS LPDF_Page_RectTo(LPDF_Page page, LPDF_UINT16 x, LPDF_UINT16 y, + LPDF_UINT16 width, LPDF_UINT16 height); + +LPDF_STATUS LPDF_Page_Stroke(LPDF_Page page); + +LPDF_STATUS LPDF_Page_SetRGBStroke(LPDF_Page page, + LPDF_REAL r, + LPDF_REAL g, + LPDF_REAL b); + +LPDF_Page LPDF_AddPage(LPDF_Doc pdf); + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/README b/examples/usb-pdf-logger-none-os-ch592/lib/README new file mode 100644 index 0000000..2593a33 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/README @@ -0,0 +1,46 @@ + +This directory is intended for project specific (private) libraries. +PlatformIO will compile them to static libraries and link into executable file. + +The source code of each library should be placed in an own separate directory +("lib/your_library_name/[here are source files]"). + +For example, see a structure of the following two libraries `Foo` and `Bar`: + +|--lib +| | +| |--Bar +| | |--docs +| | |--examples +| | |--src +| | |- Bar.c +| | |- Bar.h +| | |- library.json (optional, custom build options, etc) https://docs.platformio.org/page/librarymanager/config.html +| | +| |--Foo +| | |- Foo.c +| | |- Foo.h +| | +| |- README --> THIS FILE +| +|- platformio.ini +|--src + |- main.c + +and a contents of `src/main.c`: +``` +#include +#include + +int main (void) +{ + ... +} + +``` + +PlatformIO Library Dependency Finder will find automatically dependent +libraries scanning project source files. + +More information about PlatformIO Library Dependency Finder +- https://docs.platformio.org/page/librarymanager/ldf.html diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/sw_udisk.h b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/sw_udisk.h new file mode 100644 index 0000000..a9cbe0d --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/sw_udisk.h @@ -0,0 +1,158 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : SW_UDISK.h + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/08 + * Description : header file for SW_UDISK.c +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#ifndef __SW_UDISK_H +#define __SW_UDISK_H + +#include "stdio.h" +#include "stdlib.h" + +#ifdef __cplusplus + extern "C" { +#endif + +/******************************************************************************/ +/* BulkOnly Mass Storage Class requst */ +#define CMD_UDISK_RESET 0xFF +#define CMD_UDISK_GET_MAX_LUN 0xFE + +/******************************************************************************/ +/* USB Mass Storage Class SCSI Command */ +#define CMD_U_TEST_READY 0x00 +#define CMD_U_REZERO_UNIT 0x01 +#define CMD_U_REQUEST_SENSE 0x03 +#define CMD_U_FORMAT_UNIT 0x04 +#define CMD_U_INQUIRY 0x12 +#define CMD_U_MODE_SELECT 0x15 +#define CMD_U_RELEASE 0x17 +#define CMD_U_MODE_SENSE 0x1A +#define CMD_U_START_STOP 0x1B +#define CMD_U_SEND_DIAG 0x1D +#define CMD_U_PREVT_REMOVE 0x1E +#define CMD_U_READ_FORMAT_CAPACITY 0x23 +#define CMD_U_READ_CAPACITY 0x25 +#define CMD_U_READ10 0x28 +#define CMD_U_WRITE10 0x2A +#define CMD_U_SEEK10 0x2B +#define CMD_U_WR_VERIFY10 0x2E +#define CMD_U_VERIFY10 0x2F +#define CMD_U_SYNC_CACHE 0x35 +#define CMD_U_READ_TOC 0x43 +#define CMD_U_MODE_SENSE2 0x5A +#define CMD_U_READ12 0xA8 +#define CMD_U_WRITE12 0xAA + +/******************************************************************************/ +#define MY_UDISK_SIZE 0x00000040 + +/******************************************************************************/ +/* BulkOnly */ +typedef union _BULK_ONLY_CMD +{ + uint8_t buf[ 31 ]; + struct + { + uint8_t mCBW_Sig[ 4 ]; + uint8_t mCBW_Tag[ 4 ]; + uint8_t mCBW_DataLen[ 4 ]; + uint8_t mCBW_Flag; + uint8_t mCBW_LUN; + uint8_t mCBW_CB_Len; + uint8_t mCBW_CB_Buf[ 16 ]; + } mCBW; + struct + { + uint8_t mCSW_Sig[ 4 ]; + uint8_t mCSW_Tag[ 4 ]; + uint8_t mCSW_Residue[ 4 ]; + uint8_t mCSW_Status; + } mCSW; + struct + { + uint8_t ErrorCode; + uint8_t Reserved1; + uint8_t SenseKey; + uint8_t Information[ 4 ]; + uint8_t SenseLength; + uint8_t Reserved2[ 4 ]; + uint8_t SenseCode; + uint8_t SenseCodeQua; + uint8_t Reserved3[ 4 ]; + }ReqSense; +} BULK_ONLY_CMD; + +/******************************************************************************/ +#define DEF_DEBUG_PRINTF 1 + +#define MEDIUM_INTERAL_FLASH 1 +#define MEDIUM_SPI_FLASH 2 +#define STORAGE_MEDIUM MEDIUM_SPI_FLASH + +#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) + #define DEF_CFG_DISK_SEC_SIZE 512 /* Disk sector size */ + #define DEF_FLASH_SECTOR_SIZE 512 /* Flash sector size */ + #define DEF_UDISK_SECTOR_SIZE DEF_CFG_DISK_SEC_SIZE /* UDisk sector size */ +#elif (STORAGE_MEDIUM == MEDIUM_INTERAL_FLASH) + #define DEF_CFG_DISK_SEC_SIZE 512 /* Disk sector size */ + #define DEF_FLASH_SECTOR_SIZE 512 /* Flash sector size */ + #define DEF_UDISK_SECTOR_SIZE DEF_CFG_DISK_SEC_SIZE /* UDisk sector size */ +#endif + +#define DEF_UDISK_PACK_512 512 +#define DEF_UDISK_PACK_64 64 + +/******************************************************************************/ +/* Current u-disk status related macro definition */ +#define DEF_UDISK_EN_FLAG 0x01 + +/******************************************************************************/ +/* Current u-disk transfer status related macro definitions */ +#define DEF_UDISK_BLUCK_UP_FLAG 0x01 +#define DEF_UDISK_BLUCK_DOWN_FLAG 0x02 +#define DEF_UDISK_CSW_UP_FLAG 0x04 + +//extern uint8_t UDisk_Down_Buffer[DEF_FLASH_SECTOR_SIZE]; +/******************************************************************************/ +/* external functions */ +extern volatile uint8_t Udisk_CBW_Tag_Save[ 4 ]; +extern volatile uint8_t Udisk_Sense_Key; +extern volatile uint8_t Udisk_Sense_ASC; +extern volatile uint8_t Udisk_CSW_Status; +extern volatile uint32_t UDISK_Transfer_DataLen; +extern volatile uint32_t UDISK_Cur_Sec_Lba; +extern volatile uint16_t UDISK_Sec_Pack_Count; +extern volatile uint16_t UDISK_Pack_Size; +extern BULK_ONLY_CMD mBOC; +extern volatile uint8_t Udisk_Status; +extern volatile uint8_t Udisk_Transfer_Status; +extern volatile uint32_t Udisk_Capability; +extern uint8_t UDISK_Inquity_Tab[ ]; +extern uint8_t const UDISK_Rd_Format_Capacity[ ]; +extern uint8_t const UDISK_Rd_Capacity[ ]; +extern uint8_t const UDISK_Mode_Sense_1A[ ]; +extern uint8_t const UDISK_Mode_Senese_5A[ ]; + +extern void UDISK_CMD_Deal_Status( uint8_t key, uint8_t asc, uint8_t status ); +extern void UDISK_CMD_Deal_Fail( void ); +extern void UDISK_SCSI_CMD_Deal( void ); +extern void UDISK_Bulk_UpData( void ); +extern void UDISK_Up_CSW( void ); +extern void UDISK_Up_OnePack( void ); +extern void UDISK_Out_EP_Deal( uint8_t *pbuf, uint16_t packlen ); +extern void UDISK_In_EP_Deal( void ); +extern void UDISK_Down_OnePack( uint8_t *pbuf, uint16_t packlen ); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_connect.h b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_connect.h new file mode 100644 index 0000000..dfe94d9 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_connect.h @@ -0,0 +1,59 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : usb_connect.h +* Author : WCH +* Version : V1.0 +* Date : 2016/04/12 +* Description : +*******************************************************************************/ + + + +/******************************************************************************/ +#ifndef __USB_CONNECT_H +#define __USB_CONNECT_H + +#ifdef __cplusplus +extern "C" +{ +#endif + +//#include "CONFIG.h" +#include "CH59x_common.h" + + +/************************************************************************************************** + * MACROS + **************************************************************************************************/ +/* 按键定义 */ +/* 1 - KEY */ +#define USB_CHECK_BV GPIO_Pin_9 + +#define USB_CONNECT_CHECK() (R32_PA_PIN & USB_CHECK_BV) //睡眠唤醒引脚是否释放 +/************************************************************************************************** + * TYPEDEFS + **************************************************************************************************/ + + +/************************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************************/ + + +/********************************************************************* + * FUNCTIONS + */ + +/* + * Initialization detects whether USB is connected + */ +void HAL_USBConnCheckInit(void); + + +/************************************************************************************************** +**************************************************************************************************/ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_desc.h b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_desc.h new file mode 100644 index 0000000..624aa80 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usb_desc.h @@ -0,0 +1,72 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : usb_desc.h + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/20 + * Description : header file of usb_desc.c +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef USER_USB_DESC_H_ +#define USER_USB_DESC_H_ + +#include "CH59x_common.h" + +/******************************************************************************/ +/* global define */ +/* file version */ +#define DEF_FILE_VERSION 0x0100 + +/* usb device info define */ +#define DEF_USB_VID 0x1A86 +#define DEF_USB_PID 0xFE10 + +/* USB device descriptor, device serial number(bcdDevice) */ +#define DEF_IC_PRG_VER DEF_FILE_VERSION + +/******************************************************************************/ +/* usb device endpoint size define */ +#define DEF_USBD_UEP0_SIZE 64 /* usb hs/fs device end-point 0 size */ +/* HS */ +#define DEF_USBD_HS_PACK_SIZE 512 /* usb hs device max bluk/int pack size */ +#define DEF_USBD_HS_ISO_PACK_SIZE 1024 /* usb hs device max iso pack size */ +/* FS */ +#define DEF_USBD_FS_PACK_SIZE 64 /* usb fs device max bluk/int pack size */ +#define DEF_USBD_FS_ISO_PACK_SIZE 1023 /* usb fs device max iso pack size */ +/* LS */ +#define DEF_USBD_LS_UEP0_SIZE 8 /* usb ls device end-point 0 size */ +#define DEF_USBD_LS_PACK_SIZE 64 /* usb ls device max int pack size */ + +/* FS end-point size */ +#define DEF_USBD_EP1_FS_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_EP2_FS_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_EP3_FS_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_EP4_FS_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_EP5_FS_SIZE DEF_USBD_FS_PACK_SIZE +#define DEF_USBD_EP6_FS_SIZE DEF_USBD_FS_PACK_SIZE +/* LS end-point size */ +/* ... */ + +/******************************************************************************/ +/* usb device Descriptor length, length of usb descriptors, if one descriptor not + * exists , set the length to 0 */ +#define DEF_USBD_DEVICE_DESC_LEN ((uint8_t)MyDevDescr[0]) +#define DEF_USBD_CONFIG_DESC_LEN ((uint16_t)MyCfgDescr[2] + (uint16_t)(MyCfgDescr[3] << 8)) +#define DEF_USBD_REPORT_DESC_LEN 0 +#define DEF_USBD_LANG_DESC_LEN ((uint16_t)MyLangDescr[0]) +#define DEF_USBD_MANU_DESC_LEN ((uint16_t)MyManuInfo[0]) +#define DEF_USBD_PROD_DESC_LEN ((uint16_t)MyProdInfo[0]) +#define DEF_USBD_SN_DESC_LEN ((uint16_t)MySerNumInfo[0]) + +/******************************************************************************/ +/* external variables */ +extern const uint8_t MyDevDescr[ ]; +extern const uint8_t MyCfgDescr[ ]; +extern const uint8_t MyLangDescr[ ]; +extern const uint8_t MyManuInfo[ ]; +extern const uint8_t MyProdInfo[ ]; +extern const uint8_t MySerNumInfo[ ]; + +#endif /* USER_USB_DESC_H_ */ diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usbfs_device.h b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usbfs_device.h new file mode 100644 index 0000000..af1f3d0 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/include/usbfs_device.h @@ -0,0 +1,90 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : ch32v30x_usbfs_device.h +* Author : WCH +* Version : V1.0.0 +* Date : 2022/08/20 +* Description : This file contains all the functions prototypes for the +* USBOTG firmware library. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ +#ifndef __USBFS_DEVICE_H_ +#define __USBFS_DEVICE_H_ + +#include "CH59x_common.h" + + +/******************************************************************************/ +/* Global Define */ +#ifndef __PACKED + #define __PACKED __attribute__((packed)) +#endif + +/* end-point number */ +#define DEF_UEP_IN 0x80 +#define DEF_UEP_OUT 0x00 +#define DEF_UEP0 0x00 +#define DEF_UEP1 0x01 +#define DEF_UEP2 0x02 +#define DEF_UEP3 0x03 +#define DEF_UEP4 0x04 +#define DEF_UEP5 0x05 +#define DEF_UEP6 0x06 +#define DEF_UEP7 0x07 +#define DEF_UEP_NUM 8 + +#define USBFSD_UEP_MOD_BASE 0x4000800c +#define USBFSD_UEP_DMA_BASE 0x40008010 +#define USBFSD_UEP_LEN_BASE 0x40008020 +#define USBFSD_UEP_CTL_BASE 0x40008022 +#define USBFSD_UEP_RX_EN 0x08 +#define USBFSD_UEP_TX_EN 0x04 +#define USBFSD_UEP_BUF_MOD 0x01 +#define DEF_UEP_DMA_LOAD 0 /* Direct the DMA address to the data to be processed */ +#define DEF_UEP_CPY_LOAD 1 /* Use memcpy to move data to a buffer */ +#define USBFSD_UEP_MOD(n) (*((volatile uint8_t *)(USBFSD_UEP_MOD_BASE+n))) +#define USBFSD_UEP_CTRL(n) (*((volatile uint8_t *)(USBFSD_UEP_CTL_BASE+n*0x04))) +//#define USBFSD_UEP_RX_CTRL(n) (*((volatile uint8_t *)(USBFSD_UEP_CTL_BASE+n*0x04+1))) +#define USBFSD_UEP_DMA(n) (*((volatile uint32_t *)(USBFSD_UEP_DMA_BASE+n*0x04))) +#define USBFSD_UEP_BUF(n) ((uint8_t *)(*((volatile uint32_t *)(USBFSD_UEP_DMA_BASE+n*0x04)))+0x20000000) +#define USBFSD_UEP_TLEN(n) (*((volatile uint16_t *)(USBFSD_UEP_LEN_BASE+n*0x04))) + +/* Setup Request Packets */ +#define pUSBFS_SetupReqPak ((PUSB_SETUP_REQ)USBFS_EP0_Buf) + +/*******************************************************************************/ +/* Variable Definition */ +/* Global */ +extern const uint8_t *pUSBFS_Descr; + +/* Setup Request */ +extern volatile uint8_t USBFS_SetupReqCode; +extern volatile uint8_t USBFS_SetupReqType; +extern volatile uint16_t USBFS_SetupReqValue; +extern volatile uint16_t USBFS_SetupReqIndex; +extern volatile uint16_t USBFS_SetupReqLen; + +/* USB Device Status */ +extern volatile uint8_t USBFS_DevConfig; +extern volatile uint8_t USBFS_DevAddr; +extern volatile uint8_t USBFS_DevSleepStatus; +extern volatile uint8_t USBFS_DevEnumStatus; + +/* Endpoint Buffer */ +extern __attribute__ ((aligned(4))) uint8_t USBFS_EP0_Buf[ ]; + +/* USB IN Endpoint Busy Flag */ +extern volatile uint8_t USBFS_Endp_Busy[ ]; + +/******************************************************************************/ +/* external functions */ +extern void USBFS_Device_Init(void); +extern void USBFS_Device_Endp_Init(void); +extern void USBFS_RCC_Init(void); +extern void USBFS_Send_Resume(void); +extern void USBFS_Sleep_Wakeup_Operate(void); +extern uint8_t USBFS_Endp_DataUp(uint8_t endp, uint8_t *pbuf, uint16_t len, uint8_t mod); + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/sw_udisk.c b/examples/usb-pdf-logger-none-os-ch592/lib/USB/sw_udisk.c new file mode 100644 index 0000000..d12d381 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/sw_udisk.c @@ -0,0 +1,709 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : SW_UDISK.C +* Author : WCH +* Version : V1.00 +* Date : 2021/08/01 +* Description : UDISK Source File +******************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +/******************************************************************************/ +/* Header Files */ +#include "sw_udisk.h" +#include "spi_flash.h" +#include "usbfs_device.h" +#include "Internal_Flash.h" +#include "pdfFile.h" +#include "peripheral.h" + +/******************************************************************************/ +/* Variable Definition */ + +//__attribute__ ((aligned(4))) uint8_t UDisk_Down_Buffer[DEF_FLASH_SECTOR_SIZE]; +//__attribute__ ((aligned(4))) uint8_t UDisk_Pack_Buffer[DEF_UDISK_PACK_64]; + +/******************************************************************************/ +/* INQUITY */ +uint8_t UDISK_Inquity_Tab[ ] = +{ + /* UDISK */ + 0x00, /* Peripheral Device Type:UDISK = 0x00 */ + 0x80, /* Removable */ + 0x02, /* ISO/ECMA */ + 0x02, + 0x1F, /* Additional Length */ + 0x00, /* Reserved */ + 0x00, /* Reserved */ + 0x00, /* Reserved */ + 'F', /* Vendor Information */ + 'l', + 'a', + 's', + 'h', + ' ', + ' ', + ' ', + 'U', + 'S', + 'B', + ' ', + 'S', + 'p', + 'e', + 'c', + 'i', + 'a', + 'l', + ' ', + 'D', + 'i', + 's', + 'k', + '2', + '.', + 'D', + '0' +}; + +/******************************************************************************/ +/* formatted capacity information */ +uint8_t const UDISK_Rd_Format_Capacity[ ] = +{ + 0x00, + 0x00, + 0x00, + 0x08, + ( MY_UDISK_SIZE >> 24 ) & 0xFF, + ( MY_UDISK_SIZE >> 16 ) & 0xFF, + ( MY_UDISK_SIZE >> 8 ) & 0xFF, + ( MY_UDISK_SIZE ) & 0xFF, + 0x02, + ( DEF_CFG_DISK_SEC_SIZE >> 16 ) & 0xFF, /* Number of Blocks */ + ( DEF_CFG_DISK_SEC_SIZE >> 8 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE ) & 0xFF, +}; + +/******************************************************************************/ +/* capacity information */ +uint8_t const UDISK_Rd_Capacity[ ] = +{ + ( ( MY_UDISK_SIZE - 1 ) >> 24 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) >> 16 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) >> 8 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE >> 24 ) & 0xFF, /* Number of Blocks */ + ( DEF_CFG_DISK_SEC_SIZE >> 16 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE >> 8 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE ) & 0xFF, +}; + +/******************************************************************************/ +/* MODE_SENSE data,For CMD 0X1A */ +uint8_t const UDISK_Mode_Sense_1A[ ] = +{ + 0x0B, + 0x00, + 0x00, /* 0x00:write-unprotected,0x80:write-protected */ + 0x08, + ( ( MY_UDISK_SIZE - 1 ) >> 24 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) >> 16 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) >> 8 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE >> 24 ) & 0xFF, /* Number of Blocks */ + ( DEF_CFG_DISK_SEC_SIZE >> 16 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE >> 8 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE ) & 0xFF, +}; + +/******************************************************************************/ +/* MODE_SENSE data,For CMD 0X5A */ +uint8_t const UDISK_Mode_Senese_5A[ ] = +{ + 0x00, + 0x0E, + 0x00, + 0x00, /* 0x00:write-unprotected,0x80:write-protected */ + 0x00, + 0x00, + 0x00, + 0x08, + ( ( MY_UDISK_SIZE - 1 ) >> 24 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) >> 16 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) >> 8 ) & 0xFF, + ( ( MY_UDISK_SIZE - 1 ) ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE >> 24 ) & 0xFF, /* Number of Blocks */ + ( DEF_CFG_DISK_SEC_SIZE >> 16 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE >> 8 ) & 0xFF, + ( DEF_CFG_DISK_SEC_SIZE ) & 0xFF, +}; + + +volatile uint8_t Udisk_Status = 0x00; +volatile uint8_t Udisk_Transfer_Status = 0x00; +volatile uint32_t Udisk_Capability = 0x00; +volatile uint8_t Udisk_CBW_Tag_Save[ 4 ]; +volatile uint8_t Udisk_Sense_Key = 0x00; +volatile uint8_t Udisk_Sense_ASC = 0x00; +volatile uint8_t Udisk_CSW_Status = 0x00; + +volatile uint32_t UDISK_Transfer_DataLen = 0x00; +volatile uint32_t UDISK_Cur_Sec_Lba = 0x00; +volatile uint16_t UDISK_Sec_Pack_Count = 0x00; +volatile uint16_t UDISK_Pack_Size = DEF_UDISK_PACK_64; + +BULK_ONLY_CMD mBOC; +uint8_t *pEndp2_Buf; + + +/******************************************************************************* +* Function Name : USIDK_CMD_Deal_Status +* Description : Current command execution status +* Input : key------Primary key for disk error details +* asc------Minor key for disk error details +* status---Current command execution result status +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_CMD_Deal_Status( uint8_t key, uint8_t asc, uint8_t status ) +{ + Udisk_Sense_Key = key; + Udisk_Sense_ASC = asc; + Udisk_CSW_Status = status; +} + +/******************************************************************************* +* Function Name : UDISK_CMD_Deal_Fail +* Description : The current command failed to execute +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_CMD_Deal_Fail( void ) +{ + if( Udisk_Transfer_Status & DEF_UDISK_BLUCK_UP_FLAG ) + { + /* EP2 -> STALL */ + R8_UEP2_CTRL = ( R8_UEP2_CTRL & ~MASK_UEP_T_RES ) | UEP_T_RES_STALL; + Udisk_Transfer_Status &= ~DEF_UDISK_BLUCK_UP_FLAG; + } + if( Udisk_Transfer_Status & DEF_UDISK_BLUCK_DOWN_FLAG ) + { + /* EP3 -> STALL */ + R8_UEP3_CTRL = ( R8_UEP3_CTRL & ~MASK_UEP_R_RES ) | UEP_R_RES_STALL; + Udisk_Transfer_Status &= ~DEF_UDISK_BLUCK_DOWN_FLAG; + } +} + +/******************************************************************************* +* Function Name : CMD_RD_WR_Deal_Pre +* Description : Preparation before read and write sector processing +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void CMD_RD_WR_Deal_Pre( void ) +{ + /* Save the sector number to be operated currently */ + UDISK_Cur_Sec_Lba = (uint32_t)mBOC.mCBW.mCBW_CB_Buf[ 2 ] << 24; + UDISK_Cur_Sec_Lba = UDISK_Cur_Sec_Lba + ( (uint32_t)mBOC.mCBW.mCBW_CB_Buf[ 3 ] << 16 ); + UDISK_Cur_Sec_Lba = UDISK_Cur_Sec_Lba + ( (uint32_t)mBOC.mCBW.mCBW_CB_Buf[ 4 ] << 8 ); + UDISK_Cur_Sec_Lba = UDISK_Cur_Sec_Lba + ( (uint32_t)mBOC.mCBW.mCBW_CB_Buf[ 5 ] ); + + /* Save the current length of data to be manipulated */ + UDISK_Transfer_DataLen = ( (uint32_t)mBOC.mCBW.mCBW_CB_Buf[ 7 ] << 8 ); + UDISK_Transfer_DataLen = UDISK_Transfer_DataLen + ( (uint32_t)mBOC.mCBW.mCBW_CB_Buf[ 8 ] ); + UDISK_Transfer_DataLen = UDISK_Transfer_DataLen * DEF_UDISK_SECTOR_SIZE; + + /* Clear related variables */ + UDISK_Sec_Pack_Count = 0x00; + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); +} + +/******************************************************************************* +* Function Name : UDISK_SCSI_CMD_Deal +* Description : dealing SCSI command +* Input : +* Output : +* Return : None +*******************************************************************************/ +void UDISK_SCSI_CMD_Deal( void ) +{ + uint8_t i; + + if( ( mBOC.mCBW.mCBW_Sig[ 0 ] == 'U' ) && ( mBOC.mCBW.mCBW_Sig[ 1 ] == 'S' ) + &&( mBOC.mCBW.mCBW_Sig[ 2 ] == 'B' ) && ( mBOC.mCBW.mCBW_Sig[ 3 ] == 'C' ) ) + { + Udisk_CBW_Tag_Save[ 0 ] = mBOC.mCBW.mCBW_Tag[ 0 ]; + Udisk_CBW_Tag_Save[ 1 ] = mBOC.mCBW.mCBW_Tag[ 1 ]; + Udisk_CBW_Tag_Save[ 2 ] = mBOC.mCBW.mCBW_Tag[ 2 ]; + Udisk_CBW_Tag_Save[ 3 ] = mBOC.mCBW.mCBW_Tag[ 3 ]; + + UDISK_Transfer_DataLen = ( uint32_t )mBOC.mCBW.mCBW_DataLen[ 3 ] << 24; + UDISK_Transfer_DataLen += ( ( uint32_t )mBOC.mCBW.mCBW_DataLen[ 2 ] << 16 ); + UDISK_Transfer_DataLen += ( ( uint32_t )mBOC.mCBW.mCBW_DataLen[ 1 ] << 8 ); + UDISK_Transfer_DataLen += ( ( uint32_t )mBOC.mCBW.mCBW_DataLen[ 0 ] ); + + if( UDISK_Transfer_DataLen ) + { + if( mBOC.mCBW.mCBW_Flag & 0x80 ) + { + Udisk_Transfer_Status |= DEF_UDISK_BLUCK_UP_FLAG; + } + else + { + Udisk_Transfer_Status |= DEF_UDISK_BLUCK_DOWN_FLAG; + } + } + Udisk_Transfer_Status |= DEF_UDISK_CSW_UP_FLAG; + + /* SCSI command packet processing */ + switch( mBOC.mCBW.mCBW_CB_Buf[ 0 ] ) + { + case CMD_U_INQUIRY: + /* CMD: 0x12 */ + if( UDISK_Transfer_DataLen > 0x24 ) + { + UDISK_Transfer_DataLen = 0x24; + } + + /* Add upload FLASH chip ID number */ +#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) + UDISK_Inquity_Tab[ 32 ] = (uint8_t)( Flash_ID >> 24 ); + UDISK_Inquity_Tab[ 33 ] = (uint8_t)( Flash_ID >> 16 ); + UDISK_Inquity_Tab[ 34 ] = (uint8_t)( Flash_ID >> 8 ); + UDISK_Inquity_Tab[ 35 ] = (uint8_t)( Flash_ID ); +#endif + /* UDISK Mode */ + UDISK_Inquity_Tab[ 0 ] = 0x00; + pEndp2_Buf = (uint8_t *)UDISK_Inquity_Tab; + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + break; + + case CMD_U_READ_FORMAT_CAPACITY: + /* CMD: 0x23 */ + if( ( Udisk_Status & DEF_UDISK_EN_FLAG ) ) + { + if( UDISK_Transfer_DataLen > 0x0C ) + { + UDISK_Transfer_DataLen = 0x0C; + } + + for( i = 0x00; i < UDISK_Transfer_DataLen; i++ ) + { + mBOC.buf[ i ] = UDISK_Rd_Format_Capacity[ i ]; + } + mBOC.buf[ 4 ] = ( ( Udisk_Capability >> 24 ) & 0xFF ); + mBOC.buf[ 5 ] = ( ( Udisk_Capability >> 16 ) & 0xFF ); + mBOC.buf[ 6 ] = ( ( Udisk_Capability >> 8 ) & 0xFF ); + mBOC.buf[ 7 ] = ( ( Udisk_Capability ) & 0xFF ); + pEndp2_Buf = mBOC.buf; + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + } + else + { + UDISK_CMD_Deal_Status( 0x02, 0x3A, 0x01 ); + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_READ_CAPACITY: + /* CMD: 0x25 */ + if( ( Udisk_Status & DEF_UDISK_EN_FLAG ) ) + { + if( UDISK_Transfer_DataLen > 0x08 ) + { + UDISK_Transfer_DataLen = 0x08; + } + + for( i = 0x00; i < UDISK_Transfer_DataLen; i++ ) + { + mBOC.buf[ i ] = UDISK_Rd_Capacity[ i ]; + } + mBOC.buf[ 0 ] = ( ( Udisk_Capability - 1 ) >> 24 ) & 0xFF; + mBOC.buf[ 1 ] = ( ( Udisk_Capability - 1 ) >> 16 ) & 0xFF; + mBOC.buf[ 2 ] = ( ( Udisk_Capability - 1 ) >> 8 ) & 0xFF; + mBOC.buf[ 3 ] = ( ( Udisk_Capability - 1 ) ) & 0xFF; + + pEndp2_Buf = mBOC.buf; + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + } + else + { + UDISK_CMD_Deal_Status( 0x02, 0x3A, 0x01 ); + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_READ10: + /* CMD: 0x28 */ + if( ( Udisk_Status & DEF_UDISK_EN_FLAG ) ) + { + CMD_RD_WR_Deal_Pre( ); + } + else + { + UDISK_CMD_Deal_Status( 0x02, 0x3A, 0x01 ); + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_WR_VERIFY10: + /* CMD: 0x2E */ + case CMD_U_WRITE10: + /* CMD: 0x2A */ + if( Udisk_Status & DEF_UDISK_EN_FLAG ) + { + CMD_RD_WR_Deal_Pre( ); + } + else + { + UDISK_CMD_Deal_Status( 0x02, 0x3A, 0x01 ); + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_MODE_SENSE: + /* CMD: 0x1A */ + if( ( Udisk_Status & DEF_UDISK_EN_FLAG ) ) + { + if( UDISK_Transfer_DataLen > 0x0C ) + { + UDISK_Transfer_DataLen = 0x0C; + } + for( i = 0x00; i < UDISK_Transfer_DataLen; i++ ) + { + mBOC.buf[ i ] = UDISK_Mode_Sense_1A[ i ]; + } + mBOC.buf[ 4 ] = ( Udisk_Capability >> 24 ) & 0xFF; + mBOC.buf[ 5 ] = ( Udisk_Capability >> 16 ) & 0xFF; + mBOC.buf[ 6 ] = ( Udisk_Capability >> 8 ) & 0xFF; + mBOC.buf[ 7 ] = ( Udisk_Capability ) & 0xFF; + pEndp2_Buf = mBOC.buf; + } + else + { + UDISK_CMD_Deal_Status( 0x02, 0x3A, 0x01 ); + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_MODE_SENSE2: + /* CMD: 0x5A */ + if( mBOC.mCBW.mCBW_CB_Buf[ 2 ] == 0x3F ) + { + if( UDISK_Transfer_DataLen > 0x10 ) + { + UDISK_Transfer_DataLen = 0x10; + } + + for( i = 0x00; i < UDISK_Transfer_DataLen; i++ ) + { + mBOC.buf[ i ] = UDISK_Mode_Senese_5A[ i ]; + } + mBOC.buf[ 8 ] = ( Udisk_Capability >> 24 ) & 0xFF; + mBOC.buf[ 9 ] = ( Udisk_Capability >> 16 ) & 0xFF; + mBOC.buf[ 10 ] = ( Udisk_Capability >> 8 ) & 0xFF; + mBOC.buf[ 11 ] = ( Udisk_Capability ) & 0xFF; + pEndp2_Buf = mBOC.buf; + } + else + { + UDISK_CMD_Deal_Status( 0x05, 0x20, 0x01 ); + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_REQUEST_SENSE: + /* CMD: 0x03 */ + mBOC.ReqSense.ErrorCode = 0x70; + mBOC.ReqSense.Reserved1 = 0x00; + mBOC.ReqSense.SenseKey = Udisk_Sense_Key; + mBOC.ReqSense.Information[ 0 ] = 0x00; + mBOC.ReqSense.Information[ 1 ] = 0x00; + mBOC.ReqSense.Information[ 2 ] = 0x00; + mBOC.ReqSense.Information[ 3 ] = 0x00; + mBOC.ReqSense.SenseLength = 0x0A; + mBOC.ReqSense.Reserved2[ 0 ] = 0x00; + mBOC.ReqSense.Reserved2[ 1 ] = 0x00; + mBOC.ReqSense.Reserved2[ 2 ] = 0x00; + mBOC.ReqSense.Reserved2[ 3 ] = 0x00; + mBOC.ReqSense.SenseCode = Udisk_Sense_ASC; + mBOC.ReqSense.SenseCodeQua = 0x00; + mBOC.ReqSense.Reserved3[ 0 ] = 0x00; + mBOC.ReqSense.Reserved3[ 1 ] = 0x00; + mBOC.ReqSense.Reserved3[ 2 ] = 0x00; + mBOC.ReqSense.Reserved3[ 3 ] = 0x00; + pEndp2_Buf = mBOC.buf; + Udisk_CSW_Status = 0x00; + break; + case CMD_U_TEST_READY: + if( Udisk_Status & DEF_UDISK_EN_FLAG ) + { + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + } + else + { + UDISK_CMD_Deal_Status( 0x02, 0x3A, 0x01 ); + Udisk_Transfer_Status |= DEF_UDISK_BLUCK_UP_FLAG; + UDISK_CMD_Deal_Fail( ); + } + break; + + case CMD_U_PREVT_REMOVE: + /* CMD: 0x1E */ + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + break; + + case CMD_U_VERIFY10: + /* CMD: 0x1F */ + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + break; + + case CMD_U_START_STOP: + /* CMD: 0x1B */ + UDISK_CMD_Deal_Status( 0x00, 0x00, 0x00 ); + break; + + default: + UDISK_CMD_Deal_Status( 0x05, 0x20, 0x01 ); + Udisk_Transfer_Status |= DEF_UDISK_BLUCK_UP_FLAG; + UDISK_CMD_Deal_Fail( ); + break; + } + } + else + { /* Bad package flag for CBW package */ + UDISK_CMD_Deal_Status( 0x05, 0x20, 0x02 ); + Udisk_Transfer_Status |= DEF_UDISK_BLUCK_UP_FLAG; + Udisk_Transfer_Status |= DEF_UDISK_BLUCK_DOWN_FLAG; + UDISK_CMD_Deal_Fail( ); + } +} + +/******************************************************************************* +* Function Name : UDISK_In_EP_Deal +* Description : +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_In_EP_Deal( void ) +{ + if( Udisk_Transfer_Status & DEF_UDISK_BLUCK_UP_FLAG ) + { + if( mBOC.mCBW.mCBW_CB_Buf[ 0 ] == CMD_U_READ10 ) + { + UDISK_Up_OnePack( ); + } + else + { + UDISK_Bulk_UpData( ); + } + } + else if( Udisk_Transfer_Status & DEF_UDISK_CSW_UP_FLAG ) + { + UDISK_Up_CSW( ); + } +} + +/******************************************************************************* +* Function Name : UDISK_Out_EP_Deal +* Description : Download endpoint processing +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_Out_EP_Deal( uint8_t *pbuf, uint16_t packlen ) +{ + uint32_t i; + /* Endpoint 2 download data processing */ + + if( Udisk_Transfer_Status & DEF_UDISK_BLUCK_DOWN_FLAG ) + { + UDISK_Down_OnePack( pbuf, packlen ); + } + else + { + if( packlen == 0x1F ) + { + for( i = 0; i < packlen; i++ ) + { + mBOC.buf[ i ] = *pbuf++; + } + UDISK_SCSI_CMD_Deal( ); + if( ( Udisk_Transfer_Status & DEF_UDISK_BLUCK_DOWN_FLAG ) == 0x00 ) + { + if( Udisk_Transfer_Status & DEF_UDISK_BLUCK_UP_FLAG ) + { + if( mBOC.mCBW.mCBW_CB_Buf[ 0 ] == CMD_U_READ10 ) + { + UDISK_Up_OnePack( ); + } + else + { + UDISK_Bulk_UpData( ); + } + } + else if( Udisk_CSW_Status == 0x00 ) + { + /* upload CSW */ + UDISK_Up_CSW( ); + } + } + } + } +} + +/******************************************************************************* +* Function Name : UDISK_Bulk_UpData +* Description : EP2 upload data +* Input : Transfer_DataLen--- length of data transferred +* *pBuf---data address pointer +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_Bulk_UpData( void ) +{ + uint32_t len; + + if( UDISK_Transfer_DataLen > UDISK_Pack_Size ) + { + len = UDISK_Pack_Size; + UDISK_Transfer_DataLen -= UDISK_Pack_Size; + } + else + { + len = UDISK_Transfer_DataLen; + UDISK_Transfer_DataLen = 0x00; + Udisk_Transfer_Status &= ~DEF_UDISK_BLUCK_UP_FLAG; + } + + /* Load the data into the upload buffer and start the upload */ + USBFS_Endp_DataUp(DEF_UEP2, pEndp2_Buf, len, DEF_UEP_CPY_LOAD ); +} + +/******************************************************************************* +* Function Name : UDISK_Up_CSW +* Description : Bulk endpoint endpoint 2 upload CSW package +* Input : CBW_Tag_Save---command block label +* CSW_Status---Current command execution result status +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_Up_CSW( void ) +{ + Udisk_Transfer_Status = 0x00; + + mBOC.mCSW.mCSW_Sig[ 0 ] = 'U'; + mBOC.mCSW.mCSW_Sig[ 1 ] = 'S'; + mBOC.mCSW.mCSW_Sig[ 2 ] = 'B'; + mBOC.mCSW.mCSW_Sig[ 3 ] = 'S'; + mBOC.mCSW.mCSW_Tag[ 0 ] = Udisk_CBW_Tag_Save[ 0 ]; + mBOC.mCSW.mCSW_Tag[ 1 ] = Udisk_CBW_Tag_Save[ 1 ]; + mBOC.mCSW.mCSW_Tag[ 2 ] = Udisk_CBW_Tag_Save[ 2 ]; + mBOC.mCSW.mCSW_Tag[ 3 ] = Udisk_CBW_Tag_Save[ 3 ]; + mBOC.mCSW.mCSW_Residue[ 0 ] = 0x00; + mBOC.mCSW.mCSW_Residue[ 1 ] = 0x00; + mBOC.mCSW.mCSW_Residue[ 2 ] = 0x00; + mBOC.mCSW.mCSW_Residue[ 3 ] = 0x00; + mBOC.mCSW.mCSW_Status = Udisk_CSW_Status; + + /* Load the data into the upload buffer and start the upload */ + USBFS_Endp_DataUp(DEF_UEP2, (uint8_t *)mBOC.buf, 0x0D, DEF_UEP_CPY_LOAD ); + +} + +/******************************************************************************* +* Function Name : UDISK_Up_OnePack +* Description : UDISK upload a pack +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_Up_OnePack( void ) +{ + uint8_t *pbuf = NULL; + +#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) + if( UDISK_Sec_Pack_Count == 0x00 ) + { + FLASH_RD_Block_Start( UDISK_Cur_Sec_Lba * DEF_UDISK_SECTOR_SIZE ); + } + FLASH_RD_Block( RAM_BUFFER.PDF_BUFFER.UDisk_Pack_Buffer, UDISK_Pack_Size ); + pbuf = RAM_BUFFER.PDF_BUFFER.UDisk_Pack_Buffer; +#elif (STORAGE_MEDIUM == MEDIUM_INTERAL_FLASH) + pbuf = (uint8_t*)(IFLASH_UDISK_START_ADDR + UDISK_Cur_Sec_Lba * DEF_UDISK_SECTOR_SIZE + UDISK_Pack_Size * UDISK_Sec_Pack_Count); +#endif + + /* USB upload this package data */ + USBFS_Endp_DataUp(DEF_UEP2, pbuf,UDISK_Pack_Size, DEF_UEP_CPY_LOAD ); + + /* Determine whether the current sector data is read and uploaded */ + UDISK_Sec_Pack_Count++; + UDISK_Transfer_DataLen -= UDISK_Pack_Size; + + if( UDISK_Sec_Pack_Count == ( DEF_UDISK_SECTOR_SIZE / UDISK_Pack_Size ) ) + { +#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) + PIN_FLASH_CS_HIGH( ); +#endif + UDISK_Sec_Pack_Count = 0x00; + UDISK_Cur_Sec_Lba++; + } + /* Determine whether the current sector data is read and uploaded */ + if( UDISK_Transfer_DataLen == 0x00 ) + { + Udisk_Transfer_Status &= ~DEF_UDISK_BLUCK_UP_FLAG; + } +} + +/******************************************************************************* +* Function Name : UDISK_Down_OnePack +* Description : UDISK download a pack +* Input : None +* Output : None +* Return : None +*******************************************************************************/ +void UDISK_Down_OnePack( uint8_t *pbuf, uint16_t packlen ) +{ + uint32_t address; + uint32_t sec_start_addr; + if( UDISK_Sec_Pack_Count == 0x00 ) + { + address = (uint32_t)UDISK_Cur_Sec_Lba * DEF_UDISK_SECTOR_SIZE; + sec_start_addr = ( address / DEF_FLASH_SECTOR_SIZE ) * DEF_FLASH_SECTOR_SIZE; +//#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) +// PRINT("sec_start_addr:%x\n", sec_start_addr); +// FLASH_RD_Block_Start( sec_start_addr ); +// FLASH_RD_Block(TempBuffer, 4096); +// FLASH_RD_Block_End(); +// FLASH_Erase_Sector(sec_start_addr); +// W25XXX_WR_Block(&TempBuffer[DEF_FLASH_SECTOR_SIZE], sec_start_addr+DEF_FLASH_SECTOR_SIZE, EEPROM_BLOCK_SIZE-DEF_FLASH_SECTOR_SIZE ); +//#endif + } + pdf_memcpy(RAM_BUFFER.PDF_BUFFER.UDisk_Down_Buffer + (uint32_t)UDISK_Sec_Pack_Count * UDISK_Pack_Size ,pbuf, UDISK_Pack_Size); + UDISK_Sec_Pack_Count++; + UDISK_Transfer_DataLen -= UDISK_Pack_Size; + + if( UDISK_Sec_Pack_Count == ( DEF_UDISK_SECTOR_SIZE / UDISK_Pack_Size ) ) + { + address = (uint32_t)UDISK_Cur_Sec_Lba * DEF_UDISK_SECTOR_SIZE; + sec_start_addr = ( address / DEF_FLASH_SECTOR_SIZE ) * DEF_FLASH_SECTOR_SIZE; + +#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) + W25XXX_WR_512B(RAM_BUFFER.PDF_BUFFER.UDisk_Down_Buffer, sec_start_addr, DEF_FLASH_SECTOR_SIZE ); +#elif (STORAGE_MEDIUM == MEDIUM_INTERAL_FLASH) + IFlash_Prog_512(IFLASH_UDISK_START_ADDR + sec_start_addr,(uint32_t*)RAM_BUFFER.PDF_BUFFER.UDisk_Down_Buffer); +#endif + if( UDISK_Transfer_DataLen == 0x00 ) + { + Udisk_Transfer_Status &= ~DEF_UDISK_BLUCK_DOWN_FLAG; + UDISK_Up_CSW( ); + } + UDISK_Sec_Pack_Count = 0x00; + UDISK_Cur_Sec_Lba++; + } +} diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_connect.c b/examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_connect.c new file mode 100644 index 0000000..e4fbf35 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_connect.c @@ -0,0 +1,44 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : usb_connect.c +* Author : WCH +* Version : V1.0 +* Date : 2014/05/12 +* Description : +*******************************************************************************/ + +/******************************************************************************/ +#include "usb_connect.h" + +//#define CONFIG_USB_CONNECT_DEBUG +#ifdef CONFIG_USB_CONNECT_DEBUG +#define LOG_INFO(...) PRINT(__VA_ARGS__) +#else +#define LOG_INFO(...) +#endif + +/************************************************************************************************** + * GLOBAL VARIABLES + **************************************************************************************************/ + + +/************************************************************************************************** + * FUNCTIONS - Local + **************************************************************************************************/ + +/************************************************************************************************** + * @fn HAL_USBConnCheckInit + * + * @brief Initialization detects whether USB is connected + * + * @param None + * + * @return None + **************************************************************************************************/ +void HAL_USBConnCheckInit(void) +{ + GPIOA_ModeCfg(USB_CHECK_BV, GPIO_ModeIN_PD); + GPIOA_ITModeCfg( USB_CHECK_BV, GPIO_ITMode_RiseEdge ); // Rising edge trigger + PFIC_EnableIRQ( GPIO_A_IRQn ); +} + +/******************************** endfile @ usb_connect ******************************/ diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_desc.c b/examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_desc.c new file mode 100644 index 0000000..e0f2b23 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/usb_desc.c @@ -0,0 +1,88 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : usb_desc.c + * Author : WCH + * Version : V1.0.0 + * Date : 2022/08/20 + * Description : usb device descriptor,configuration descriptor, + * string descriptors and other descriptors. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#include "usb_desc.h" + +/* Device Descriptor */ +const uint8_t MyDevDescr[ ] = +{ + 0x12, // bLength + 0x01, // bDescriptorType (Device) + 0x00, 0x02, // bcdUSB 2.00 + 0x00, // bDeviceClass (Use class information in the Interface Descriptors) + 0x00, // bDeviceSubClass + 0x00, // bDeviceProtocol + DEF_USBD_UEP0_SIZE, // bMaxPacketSize0 64 + (uint8_t)DEF_USB_VID, (uint8_t)(DEF_USB_VID >> 8), // idVendor 0x1A86 + (uint8_t)DEF_USB_PID, (uint8_t)(DEF_USB_PID >> 8), // idProduct 0xFE10 + (uint8_t)DEF_IC_PRG_VER, (uint8_t)(DEF_IC_PRG_VER>>8), // bcdDevice 1.0 + 0x01, // iManufacturer (String Index) + 0x02, // iProduct (String Index) + 0x03, // iSerialNumber (String Index) + 0x01, // bNumConfigurations 1 +}; + +/* Configuration Descriptor */ +const uint8_t MyCfgDescr[ ] = +{ + /* Configuration Descriptor */ + 0x09, // bLength + 0x02, // bDescriptorType (Configuration) + 0x20, 0x00, // wTotalLength 32 + 0x01, // bNumInterfaces 1 + 0x01, // bConfigurationValue + 0x00, // iConfiguration (String Index) + 0xC0, // bmAttributes Self Powered + 0x32, // bMaxPower 100mA + + /*****************************************************************/ + /* Interface Descriptor(UDisk) */ + 0x09, // bLength + 0x04, // bDescriptorType (Interface) + 0x00, // bInterfaceNumber 0 + 0x00, // bAlternateSetting + 0x02, // bNumEndpoints 2 + 0x08, // bInterfaceClass + 0x06, // bInterfaceSubClass + 0x50, // bInterfaceProtocol + 0x00, // iInterface (String Index) + + /* Endpoint Descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x82, // bEndpointAddress (IN/D2H) + 0x02, // bmAttributes (Bulk) + 0x40, 0x00, // wMaxPacketSize 64 + 0x00, // bInterval 0 (unit depends on device speed) + + /* Endpoint Descriptor */ + 0x07, // bLength + 0x05, // bDescriptorType (Endpoint) + 0x03, // bEndpointAddress (OUT/H2D) + 0x02, // bmAttributes (Bulk) + 0x40, 0x00, // wMaxPacketSize 64 + 0x00, // bInterval 0 (unit depends on device speed) +}; + +/* Language Descriptor */ +const uint8_t MyLangDescr[ ] = { 0x04, 0x03, 0x09, 0x04 }; + +/* Manufacturer Descriptor */ +const uint8_t MyManuInfo[ ] = { 0x0E, 0x03, 'w', 0, 'c', 0, 'h', 0, '.', 0, 'c', 0, 'n', 0 }; + +/* Product Information */ +const uint8_t MyProdInfo[ ] = { 0x16, 0x03, 'C', 0, 'H', 0, '5', 0, '9', 0, 'x', 0, 'U', 0 , 'D', 0, 'i', 0, 's', 0, 'k', 0 }; + +/* Serial Number Information */ +const uint8_t MySerNumInfo[ ] = { 0x16, 0x03, '0', 0, '1', 0, '2', 0, '3', 0, '4', 0, '5', 0 , '6', 0, '7', 0, '8', 0, '9', 0 }; + diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB/usbfs_device.c b/examples/usb-pdf-logger-none-os-ch592/lib/USB/usbfs_device.c new file mode 100644 index 0000000..48da794 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB/usbfs_device.c @@ -0,0 +1,529 @@ +/********************************** (C) COPYRIGHT ******************************* +* File Name : ch32v30x_usbotg_device.c +* Author : WCH +* Version : V1.0.0 +* Date : 2022/08/20 +* Description : This file provides all the USBOTG firmware functions. +********************************************************************************* +* Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. +* Attention: This software (modified or not) and binary are used for +* microcontroller manufactured by Nanjing Qinheng Microelectronics. +*******************************************************************************/ + +#include "usbfs_device.h" +#include "SW_UDISK.h" +#include "usb_desc.h" +#include "pdfFile.h" + +#define USB_REQ_FEAT_REMOTE_WAKEUP 0x01 +#define USB_REQ_FEAT_ENDP_HALT 0x00 + +#define DEF_STRING_DESC_LANG 0x00 +#define DEF_STRING_DESC_MANU 0x01 +#define DEF_STRING_DESC_PROD 0x02 +#define DEF_STRING_DESC_SERN 0x03 + + +/*******************************************************************************/ +/* Variable Definition */ +/* Global */ +const uint8_t *pUSBFS_Descr; + +/* Setup Request */ +volatile uint8_t USBFS_SetupReqCode; +volatile uint8_t USBFS_SetupReqType; +volatile uint16_t USBFS_SetupReqValue; +volatile uint16_t USBFS_SetupReqIndex; +volatile uint16_t USBFS_SetupReqLen; + +/* USB Device Status */ +volatile uint8_t USBFS_DevConfig; +volatile uint8_t USBFS_DevAddr; +volatile uint8_t USBFS_DevSleepStatus; +volatile uint8_t USBFS_DevEnumStatus; + +/* Endpoint Buffer */ +__attribute__ ((aligned(4))) uint8_t USBFS_EP0_Buf[ DEF_USBD_UEP0_SIZE ]; //ep0(64) +__attribute__ ((aligned(4))) uint8_t UDisk_In_Buf[ DEF_UDISK_PACK_64 ]; +__attribute__ ((aligned(4))) uint8_t UDisk_Out_Buf[ DEF_UDISK_PACK_64 ]; + +/* USB IN Endpoint Busy Flag */ +volatile uint8_t USBFS_Endp_Busy[ DEF_UEP_NUM ]; + +__attribute__((aligned(4))) uint8_t RxBuffer[MAX_PACKET_SIZE]; // IN, must even address +__attribute__((aligned(4))) uint8_t TxBuffer[MAX_PACKET_SIZE]; // OUT, must even address + + +/********************************************************************* + * @fn USB_DeviceInit + * + * @brief USB设备功能初始化,4个端点,8个通道。 + * + * @param none + * + * @return none + */ +void USBFS_DeviceInit(void) +{ + R8_USB_CTRL = 0x00; + + R8_UEP2_3_MOD = RB_UEP2_TX_EN | RB_UEP3_RX_EN; // endpoint2 OUT, endpoint3 IN + + R16_UEP0_DMA = (uint16_t)(uint32_t)pEP0_RAM_Addr; + R16_UEP2_DMA = (uint16_t)(uint32_t)pEP2_RAM_Addr; + R16_UEP3_DMA = (uint16_t)(uint32_t)pEP3_RAM_Addr; + + R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + R8_UEP2_CTRL = UEP_T_RES_NAK; + R8_UEP3_CTRL = UEP_R_RES_ACK; + + R8_USB_DEV_AD = 0x00; + R8_USB_CTRL = RB_UC_DEV_PU_EN | RB_UC_INT_BUSY | RB_UC_DMA_EN; // 启动USB设备及DMA,在中断期间中断标志未清除前自动返回NAK + R16_PIN_ANALOG_IE |= RB_PIN_USB_IE | RB_PIN_USB_DP_PU; // 防止USB端口浮空及上拉电阻 + R8_USB_INT_FG = 0xFF; // 清中断标志 + R8_UDEV_CTRL = RB_UD_PD_DIS | RB_UD_PORT_EN; // 允许USB端口 + R8_USB_INT_EN = RB_UIE_SUSPEND | RB_UIE_BUS_RST | RB_UIE_TRANSFER; +} + + +/********************************************************************* + * @fn USBFS_Device_Init + * + * @brief Initializes USB device. + * + * @return none + */ +void USBFS_Device_Init( void ) +{ + uint8_t i; + + pEP0_RAM_Addr = USBFS_EP0_Buf; + pEP2_RAM_Addr = UDisk_In_Buf; + pEP3_RAM_Addr = UDisk_Out_Buf; + + /* Clear End-points Busy Status */ + for( i=0; i=DEF_UEP1) && (endp<=DEF_UEP7) ) + { + if( USBFS_Endp_Busy[ endp ] == 0 ) + { + if( (endp == DEF_UEP1) || (endp == DEF_UEP4) ) + { + /* endp1/endp4 */ + endp_mode = USBFSD_UEP_MOD(0); + if( endp == DEF_UEP1 ) + { + endp_mode = (uint8_t)(endp_mode>>4); + } + } + else if( (endp == DEF_UEP2) || (endp == DEF_UEP3) ) + { + /* endp2/endp3 */ + endp_mode = USBFSD_UEP_MOD(1); + if( endp == DEF_UEP3 ) + { + endp_mode = (uint8_t)(endp_mode>>4); + } + } + else if( (endp == DEF_UEP5) || (endp == DEF_UEP6) ) + { + /* endp5/endp6 */ + endp_mode = USBFSD_UEP_MOD(2); + if( endp == DEF_UEP6 ) + { + endp_mode = (uint8_t)(endp_mode>>4); + } + } + else + { + /* endp7 */ + endp_mode = USBFSD_UEP_MOD(3); + } + + if( endp_mode & USBFSD_UEP_TX_EN ) + { + if( endp_mode & USBFSD_UEP_RX_EN ) + { + buf_load_offset = 64; + } + else + { + buf_load_offset = 0; + } + + if( buf_load_offset == 0 ) + { + if( mod == DEF_UEP_DMA_LOAD ) + { + /* DMA mode */ + USBFSD_UEP_DMA(endp) = (uint16_t)(uint32_t)pbuf; + } + else + { + /* copy mode */ + pdf_memcpy( USBFSD_UEP_BUF(endp), pbuf, len ); + } + } + else + { + pdf_memcpy( USBFSD_UEP_BUF(endp)+buf_load_offset, pbuf, len ); + } + /* Set end-point busy */ + USBFS_Endp_Busy[ endp ] = 0x01; + /* tx length */ + USBFSD_UEP_TLEN(endp) = len; + /* response ack */ + USBFSD_UEP_CTRL(endp) = (USBFSD_UEP_CTRL(endp) & ~MASK_UEP_T_RES) | UEP_T_RES_ACK; + } + } + else + { + return 1; + } + } + else + { + return 1; + } + + return 0; +} + + +/********************************************************************* + * @fn USB_DevTransProcess + * + * @brief USB 传输处理函数 + * + * @return none + */ +void USB_DevTransProcess(void) +{ + uint16_t len; + uint8_t intflag, errflag; + + intflag = R8_USB_INT_FG; + + if(intflag & RB_UIF_TRANSFER) + { + if((R8_USB_INT_ST & MASK_UIS_TOKEN) != MASK_UIS_TOKEN) // 非空闲 + { + switch(R8_USB_INT_ST & (MASK_UIS_TOKEN | MASK_UIS_ENDP)) + // 分析操作令牌和端点号 + { + /* end-point 0 data in interrupt */ + case UIS_TOKEN_IN | DEF_UEP0: + { + switch(USBFS_SetupReqCode) + { + case USB_GET_DESCRIPTOR: + len = USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE ? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen; // 本次传输长度 + pdf_memcpy(pEP0_DataBuf, pUSBFS_Descr, len); /* 加载上传数据 */ + USBFS_SetupReqLen -= len; + pUSBFS_Descr += len; + R8_UEP0_T_LEN = len; + R8_UEP0_CTRL ^= RB_UEP_T_TOG; // 翻转 + break; + + case USB_SET_ADDRESS: + R8_USB_DEV_AD = (R8_USB_DEV_AD & RB_UDA_GP_BIT) | USBFS_DevAddr; + R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + break; + + default: + R8_UEP0_T_LEN = 0; // 状态阶段完成中断或者是强制上传0长度数据包结束控制传输 + R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + break; + } + } + break; + + case UIS_TOKEN_OUT | DEF_UEP0: + len = R8_USB_RX_LEN; + break; + + case UIS_TOKEN_IN | DEF_UEP2: + R8_UEP2_CTRL ^= RB_UEP_T_TOG; + R8_UEP2_CTRL = (R8_UEP2_CTRL & ~MASK_UEP_T_RES) | UEP_T_RES_NAK; + USBFS_Endp_Busy[ DEF_UEP2 ] = 0; + UDISK_In_EP_Deal(); + break; + + case UIS_TOKEN_OUT | DEF_UEP3: + if(R8_USB_INT_ST & RB_UIS_TOG_OK) + { // 不同步的数据包将丢弃 + R8_UEP3_CTRL ^= RB_UEP_R_TOG; + len = R8_USB_RX_LEN; + R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_NAK; + UDISK_Out_EP_Deal(UDisk_Out_Buf,len); + R8_UEP3_CTRL = (R8_UEP3_CTRL & ~MASK_UEP_R_RES) | UEP_R_RES_ACK; + } + break; + + default: + break; + } + R8_USB_INT_FG = RB_UIF_TRANSFER; + } + + if(R8_USB_INT_ST & RB_UIS_SETUP_ACT) // Setup包处理 + { + R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_NAK; + /* Store All Setup Values */ + USBFS_SetupReqType = pSetupReqPak->bRequestType; + USBFS_SetupReqCode = pSetupReqPak->bRequest; + USBFS_SetupReqLen = pSetupReqPak->wLength; + USBFS_SetupReqValue = pSetupReqPak->wValue; + USBFS_SetupReqIndex = pSetupReqPak->wIndex; + + len = 0; + errflag = 0; + if((USBFS_SetupReqType & USB_REQ_TYP_MASK) != USB_REQ_TYP_STANDARD) + { + /* usb non-standard request processing */ + if (( USBFS_SetupReqType & USB_REQ_TYP_MASK ) == USB_REQ_TYP_CLASS) + { + if (USBFS_SetupReqCode == CMD_UDISK_GET_MAX_LUN) + { + USBFS_EP0_Buf[0] = 0; + pUSBFS_Descr = (uint8_t*)USBFS_EP0_Buf; + len = 1; + } + else if (USBFS_SetupReqCode == CMD_UDISK_RESET) + { + /* UDisk Reset */ + Udisk_Sense_Key = 0x00; + Udisk_Sense_ASC = 0x00; + Udisk_CSW_Status = 0x00; + Udisk_Transfer_Status = 0x00; + UDISK_Transfer_DataLen = 0x00; + } + else + { + errflag = 0xFF; + } + } + else + { + errflag = 0xFF; /* 非标准请求 */ + } + } + else /* 标准请求 */ + { + switch(USBFS_SetupReqCode) + { + case USB_GET_DESCRIPTOR: + { + switch((uint8_t)( USBFS_SetupReqValue >> 8 )) + { + /* get usb device descriptor */ + case USB_DESCR_TYP_DEVICE: + { + pUSBFS_Descr = MyDevDescr; + len = DEF_USBD_DEVICE_DESC_LEN; + } + break; + + /* get usb configuration descriptor */ + case USB_DESCR_TYP_CONFIG: + { + pUSBFS_Descr = MyCfgDescr; + len = DEF_USBD_CONFIG_DESC_LEN; + } + break; + + case USB_DESCR_TYP_STRING: + { + switch( (uint8_t)( USBFS_SetupReqValue & 0xFF ) ) + { + /* Descriptor 0, Language descriptor */ + case DEF_STRING_DESC_LANG: + pUSBFS_Descr = MyLangDescr; + len = DEF_USBD_LANG_DESC_LEN; + break; + + /* Descriptor 1, Manufacturers String descriptor */ + case DEF_STRING_DESC_MANU: + pUSBFS_Descr = MyManuInfo; + len = DEF_USBD_MANU_DESC_LEN; + break; + + /* Descriptor 2, Product String descriptor */ + case DEF_STRING_DESC_PROD: + pUSBFS_Descr = MyProdInfo; + len = DEF_USBD_PROD_DESC_LEN; + break; + + /* Descriptor 3, Serial-number String descriptor */ + case DEF_STRING_DESC_SERN: + pUSBFS_Descr = MySerNumInfo; + len = DEF_USBD_SN_DESC_LEN; + break; + + default: + errflag = 0xFF; // 不支持的字符串描述符 + break; + } + } + break; + + default: + errflag = 0xff; + break; + } + if(USBFS_SetupReqLen > len) + USBFS_SetupReqLen = len; //实际需上传总长度 + len = (USBFS_SetupReqLen >= DEF_USBD_UEP0_SIZE) ? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen; + pdf_memcpy(pEP0_DataBuf, pUSBFS_Descr, len); + pUSBFS_Descr += len; + } + break; + + case USB_SET_ADDRESS: + USBFS_DevAddr = (uint8_t)( USBFS_SetupReqValue & 0xFF ); + break; + + case USB_GET_CONFIGURATION: + pEP0_DataBuf[0] = USBFS_DevConfig; + if(USBFS_SetupReqLen > 1) + USBFS_SetupReqLen = 1; + break; + + case USB_SET_CONFIGURATION: + USBFS_DevConfig = (uint8_t)( USBFS_SetupReqValue & 0xFF ); + USBFS_DevEnumStatus = 0x01; + break; + + case USB_CLEAR_FEATURE: + { + if((USBFS_SetupReqType & USB_REQ_RECIP_MASK) == USB_REQ_RECIP_ENDP) // 端点 + { + switch(USBFS_SetupReqIndex & 0xff) + { + case 0x82: + R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; + break; + case 0x02: + R8_UEP2_CTRL = (R8_UEP2_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; + break; + case 0x81: + R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_T_TOG | MASK_UEP_T_RES)) | UEP_T_RES_NAK; + break; + case 0x01: + R8_UEP1_CTRL = (R8_UEP1_CTRL & ~(RB_UEP_R_TOG | MASK_UEP_R_RES)) | UEP_R_RES_ACK; + break; + default: + errflag = 0xFF; // 不支持的端点 + break; + } + } + else + errflag = 0xFF; + } + break; + + case USB_GET_INTERFACE: + pEP0_DataBuf[0] = 0x00; + if(USBFS_SetupReqLen > 1) + USBFS_SetupReqLen = 1; + break; + + case USB_GET_STATUS: + pEP0_DataBuf[0] = 0x00; + pEP0_DataBuf[1] = 0x00; + if(USBFS_SetupReqLen > 2) + USBFS_SetupReqLen = 2; + break; + + default: + errflag = 0xff; + break; + } + } + + if(errflag == 0xff) // 错误或不支持 + { + // SetupReqCode = 0xFF; + R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_STALL | UEP_T_RES_STALL; // STALL + } + else + { + if(USBFS_SetupReqType & 0x80) // 上传 + { + len = (USBFS_SetupReqLen > DEF_USBD_UEP0_SIZE) ? DEF_USBD_UEP0_SIZE : USBFS_SetupReqLen; + USBFS_SetupReqLen -= len; + } + else + { + len = 0; // 下传 + } + R8_UEP0_T_LEN = len; + R8_UEP0_CTRL = RB_UEP_R_TOG | RB_UEP_T_TOG | UEP_R_RES_ACK | UEP_T_RES_ACK; // 默认数据包是DATA1 + } + + R8_USB_INT_FG = RB_UIF_TRANSFER; + } + } + else if(intflag & RB_UIF_BUS_RST) + { + R8_USB_DEV_AD = 0; + R8_UEP0_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + R8_UEP1_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + R8_UEP2_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + R8_UEP3_CTRL = UEP_R_RES_ACK | UEP_T_RES_NAK; + R8_USB_INT_FG = RB_UIF_BUS_RST; + } + else if(intflag & RB_UIF_SUSPEND) + { + if(R8_USB_MIS_ST & RB_UMS_SUSPEND) + { + ; + } // 挂起 + else + { + ; + } // 唤醒 + R8_USB_INT_FG = RB_UIF_SUSPEND; + } + else + { + R8_USB_INT_FG = intflag; + } +} + + +/********************************************************************* + * @fn USB_IRQHandler + * + * @brief USB中断函数 + * + * @return none + */ +__INTERRUPT +__HIGH_CODE +void USB_IRQHandler(void) /* USB中断服务程序,使用寄存器组1 */ +{ + USB_DevTransProcess(); +} diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CH592UFI.c b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CH592UFI.c new file mode 100644 index 0000000..1d782f0 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CH592UFI.c @@ -0,0 +1,330 @@ +/* 2014.09.09 +***************************************** +** Copyright (C) W.ch 1999-2019 ** +** Web: http://wch.cn ** +***************************************** +** USB-flash File Interface for CH592 ** +** KEIL423, gcc 8.20 ** +***************************************** +*/ +/* CHRV3 U盘主机文件系统接口, 支持: FAT12/FAT16/FAT32 */ + +//#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节(可以选择为2048甚至4096以支持某些大扇区的U盘),为0则禁止在本文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */ +/* 如果需要复用磁盘数据缓冲区以节约RAM,那么可将DISK_BASE_BUF_LEN定义为0以禁止在本文件中定义缓冲区,而由应用程序在调用CHRV3LibInit之前将与其它程序合用的缓冲区起始地址置入pDISK_BASE_BUF变量 */ + +#define NO_DEFAULT_ACCESS_SECTOR 1 /* 禁止默认的磁盘扇区读写子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_DISK_CONNECT 1 /* 禁止默认的检查磁盘连接子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默认的文件名枚举回调程序,下面用自行编写的程序代替它 */ + +#include "CH59x_common.h" +#include "CHRV3UFI.h" +#include "Internal_Flash.h" +#include "SW_UDISK.h" +#include "pdfFile.h" +#include "spi_flash.h" +#include "peripheral.h" + +UINT8 CtrlGetConfigDescrTB(void) // 获取配置描述符,返回在TxBuffer中 +{ + return (CtrlGetConfigDescr()); +} + +CMD_PARAM_I mCmdParam; /* 命令参数 */ +#if DISK_BASE_BUF_LEN > 0 +//UINT8 DISK_BASE_BUF[ DISK_BASE_BUF_LEN ] __attribute__((at(BA_RAM+SZ_RAM/2))); /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ +//UINT8 DISK_BASE_BUF[DISK_BASE_BUF_LEN] __attribute__((aligned(4))); /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ +//UINT8 DISK_FAT_BUF[ DISK_BASE_BUF_LEN ] __attribute__((aligned (4))); /* 外部RAM的磁盘FAT数据缓冲区,缓冲区长度为一个扇区的长度 */ +#endif + +/* 以下程序可以根据需要修改 */ + +#ifndef NO_DEFAULT_ACCESS_SECTOR /* 在应用程序中定义NO_DEFAULT_ACCESS_SECTOR可以禁止默认的磁盘扇区读写子程序,然后用自行编写的程序代替它 */ +//if ( use_external_interface ) { // 替换U盘扇区底层读写子程序 +// CHRV3vSectorSize=512; // 设置实际的扇区大小,必须是512的倍数,该值是磁盘的扇区大小 +// CHRV3vSectorSizeB=9; // 设置实际的扇区大小的位移数,512则对应9,1024对应10,2048对应11 +// CHRV3DiskStatus=DISK_MOUNTED; // 强制块设备连接成功(只差分析文件系统) +//} + +UINT8 CHRV3ReadSector(UINT8 SectCount, PUINT8 DataBuf) /* 从磁盘读取多个扇区的数据到缓冲区中 */ +{ + UINT8 retry; + // if ( use_external_interface ) return( extReadSector( CHRV3vLbaCurrent, SectCount, DataBuf ) ); /* 外部接口 */ + for(retry = 0; retry < 3; retry++) + { /* 错误重试 */ + pCBW->mCBW_DataLen = (UINT32)SectCount << CHRV3vSectorSizeB; /* 数据传输长度 */ + pCBW->mCBW_Flag = 0x80; + pCBW->mCBW_LUN = CHRV3vCurrentLun; + pCBW->mCBW_CB_Len = 10; + pCBW->mCBW_CB_Buf[0] = SPC_CMD_READ10; + pCBW->mCBW_CB_Buf[1] = 0x00; + pCBW->mCBW_CB_Buf[2] = (UINT8)(CHRV3vLbaCurrent >> 24); + pCBW->mCBW_CB_Buf[3] = (UINT8)(CHRV3vLbaCurrent >> 16); + pCBW->mCBW_CB_Buf[4] = (UINT8)(CHRV3vLbaCurrent >> 8); + pCBW->mCBW_CB_Buf[5] = (UINT8)(CHRV3vLbaCurrent); + pCBW->mCBW_CB_Buf[6] = 0x00; + pCBW->mCBW_CB_Buf[7] = 0x00; + pCBW->mCBW_CB_Buf[8] = SectCount; + pCBW->mCBW_CB_Buf[9] = 0x00; + CHRV3BulkOnlyCmd(DataBuf); /* 执行基于BulkOnly协议的命令 */ + if(CHRV3IntStatus == ERR_SUCCESS) + { + return (ERR_SUCCESS); + } + CHRV3IntStatus = CHRV3AnalyzeError(retry); + if(CHRV3IntStatus != ERR_SUCCESS) + { + return (CHRV3IntStatus); + } + } + return (CHRV3IntStatus = ERR_USB_DISK_ERR); /* 磁盘操作错误 */ +} + + #ifdef EN_DISK_WRITE +UINT8 CHRV3WriteSector(UINT8 SectCount, PUINT8 DataBuf) /* 将缓冲区中的多个扇区的数据块写入磁盘 */ +{ + UINT8 retry; + // if ( use_external_interface ) return( extWriteSector( CHRV3vLbaCurrent, SectCount, DataBuf ) ); /* 外部接口 */ + for(retry = 0; retry < 3; retry++) + { /* 错误重试 */ + pCBW->mCBW_DataLen = (UINT32)SectCount << CHRV3vSectorSizeB; /* 数据传输长度 */ + pCBW->mCBW_Flag = 0x00; + pCBW->mCBW_LUN = CHRV3vCurrentLun; + pCBW->mCBW_CB_Len = 10; + pCBW->mCBW_CB_Buf[0] = SPC_CMD_WRITE10; + pCBW->mCBW_CB_Buf[1] = 0x00; + pCBW->mCBW_CB_Buf[2] = (UINT8)(CHRV3vLbaCurrent >> 24); + pCBW->mCBW_CB_Buf[3] = (UINT8)(CHRV3vLbaCurrent >> 16); + pCBW->mCBW_CB_Buf[4] = (UINT8)(CHRV3vLbaCurrent >> 8); + pCBW->mCBW_CB_Buf[5] = (UINT8)(CHRV3vLbaCurrent); + pCBW->mCBW_CB_Buf[6] = 0x00; + pCBW->mCBW_CB_Buf[7] = 0x00; + pCBW->mCBW_CB_Buf[8] = SectCount; + pCBW->mCBW_CB_Buf[9] = 0x00; + CHRV3BulkOnlyCmd(DataBuf); /* 执行基于BulkOnly协议的命令 */ + if(CHRV3IntStatus == ERR_SUCCESS) + { + mDelayuS(200); /* 写操作后延时 */ + return (ERR_SUCCESS); + } + CHRV3IntStatus = CHRV3AnalyzeError(retry); + if(CHRV3IntStatus != ERR_SUCCESS) + { + return (CHRV3IntStatus); + } + } + return (CHRV3IntStatus = ERR_USB_DISK_ERR); /* 磁盘操作错误 */ +} + #endif +#else +UINT8 CHRV3ReadSector(UINT8 SectCount, PUINT8 DataBuf) /* Read multiple sectors of data from disk into a buffer */ +{ + int len; + uint32_t addr; + + len =(uint32_t)SectCount << CHRV3vSectorSizeB; + addr = CHRV3vLbaCurrent * DEF_UDISK_SECTOR_SIZE; + + FLASH_RD_Block_Start( addr ); + FLASH_RD_Block( DataBuf, len ); + FLASH_RD_Block_End(); +// pdf_memcpy(DataBuf, (uint8_t *)addr, len); + CHRV3IntStatus = ERR_SUCCESS; + + return ERR_SUCCESS; +} + +UINT8 CHRV3WriteSector(UINT8 SectCount, PUINT8 DataBuf) /* Write data blocks of multiple sectors in the buffer to disk */ +{ + int len; + uint32_t addr; + + len =(uint32_t)SectCount << CHRV3vSectorSizeB; + addr = CHRV3vLbaCurrent * DEF_UDISK_SECTOR_SIZE; + + pdf_memcpy(RAM_BUFFER.PDF_BUFFER.UDisk_Down_Buffer, DataBuf, len); + W25XXX_WR_512B(RAM_BUFFER.PDF_BUFFER.UDisk_Down_Buffer, addr, 512); +// IFlash_Prog_512( addr,(uint32_t*)UDisk_Down_Buffer); + CHRV3IntStatus = ERR_SUCCESS; + + return ERR_SUCCESS; +} +#endif // NO_DEFAULT_ACCESS_SECTOR + +#ifndef NO_DEFAULT_DISK_CONNECT /* 在应用程序中定义NO_DEFAULT_DISK_CONNECT可以禁止默认的检查磁盘连接子程序,然后用自行编写的程序代替它 */ + +/* +约定: USB设备地址分配规则(参考USB_DEVICE_ADDR) +地址值 设备位置 +0x02 内置Root-HUB0下的USB设备或外部HUB +0x03 内置Root-HUB1下的USB设备或外部HUB +0x1x 内置Root-HUB0下的外部HUB的端口x下的USB设备,x为1~n +0x2x 内置Root-HUB1下的外部HUB的端口x下的USB设备,x为1~n +*/ + +//#define UHUB_DEV_ADDR ( CHRV3vRootPort ? R8_USB1_DEV_AD : R8_USB0_DEV_AD ) +//#define UHUB_MIS_STAT ( CHRV3vRootPort ? R8_USB1_MIS_ST : R8_USB0_MIS_ST ) +//#define UHUB_HOST_CTRL ( CHRV3vRootPort ? R8_UHOST1_CTRL : R8_UHOST0_CTRL ) +//#define UHUB_INT_FLAG ( CHRV3vRootPort ? R8_USB1_INT_FG : R8_USB0_INT_FG ) +#define UHUB_DEV_ADDR R8_USB_DEV_AD +#define UHUB_MIS_STAT R8_USB_MIS_ST +#define UHUB_HOST_CTRL R8_UHOST_CTRL +#define UHUB_INT_FLAG R8_USB_INT_FG +#define bUMS_ATTACH RB_UMS_DEV_ATTACH +#define bUMS_SUSPEND RB_UMS_SUSPEND + +/* 检查磁盘是否连接 */ +UINT8 CHRV3DiskConnect(void) +{ + UINT8 ums, devaddr; + UHUB_DEV_ADDR = UHUB_DEV_ADDR & 0x7F; + ums = UHUB_MIS_STAT; + devaddr = UHUB_DEV_ADDR; + if(devaddr == USB_DEVICE_ADDR) + { /* 内置Root-HUB下的USB设备 */ + // if ( UHUB_HOST_CTRL & RB_UH_PORT_EN ) { /* 内置Root-HUB下的USB设备存在且未插拔 */ + if(ums & bUMS_ATTACH) + { /* 内置Root-HUB下的USB设备存在 */ + // if ( ( UHUB_INT_FLAG & UIF_DETECT ) == 0 ) { /* 内置Root-HUB下的USB设备存在且未插拔 */ + if((ums & bUMS_SUSPEND) == 0) + { /* 内置Root-HUB下的USB设备存在且未插拔 */ + return (ERR_SUCCESS); /* USB设备已经连接且未插拔 */ + } + else + { /* 内置Root-HUB下的USB设备存在 */ + mDiskConnect: + CHRV3DiskStatus = DISK_CONNECT; /* 曾经断开过 */ + return (ERR_SUCCESS); /* 外部HUB或USB设备已经连接或者断开后重新连接 */ + } + } + else + { /* USB设备断开 */ + mDiskDisconn: + CHRV3DiskStatus = DISK_DISCONNECT; + return (ERR_USB_DISCON); + } + } + #ifndef FOR_ROOT_UDISK_ONLY + else if(devaddr > 0x10 && devaddr <= 0x14) + { /* 外部HUB的端口下的USB设备 */ + // if ( UHUB_HOST_CTRL & RB_UH_PORT_EN ) { /* 内置Root-HUB下的外部HUB存在且未插拔 */ + if(ums & bUMS_ATTACH) + { /* 内置Root-HUB下的USB设备存在 */ + // if ( ( UHUB_INT_FLAG & UIF_DETECT ) == 0 ) { /* 内置Root-HUB下的USB设备存在且未插拔 */ + if((ums & bUMS_SUSPEND) == 0) + { /* 内置Root-HUB下的USB设备存在且未插拔 */ + TxBuffer[MAX_PACKET_SIZE - 1] = devaddr; /* 备份 */ + UHUB_DEV_ADDR = USB_DEVICE_ADDR - 1 + (UHUB_DEV_ADDR >> 4); /* 设置USB主机端的USB地址指向HUB */ + CHRV3IntStatus = HubGetPortStatus(TxBuffer[MAX_PACKET_SIZE - 1] & 0x0F); /* 查询HUB端口状态,返回在TxBuffer中 */ + if(CHRV3IntStatus == ERR_SUCCESS) + { + if(TxBuffer[2] & (1 << (HUB_C_PORT_CONNECTION - 0x10))) + { /* 检测到HUB端口上的插拔事件 */ + CHRV3DiskStatus = DISK_DISCONNECT; /* 假定为HUB端口上的USB设备断开 */ + HubClearPortFeature(TxBuffer[MAX_PACKET_SIZE - 1] & 0x0F, HUB_C_PORT_CONNECTION); /* 清除HUB端口连接事件状态 */ + } + UHUB_DEV_ADDR = TxBuffer[MAX_PACKET_SIZE - 1]; /* 设置USB主机端的USB地址指向USB设备 */ + if(TxBuffer[0] & (1 << HUB_PORT_CONNECTION)) + { /* 连接状态 */ + if(CHRV3DiskStatus < DISK_CONNECT) + { + CHRV3DiskStatus = DISK_CONNECT; /* 曾经断开过 */ + } + return (ERR_SUCCESS); /* USB设备已经连接或者断开后重新连接 */ + } + else + { + // CHRV3DiskStatus = DISK_DISCONNECT; + // return( ERR_USB_DISCON ); + CHRV3DiskStatus = DISK_CONNECT; + return (ERR_HUB_PORT_FREE); /* HUB已经连接但是HUB端口尚未连接磁盘 */ + } + } + else + { + UHUB_DEV_ADDR = TxBuffer[MAX_PACKET_SIZE - 1]; /* 设置USB主机端的USB地址指向USB设备 */ + if(CHRV3IntStatus == ERR_USB_DISCON) + { + // CHRV3DiskStatus = DISK_DISCONNECT; + // return( ERR_USB_DISCON ); + goto mDiskDisconn; + } + else + { + CHRV3DiskStatus = DISK_CONNECT; /* HUB操作失败 */ + return (CHRV3IntStatus); + } + } + } + else + { /* 内置Root-HUB下的USB设备存在,外部HUB或USB设备已经连接或者断开后重新连接 */ + // CHRV3DiskStatus = DISK_CONNECT; /* 曾经断开过 */ + // return( ERR_SUCCESS ); /* 外部HUB或USB设备已经连接或者断开后重新连接 */ + goto mDiskConnect; + } + } + else + { /* 外部HUB断开 */ + CHRV3DiskStatus = DISK_DISCONNECT; + } + } + #endif + else + { + // CHRV3DiskStatus = DISK_DISCONNECT; + // return( ERR_USB_DISCON ); + goto mDiskDisconn; + } +} +#endif // NO_DEFAULT_DISK_CONNECT + +#ifndef NO_DEFAULT_FILE_ENUMER /* 在应用程序中定义NO_DEFAULT_FILE_ENUMER可以禁止默认的文件名枚举回调程序,然后用自行编写的程序代替它 */ +void xFileNameEnumer(void) /* 文件名枚举回调子程序 */ +{ + /* 如果指定枚举序号CHRV3vFileSize为0xFFFFFFFF后调用FileOpen,那么每搜索到一个文件FileOpen都会调用本回调程序, + 回调程序xFileNameEnumer返回后,FileOpen递减CHRV3vFileSize并继续枚举直到搜索不到文件或者目录。建议做法是, + 在调用FileOpen之前定义一个全局变量为0,当FileOpen回调本程序后,本程序由CHRV3vFdtOffset得到结构FAT_DIR_INFO, + 分析结构中的DIR_Attr以及DIR_Name判断是否为所需文件名或者目录名,记录相关信息,并将全局变量计数增量, + 当FileOpen返回后,判断返回值如果是ERR_MISS_FILE或ERR_FOUND_NAME都视为操作成功,全局变量为搜索到的有效文件数。 + 如果在本回调程序xFileNameEnumer中将CHRV3vFileSize置为1,那么可以通知FileOpen提前结束搜索。以下是回调程序例子 */ + #if 0 + UINT8 i; + UINT16 FileCount; + PX_FAT_DIR_INFO pFileDir; + PUINT8 NameBuf; + pFileDir = (PX_FAT_DIR_INFO)(pDISK_BASE_BUF + CHRV3vFdtOffset); /* 当前FDT的起始地址 */ + FileCount = (UINT16)(0xFFFFFFFF - CHRV3vFileSize); /* 当前文件名的枚举序号,CHRV3vFileSize初值是0xFFFFFFFF,找到文件名后递减 */ + if(FileCount < sizeof(FILE_DATA_BUF) / 12) + { /* 检查缓冲区是否足够存放,假定每个文件名需占用12个字节存放 */ + NameBuf = &FILE_DATA_BUF[FileCount * 12]; /* 计算保存当前文件名的缓冲区地址 */ + for(i = 0; i < 11; i++) + NameBuf[i] = pFileDir->DIR_Name[i]; /* 复制文件名,长度为11个字符,未处理空格 */ + // if ( pFileDir -> DIR_Attr & ATTR_DIRECTORY ) NameBuf[ i ] = 1; /* 判断是目录名 */ + NameBuf[i] = 0; /* 文件名结束符 */ + } + #endif +} +#endif // NO_DEFAULT_FILE_ENUMER + +UINT8 CHRV3LibInit(void) /* 初始化CHRV3程序库,操作成功返回0 */ +{ + if(CHRV3GetVer() < CHRV3_LIB_VER) + return (0xFF); /* 获取当前子程序库的版本号,版本太低则返回错误 */ +#if DISK_BASE_BUF_LEN > 0 + pDISK_BASE_BUF = &RAM_BUFFER.PDF_BUFFER.DISK_BASE_BUF[0]; /* 指向外部RAM的磁盘数据缓冲区 */ +// pDISK_FAT_BUF = &DISK_BASE_BUF[0]; /* 指向外部RAM的磁盘FAT数据缓冲区,可以与pDISK_BASE_BUF合用以节约RAM */ + pDISK_FAT_BUF = &RAM_BUFFER.PDF_BUFFER.DISK_FAT_BUF[0]; /* 指向外部RAM的磁盘FAT数据缓冲区,独立于pDISK_BASE_BUF以提高速度 */ +/* 如果希望提高文件存取速度,那么可以在主程序中调用CHRV3LibInit之后,将pDISK_FAT_BUF重新指向另一个独立分配的与pDISK_BASE_BUF同样大小的缓冲区 */ +#endif + CHRV3DiskStatus = DISK_UNKNOWN; /* 未知状态 */ + CHRV3vSectorSizeB = 9; /* 默认的物理磁盘的扇区是512B */ + CHRV3vSectorSize = 512; // 默认的物理磁盘的扇区是512B,该值是磁盘的扇区大小 + CHRV3vStartLba = 0; /* 默认为自动分析FDD和HDD */ + CHRV3vPacketSize = 64; /* USB存储类设备的最大包长度:64@FS,512@HS/SS,由应用程序初始化,枚举U盘后如果是高速或者超速那么及时更新为512 */ + pTX_DMA_A_REG = (PUINT32)&R16_UH_TX_DMA; /* 指向发送DMA地址寄存器,由应用程序初始化 */ + pRX_DMA_A_REG = (PUINT32)&R16_UH_RX_DMA; /* 指向接收DMA地址寄存器,由应用程序初始化 */ + pTX_LEN_REG = (PUINT16)&R8_UH_TX_LEN; /* 指向发送长度寄存器,由应用程序初始化 */ + pRX_LEN_REG = (PUINT16)&R8_USB_RX_LEN; /* 指向接收长度寄存器,由应用程序初始化 */ + + //CHRV3vRootPort = 0; /* USB主机选择(类似Root-hub根集线器选端口) */ + return (ERR_SUCCESS); +} diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UFI.h b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UFI.h new file mode 100644 index 0000000..899d55a --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UFI.h @@ -0,0 +1,346 @@ +/* 2014.09.09 +***************************************** +** Copyright (C) W.ch 1999-2019 ** +** Web: http://wch.cn ** +***************************************** +** USB-flash File Interface for CHRV3 ** +** KEIL423, gcc 8.20 ** +***************************************** +*/ +/* CHRV3 U盘主机文件系统接口, 支持: FAT12/FAT16/FAT32 */ + +//#include "CHRV3BAS.H" + +#ifndef __CHRV3UFI_H__ +#define __CHRV3UFI_H__ + +#define CHRV3_LIB_VER 0x10 + +//#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节(可以选择为2048甚至4096以支持某些大扇区的U盘),为0则禁止在本文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */ +/* 如果需要复用磁盘数据缓冲区以节约RAM,那么可将DISK_BASE_BUF_LEN定义为0以禁止在本文件中定义缓冲区,而由应用程序在调用CHRV3LibInit之前将与其它程序合用的缓冲区起始地址置入pDISK_BASE_BUF变量 */ + +//#define NO_DEFAULT_ACCESS_SECTOR 1 /* 禁止默认的磁盘扇区读写子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_DISK_CONNECT 1 /* 禁止默认的检查磁盘连接子程序,下面用自行编写的程序代替它 */ +//#define NO_DEFAULT_FILE_ENUMER 1 /* 禁止默认的文件名枚举回调程序,下面用自行编写的程序代替它 */ + +#ifdef __cplusplus +extern "C" { +#endif + +/* ********************************************************************************************************************* */ + +/* FILE: CHRV3UF.H */ + +/* 错误码 */ +#ifndef ERR_SUCCESS +#define ERR_SUCCESS 0x00 /* 操作成功 */ +#endif +#ifndef ERR_DISK_DISCON +#define ERR_CHRV3_ERROR 0x81 /* CHRV3硬件错误,可能需要复位CHRV3 */ +//#define ERR_DISK_DISCON 0x82 /* 磁盘尚未连接,可能磁盘已经断开 */ +#define ERR_STATUS_ERR 0x83 /* 磁盘状态错误,可能正在连接或者断开磁盘 */ +#define ERR_HUB_PORT_FREE 0x84 /* USB-HUB已经连接但是HUB端口尚未连接磁盘,可能磁盘已经断开 */ +#define ERR_MBR_ERROR 0x91 /* 磁盘的主引导记录无效,可能磁盘尚未分区或者尚未格式化 */ +#define ERR_TYPE_ERROR 0x92 /* 磁盘分区类型不支持,只支持FAT12/FAT16/BigDOS/FAT32,需要由磁盘管理工具重新分区 */ +#define ERR_BPB_ERROR 0xA1 /* 磁盘尚未格式化,或者参数错误,需要由WINDOWS采用默认参数重新格式化 */ +#define ERR_TOO_LARGE 0xA2 /* 磁盘非正常格式化并且容量大于4GB,或者容量大于250GB,需要由WINDOWS采用默认参数重新格式化 */ +#define ERR_FAT_ERROR 0xA3 /* 磁盘的文件系统不支持,只支持FAT12/FAT16/FAT32,需要由WINDOWS采用默认参数重新格式化 */ +#define ERR_DISK_FULL 0xB1 /* 磁盘文件太满,剩余空间太少或者已经没有,需要磁盘整理 */ +#define ERR_FDT_OVER 0xB2 /* 目录内文件太多,没有空闲的目录项,FAT12/FAT16根目录下的文件数应该少于500个,需要磁盘整理 */ +#define ERR_MISS_DIR 0xB3 /* 指定路径的某个子目录没有找到,可能是目录名称错误 */ +#define ERR_FILE_CLOSE 0xB4 /* 文件已经关闭,如果需要使用,应该重新打开文件 */ +#define ERR_OPEN_DIR 0x41 /* 指定路径的目录被打开 */ +#define ERR_MISS_FILE 0x42 /* 指定路径的文件没有找到,可能是文件名称错误 */ +#define ERR_FOUND_NAME 0x43 /* 搜索到与通配符相匹配的文件名,文件名及其完整路径在命令缓冲区中,如果需要使用,应该打开该文件 */ +#endif +/* 代码2XH-3XH用于USB主机方式的通讯失败代码,由CHRV3子程序模仿CH375的返回 */ +/* 代码1XH用于USB主机方式的操作状态代码,由CHRV3子程序模仿CH375的返回 */ +#ifndef ERR_USB_CONNECT +#define ERR_USB_CONNECT_LS 0x13 /* 检测到低速USB设备连接事件 */ +#define ERR_USB_CONNECT 0x15 /* 检测到USB设备连接事件,磁盘已经连接 */ +#define ERR_USB_DISCON 0x16 /* 检测到USB设备断开事件,磁盘已经断开 */ +#define ERR_USB_BUF_OVER 0x17 /* USB传输的数据有误或者数据太多缓冲区溢出 */ +#define ERR_USB_DISK_ERR 0x1F /* USB存储器操作失败,在初始化时可能是USB存储器不支持,在读写操作中可能是磁盘损坏或者已经断开 */ +#define ERR_USB_TRANSFER 0x20 /* NAK/STALL等更多错误码在0x20~0x2F */ +#endif + +/* 磁盘及文件状态 */ +#define DISK_UNKNOWN 0x00 /* 尚未初始化,未知状态 */ +#define DISK_DISCONNECT 0x01 /* 磁盘没有连接或者已经断开 */ +#define DISK_CONNECT 0x02 /* 磁盘已经连接,但是尚未初始化或者无法识别该磁盘 */ +#define DISK_USB_ADDR 0x04 /* 磁盘已经分配USB设备地址,但是尚未配置USB和初始化磁盘 */ +#define DISK_MOUNTED 0x05 /* 磁盘已经初始化成功,但是尚未分析文件系统或者文件系统不支持 */ +#define DISK_READY 0x10 /* 已经分析磁盘的文件系统并且能够支持 */ +#define DISK_OPEN_ROOT 0x12 /* 已经打开根目录,扇区模式,只能以扇区为单位读写目录的内容,使用后必须关闭,注意FAT12/FAT16根目录是固定长度 */ +#define DISK_OPEN_DIR 0x13 /* 已经打开子目录,扇区模式,只能以扇区为单位读写目录的内容 */ +#define DISK_OPEN_FILE 0x14 /* 已经打开文件,扇区模式,可以以扇区为单位进行数据读写 */ +#define DISK_OPEN_FILE_B 0x15 /* 已经打开文件,字节模式,可以以字节为单位进行数据读写 */ + +/* FAT类型标志 */ +#ifndef DISK_FAT16 +#define DISK_FS_UNKNOWN 0 /* 未知的文件系统 */ +#define DISK_FAT12 1 /* FAT12文件系统 */ +#define DISK_FAT16 2 /* FAT16文件系统 */ +#define DISK_FAT32 3 /* FAT32文件系统 */ +#endif + +/* FAT数据区中文件目录信息 */ +typedef struct _FAT_DIR_INFO { + UINT8 DIR_Name[11]; /* 00H,文件名,共11字节,不足处填空格 */ + UINT8 DIR_Attr; /* 0BH,文件属性,参考下面的说明 */ + UINT8 DIR_NTRes; /* 0CH */ + UINT8 DIR_CrtTimeTenth; /* 0DH,文件创建的时间,以0.1秒单位计数 */ + UINT16 DIR_CrtTime; /* 0EH,文件创建的时间 */ + UINT16 DIR_CrtDate; /* 10H,文件创建的日期 */ + UINT16 DIR_LstAccDate; /* 12H,最近一次存取操作的日期 */ + UINT16 DIR_FstClusHI; /* 14H */ + UINT16 DIR_WrtTime; /* 16H,文件修改时间,参考宏MAKE_FILE_TIME */ + UINT16 DIR_WrtDate; /* 18H,文件修改日期,参考宏MAKE_FILE_DATA */ + UINT16 DIR_FstClusLO; /* 1AH */ + UINT32 DIR_FileSize; /* 1CH,文件长度 */ +} FAT_DIR_INFO; /* 20H */ + +typedef FAT_DIR_INFO *PX_FAT_DIR_INFO; + +/* 文件属性 */ +#define ATTR_READ_ONLY 0x01 /* 文件为只读属性 */ +#define ATTR_HIDDEN 0x02 /* 文件为隐含属性 */ +#define ATTR_SYSTEM 0x04 /* 文件为系统属性 */ +#define ATTR_VOLUME_ID 0x08 /* 卷标 */ +#define ATTR_DIRECTORY 0x10 /* 子目录 */ +#define ATTR_ARCHIVE 0x20 /* 文件为存档属性 */ +#define ATTR_LONG_NAME ( ATTR_READ_ONLY | ATTR_HIDDEN | ATTR_SYSTEM | ATTR_VOLUME_ID ) +/* 文件属性 UINT8 */ +/* bit0 bit1 bit2 bit3 bit4 bit5 bit6 bit7 */ +/* 只 隐 系 卷 目 存 未定义 */ +/* 读 藏 统 标 录 档 */ +/* 文件时间 UINT16 */ +/* Time = (Hour<<11) + (Minute<<5) + (Second>>1) */ +#define MAKE_FILE_TIME( h, m, s ) ( (h<<11) + (m<<5) + (s>>1) ) /* 生成指定时分秒的文件时间数据 */ +/* 文件日期 UINT16 */ +/* Date = ((Year-1980)<<9) + (Month<<5) + Day */ +#define MAKE_FILE_DATE( y, m, d ) ( ((y-1980)<<9) + (m<<5) + d ) /* 生成指定年月日的文件日期数据 */ + +/* 文件名 */ +#define PATH_WILDCARD_CHAR 0x2A /* 路径名的通配符 '*' */ +#define PATH_SEPAR_CHAR1 0x5C /* 路径名的分隔符 '\' */ +#define PATH_SEPAR_CHAR2 0x2F /* 路径名的分隔符 '/' */ +#ifndef MAX_PATH_LEN +#define MAX_PATH_LEN 64 /* 最大路径长度,含所有斜杠分隔符和小数点间隔符以及路径结束符00H */ +#endif + +/* 外部命令参数 */ +typedef union _CMD_PARAM { + struct { + UINT8 mBuffer[ MAX_PATH_LEN ]; + } Other; + struct { + UINT32 mTotalSector; /* 返回: 当前逻辑盘的总扇区数 */ + UINT32 mFreeSector; /* 返回: 当前逻辑盘的剩余扇区数 */ + UINT32 mSaveValue; + } Query; /* CMD_DiskQuery, 查询磁盘信息 */ + struct { + UINT8 mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILENAME.EXT",00H */ + } Open; /* CMD_FileOpen, 打开文件 */ +// struct { +// UINT8 mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名(含通配符*)...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILE*",00H */ +// } Open; /* CMD_FileOpen, 枚举文件, CHRV3vFileSize最高位为1则各调用xFileNameEnumer,为0则返回指定序号的文件名 */ + struct { + UINT8 mUpdateLen; /* 输入参数: 是否允许更新长度: 0禁止,1允许 */ + } Close; /* CMD_FileClose, 关闭当前文件 */ + struct { + UINT8 mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILENAME.EXT",00H */ + } Create; /* CMD_FileCreate, 新建文件并打开,如果文件已经存在则先删除后再新建 */ + struct { + UINT8 mPathName[ MAX_PATH_LEN ]; /* 输入参数: 路径: [盘符,冒号,斜杠,目录名或者文件名及扩展名...,结束符00H], 其中盘符和冒号可以省略, 例如"C:\DIR1.EXT\DIR2\FILENAME.EXT",00H */ + } Erase; /* CMD_FileErase, 删除文件并关闭 */ + struct { + UINT32 mFileSize; /* 输入参数: 新的文件长度,为0FFFFFFFFH则不修改, 返回: 原长度 */ + UINT16 mFileDate; /* 输入参数: 新的文件日期,为0FFFFH则不修改, 返回: 原日期 */ + UINT16 mFileTime; /* 输入参数: 新的文件时间,为0FFFFH则不修改, 返回: 原时间 */ + UINT8 mFileAttr; /* 输入参数: 新的文件属性,为0FFH则不修改, 返回: 原属性 */ + } Modify; /* CMD_FileQuery, 查询当前文件的信息; CMD_FileModify, 查询或者修改当前文件的信息 */ + struct { + UINT32 mSaveCurrClus; + UINT32 mSaveLastClus; + } Alloc; /* CMD_FileAlloc, 根据文件长度调整为文件分配的磁盘空间 */ + struct { + UINT32 mSectorOffset; /* 输入参数: 扇区偏移,0则移动到文件头,0FFFFFFFFH则移动到文件尾, 返回: 当前文件指针对应的绝对线性扇区号, 0FFFFFFFFH则已到文件尾 */ + UINT32 mLastOffset; + } Locate; /* CMD_FileLocate, 移动当前文件指针 */ + struct { + UINT8 mSectorCount; /* 输入参数: 读取扇区数, 返回: 实际读取扇区数 */ + UINT8 mActCnt; + UINT8 mLbaCount; + UINT8 mRemainCnt; + PUINT8 mDataBuffer; /* 输入参数: 缓冲区起始地址, 返回: 缓冲区当前地址 */ + UINT32 mLbaStart; + } Read; /* CMD_FileRead, 从当前文件读取数据 */ + struct { + UINT8 mSectorCount; /* 输入参数: 写入扇区数, 返回: 实际写入扇区数 */ + UINT8 mActCnt; + UINT8 mLbaCount; + UINT8 mAllocCnt; + PUINT8 mDataBuffer; /* 输入参数: 缓冲区起始地址, 返回: 缓冲区当前地址 */ + UINT32 mLbaStart; + UINT32 mSaveValue; + } Write; /* CMD_FileWrite, 向当前文件写入数据 */ + struct { + UINT32 mDiskSizeSec; /* 返回: 整个物理磁盘的总扇区数, 仅首次调用时返回 */ + } DiskReady; /* CMD_DiskReady, 查询磁盘就绪 */ + struct { + UINT32 mByteOffset; /* 输入参数: 以字节为单位的偏移量, 以字节为单位的文件指针, 返回: 当前文件指针对应的绝对线性扇区号, 0FFFFFFFFH则已到文件尾 */ + UINT32 mLastOffset; + } ByteLocate; /* CMD_ByteLocate, 以字节为单位移动当前文件指针 */ + struct { + UINT16 mByteCount; /* 输入参数: 准备读取的字节数, 返回: 实际读出的字节数 */ + PUINT8 mByteBuffer; /* 输入参数: 指向存放读出数据块的缓冲区 */ + UINT16 mActCnt; + } ByteRead; /* CMD_ByteRead, 以字节为单位从当前文件读取数据块 */ + struct { + UINT16 mByteCount; /* 输入参数: 准备写入的字节数, 返回: 实际写入的字节数 */ + PUINT8 mByteBuffer; /* 输入参数: 指向存放读出数据块的缓冲区 */ + UINT16 mActCnt; + } ByteWrite; /* CMD_ByteWrite, 以字节为单位向当前文件写入数据块 */ + struct { + UINT8 mSaveVariable; /* 输入参数: 为0则恢复单个U盘的变量,为0x80则恢复多个U盘的变量,其它值则备份/保存变量 */ + UINT8 mReserved[3]; + PUINT8 mBuffer; /* 输入参数: 指向子程序库的变量的备份缓冲区,长度不小于80个字节 */ + } SaveVariable; /* CMD_SaveVariable, 备份/保存/恢复子程序库的变量 */ +} CMD_PARAM; + +typedef CMD_PARAM CMD_PARAM_I; +//typedef CMD_PARAM *P_CMD_PARAM; + +/* SCSI命令码 */ +#ifndef SPC_CMD_INQUIRY +#define SPC_CMD_INQUIRY 0x12 +#define SPC_CMD_READ_CAPACITY 0x25 +#define SPC_CMD_READ10 0x28 +#define SPC_CMD_WRITE10 0x2A +#define SPC_CMD_TEST_READY 0x00 +#define SPC_CMD_REQUEST_SENSE 0x03 +#define SPC_CMD_MODESENSE6 0x1A +#define SPC_CMD_MODESENSE10 0x5A +#define SPC_CMD_START_STOP 0x1B +#endif + +/* FILE: CHRV3UFI.C */ + +#define EN_DISK_WRITE 1 + +#ifndef DISK_BASE_BUF_LEN +#define DISK_BASE_BUF_LEN 512 /* 默认的磁盘数据缓冲区大小为512字节,建议选择为2048甚至4096以支持某些大扇区的U盘,为0则禁止在.H文件中定义缓冲区并由应用程序在pDISK_BASE_BUF中指定 */ +#endif + +/* 子程序库中提供的变量 */ +extern UINT8V CHRV3IntStatus; /* CHRV3操作的中断状态 */ +extern UINT8V CHRV3DiskStatus; /* 磁盘及文件状态 */ +extern UINT8 CHRV3vDiskFat; /* 逻辑盘的FAT标志:1=FAT12,2=FAT16,3=FAT32 */ +extern UINT8 CHRV3vSecPerClus; /* 逻辑盘的每簇扇区数 */ +extern UINT8 CHRV3vSectorSizeB; /* log2(CHRV3vSectorSize) */ +extern UINT32 CHRV3vStartLba; /* 逻辑盘的起始绝对扇区号LBA */ +extern UINT32 CHRV3vDiskRoot; /* 对于FAT16盘为根目录占用扇区数,对于FAT32盘为根目录起始簇号 */ +extern UINT32 CHRV3vDataStart; /* 逻辑盘的数据区域的起始LBA */ +extern UINT32 CHRV3vStartCluster; /* 当前文件或者目录的起始簇号 */ +extern UINT32 CHRV3vFileSize; /* 当前文件的长度 */ +extern UINT32 CHRV3vCurrentOffset; /* 当前文件指针,当前读写位置的字节偏移 */ +extern UINT32 CHRV3vFdtLba; /* 当前FDT所在的LBA地址 */ +extern UINT32 CHRV3vLbaCurrent; /* 当前读写的磁盘起始LBA地址 */ +extern UINT16 CHRV3vFdtOffset; /* 当前FDT在扇区内的偏移地址 */ +extern UINT16 CHRV3vSectorSize; /* 磁盘的扇区大小 */ +extern UINT8 CHRV3vCurrentLun; /* 磁盘当前操作逻辑单元号 */ +extern BOOL CHRV3vSubClassIs6; /* USB存储类设备的子类为6,0则非6 */ +extern PUINT8 pDISK_BASE_BUF; /* 指向外部RAM的磁盘数据缓冲区,缓冲区长度不小于CHRV3vSectorSize,由应用程序初始化 */ +extern PUINT8 pDISK_FAT_BUF; /* 指向外部RAM的磁盘FAT数据缓冲区,缓冲区长度不小于CHRV3vSectorSize,由应用程序初始化 */ +extern UINT16 CHRV3vPacketSize; /* USB存储类设备的最大包长度:64@FS,512@HS/SS,由应用程序初始化 */ +extern PUINT32 pTX_DMA_A_REG; /* 指向发送DMA地址寄存器,由应用程序初始化 */ +extern PUINT32 pRX_DMA_A_REG; /* 指向接收DMA地址寄存器,由应用程序初始化 */ +extern PUINT16 pTX_LEN_REG; /* 指向发送长度寄存器,由应用程序初始化 */ +extern PUINT16 pRX_LEN_REG; /* 指向接收长度寄存器,由应用程序初始化 */ + +extern CMD_PARAM_I mCmdParam; /* 命令参数 */ + +extern UINT8 RxBuffer[ MAX_PACKET_SIZE ]; // IN, must even address +extern UINT8 TxBuffer[ MAX_PACKET_SIZE ]; // OUT, must even address + +//#define PXUDISK_BOC_CBW PUDISK_BOC_CBW +//#define PXUDISK_BOC_CSW PUDISK_BOC_CSW + +#ifndef pSetupReq +#define pSetupReq ((PUSB_SETUP_REQ)TxBuffer) +#endif +#ifndef pCBW +#define pCBW ((PXUDISK_BOC_CBW)TxBuffer) +#define pCSW ((PXUDISK_BOC_CSW)RxBuffer) +#endif +#ifndef pBOC_buf +#define pBOC_buf (TxBuffer+((USB_BO_CBW_SIZE+4)&0xFE)) +#endif + +#if DISK_BASE_BUF_LEN > 0 +//extern UINT8 DISK_BASE_BUF[ DISK_BASE_BUF_LEN ]; /* 外部RAM的磁盘数据缓冲区,缓冲区长度为一个扇区的长度 */ +#endif +extern UINT8 CHRV3ReadSector( UINT8 SectCount, PUINT8 DataBuf ); /* 从磁盘读取多个扇区的数据到缓冲区中 */ +#ifdef EN_DISK_WRITE +extern UINT8 CHRV3WriteSector( UINT8 SectCount, PUINT8 DataBuf ); /* 将缓冲区中的多个扇区的数据块写入磁盘 */ +#endif + +extern UINT8 CHRV3DiskConnect( void ); /* 检查磁盘是否连接并更新磁盘状态 */ +extern void xFileNameEnumer( void ); /* 调用外部定义的子程序,文件名枚举回调子程序 */ + +extern UINT8 CHRV3LibInit( void ); /* 初始化CHRV3程序库,操作成功返回0 */ + +/* 子程序库中提供的子程序 */ +/* 下述子程序中, 文件操作子程序CHRV3File*和磁盘查询子程序CHRV3DiskQuery都可能会用到磁盘数据缓冲区pDISK_BASE_BUF, + 并且有可能在pDISK_BASE_BUF中保存了磁盘信息, 所以必须保证pDISK_BASE_BUF不被用于其它用途, + 如果RAM较少, 要将pDISK_BASE_BUF临时用于其它用途, 那么在临时用完后必须调用CHRV3DirtyBuffer清除磁盘缓冲区 */ +extern UINT8 CHRV3GetVer( void ); /* 获取当前子程序库的版本号 */ +extern void CHRV3DirtyBuffer( void ); /* 清除磁盘缓冲区 */ +extern UINT8 CHRV3BulkOnlyCmd( PUINT8 DataBuf ); /* 执行基于BulkOnly协议的命令 */ +extern UINT8 CHRV3DiskReady( void ); /* 查询磁盘是否准备好 */ +extern UINT8 CHRV3AnalyzeError( UINT8 iMode ); /* USB操作失败分析CHRV3IntStatus返回错误状态 */ +extern UINT8 CHRV3FileOpen( void ); /* 打开文件或者枚举文件 */ +extern UINT8 CHRV3FileClose( void ); /* 关闭当前文件 */ +#ifdef EN_DISK_WRITE +extern UINT8 CHRV3FileErase( void ); /* 删除文件并关闭 */ +extern UINT8 CHRV3FileCreate( void ); /* 新建文件并打开,如果文件已经存在则先删除后再新建 */ +extern UINT8 CHRV3FileAlloc( void ); /* 根据文件长度调整为文件分配的磁盘空间 */ +#endif +extern UINT8 CHRV3FileModify( void ); /* 查询或者修改当前文件的信息 */ +extern UINT8 CHRV3FileQuery( void ); /* 查询当前文件的信息 */ +extern UINT8 CHRV3FileLocate( void ); /* 移动当前文件指针 */ +extern UINT8 CHRV3FileRead( void ); /* 从当前文件读取数据到指定缓冲区 */ +#ifdef EN_DISK_WRITE +extern UINT8 CHRV3FileWrite( void ); /* 向当前文件写入指定缓冲区的数据 */ +#endif +extern UINT8 CHRV3ByteLocate( void ); /* 以字节为单位移动当前文件指针 */ +extern UINT8 CHRV3ByteRead( void ); /* 以字节为单位从当前位置读取数据块 */ +#ifdef EN_DISK_WRITE +extern UINT8 CHRV3ByteWrite( void ); /* 以字节为单位向当前位置写入数据块 */ +#endif +extern UINT8 CHRV3DiskQuery( void ); /* 查询磁盘信息 */ +extern void CHRV3SaveVariable( void ); /* 备份/保存/恢复子程序库的变量,用于子程序库在多个芯片或者U盘之间进行切换 */ + +extern void mDelayuS( UINT16 n ); // 以uS为单位延时 +extern void mDelaymS( UINT16 n ); // 以mS为单位延时 +extern UINT8 USBHostTransact( UINT8 endp_pid, UINT8 tog, UINT32 timeout ); // CHRV3传输事务,输入目的端点地址/PID令牌,同步标志,NAK重试时间,返回0成功,超时/出错重试 +extern UINT8 HostCtrlTransfer( PUINT8 DataBuf, PUINT8 RetLen ); // 执行控制传输,8字节请求码在pSetupReq中,DataBuf为可选的收发缓冲区,实际收发长度返回在ReqLen指向的变量中 +//extern void CopySetupReqPkg( PCCHAR pReqPkt ); // 复制控制传输的请求包 +//extern UINT8 CtrlGetDeviceDescrTB( void ); // 获取设备描述符,返回在TxBuffer中 +extern UINT8 CtrlGetConfigDescrTB( void ); // 获取配置描述符,返回在TxBuffer中 +//extern UINT8 CtrlSetUsbAddress( UINT8 addr ); // 设置USB设备地址 +extern UINT8 CtrlSetUsbConfig( UINT8 cfg ); // 设置USB设备配置 +extern UINT8 CtrlClearEndpStall( UINT8 endp ); // 清除端点STALL +#ifndef FOR_ROOT_UDISK_ONLY +//extern UINT8 CtrlGetHubDescr( void ); // 获取HUB描述符,返回在TxBuffer中 +extern UINT8 HubGetPortStatus( UINT8 HubPortIndex ); // 查询HUB端口状态,返回在TxBuffer中 +//extern UINT8 HubSetPortFeature( UINT8 HubPortIndex, UINT8 FeatureSelt ); // 设置HUB端口特性 +extern UINT8 HubClearPortFeature( UINT8 HubPortIndex, UINT8 FeatureSelt ); // 清除HUB端口特性 +#endif + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UF_README.TXT b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UF_README.TXT new file mode 100644 index 0000000..9428659 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/CHRV3UF_README.TXT @@ -0,0 +1,9 @@ +有关WCH-RISC-V3处理器的U盘文件级子程序库的接口说明以及例子程序 +请参考CHxxx评估板资料和相关PDF文档 + +***************************************************************************************** + +CHRV3UFI V1.0 最新更新 2020.05 + 支持FS全速、HS高速、SS超速USB主机,支持内置root-hub或外置hub + +***************************************************************************************** diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/libRV3UFI.a b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/libRV3UFI.a new file mode 100644 index 0000000000000000000000000000000000000000..07229b2f8cae3e4a3c84d6312e1684e2bcb92070 GIT binary patch literal 88222 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 C31bof literal 0 HcmV?d00001 diff --git a/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/library.json b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/library.json new file mode 100644 index 0000000..f18eba4 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/lib/USB_LIB/library.json @@ -0,0 +1,11 @@ +{ + "name": "USB_LIB", + "version": "1.0.0", + "build": { + "includeDir": ".", + "flags": [ + "-L.", + "-lRV3UFI" + ] + } +} \ No newline at end of file diff --git a/examples/usb-pdf-logger-none-os-ch592/platformio.ini b/examples/usb-pdf-logger-none-os-ch592/platformio.ini new file mode 100644 index 0000000..f540cf1 --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/platformio.ini @@ -0,0 +1,18 @@ +; PlatformIO Project Configuration File +; +; Build options: build flags, source filter +; Upload options: custom upload port, speed and extra flags +; Library options: dependencies, extra library storages +; Advanced options: extra scripting +; +; Please visit documentation for the other options and examples +; https://docs.platformio.org/page/projectconf.html + +[env:genericCH592F] +platform = ch32v +board = genericCH592F +framework = noneos-sdk +; make include folder available to all libraries +build_flags = -I include +; So that dependencies correctly find their sub-dependencies +lib_ldf_mode = deep+ \ No newline at end of file diff --git a/examples/usb-pdf-logger-none-os-ch592/src/peripheral_main.c b/examples/usb-pdf-logger-none-os-ch592/src/peripheral_main.c new file mode 100644 index 0000000..14e09ae --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/src/peripheral_main.c @@ -0,0 +1,194 @@ +/********************************** (C) COPYRIGHT ******************************* + * File Name : main.c + * Author : WCH + * Version : V1.1 + * Date : 2020/08/06 + * Description : 外设从机应用主函数及任务系统初始化 + ********************************************************************************* + * Copyright (c) 2021 Nanjing Qinheng Microelectronics Co., Ltd. + * Attention: This software (modified or not) and binary are used for + * microcontroller manufactured by Nanjing Qinheng Microelectronics. + *******************************************************************************/ + +/******************************************************************************/ +/* 头文件包含 */ +#include "CH59x_common.h" +#include "peripheral.h" +#include "flash_info.h" +#include "usb_connect.h" +#include "internal_flash.h" +#include "spi_flash.h" +#include "sw_udisk.h" +#include "CHRV3UFI.h" +#include "pdfTempe.h" +#include "pdfFile.h" + +//#define CONFIG_MAIN_DEBUG +#ifdef CONFIG_MAIN_DEBUG +#define LOG_INFO(...) PRINT(__VA_ARGS__) +#else +#define LOG_INFO(...) +#endif + +#define IMAGE_A_START_ADD 0x14000 +#define jumpApp ((void (*)(void))((int *)IMAGE_A_START_ADD)) + +/* Status of device */ +#define DEF_DEVICE_STATUS_FACTORY 0x00 +#define DEF_DEVICE_STATUS_NORMAL 0x01 +#define DEF_DEVICE_STATUS_USB 0x02 + +#define IFLASH_TEMP_START_ADDR (268*1024) +#define IFLASH_HUMI_START_ADDR (358*1024) +/********************************************************************* + * GLOBAL TYPEDEFS + */ + +//__attribute__((aligned(4))) uint32_t MEM_BUF[BLE_MEMHEAP_SIZE / 4]; +__attribute__((aligned(4))) RAM_BUFFER_t RAM_BUFFER; + +#if(defined(BLE_MAC)) && (BLE_MAC == TRUE) +const uint8_t MacAddr[6] = {0x84, 0xC2, 0xE4, 0x03, 0x02, 0x02}; +#endif + +/* Status of device */ +uint8_t DeviceStatus; + +/********************************************************************* + * @fn Main_Circulation + * + * @brief 主循环 + * + * @return none + */ + +float AHT20_TemperatureValue; +float AHT20_HumidityValue; + +/********************************************************************* + * @fn main + * + * @brief 主函数 + * + * @return none + */ +int main(void) +{ + SetSysClock(CLK_SOURCE_PLL_60MHz); + GPIOA_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU); + GPIOB_ModeCfg(GPIO_Pin_All, GPIO_ModeIN_PU); + +#ifdef CONFIG_MAIN_DEBUG + GPIOA_SetBits(bTXD1); + GPIOA_ModeCfg(bTXD1, GPIO_ModeOut_PP_5mA); + UART1_DefInit(); +#endif + LOG_INFO("%s\r\n", __TIME__); + +#if (STORAGE_MEDIUM == MEDIUM_SPI_FLASH) + LOG_INFO( "USBD UDisk Demo\r\nStorage Medium: SPI FLASH \r\n" ); + /* SPI flash init */ + FLASH_Port_Init( ); + /* FLASH ID check */ + FLASH_IC_Check( ); +#elif (STORAGE_MEDIUM == MEDIUM_INTERAL_FLASH) + LOG_INFO( "USBD UDisk Demo\r\nStorage Medium: INTERNAL FLASH \r\n" ); + Flash_Sector_Count = IFLASH_UDISK_SIZE / DEF_UDISK_SECTOR_SIZE; + Flash_Sector_Size = DEF_UDISK_SECTOR_SIZE; + LOG_INFO("Flash_Sector_Count:%d | Flash_Sector_Size:%d\r\n",Flash_Sector_Count,Flash_Sector_Size); +#endif + + /* Read device information */ + HAL_ReadDeviceInfo(); + + LOG_INFO("Bond Info:"); + for (uint8_t i = 0; i < DEVICEINFO_LEN; ++i) + { + LOG_INFO(" %02x", ((uint8_t * )(&DeviceInfo))[i]); + } + LOG_INFO("\n"); + LOG_INFO("NO.%d | StatusFlag:%d | MeasureNum:%d\n", DeviceInfo.InfoNum, DeviceInfo.StatusFlag, DeviceInfo.MeasureNum); + LOG_INFO("MeasureInterval:%d | Unit:%d\n", DeviceInfo.PdfParam.MeasureInterval, DeviceInfo.PdfParam.TempUnit); + LOG_INFO("MaxTempAlarm:%f | MinTempAlarm:%f\n", DeviceInfo.PdfParam.MaxTempAlarm, DeviceInfo.PdfParam.MinTempAlarm); + LOG_INFO("MaxHumiAlarm:%f | MinHumiAlarm:%f\n", DeviceInfo.PdfParam.MaxHumiAlarm, DeviceInfo.PdfParam.MinHumiAlarm); + +// ++DeviceInfo.MeasureNum; +// ++DeviceInfo.MeasureNum; +// ++DeviceInfo.MeasureNum; +// HAL_SaveDeviceInfo(); +// HAL_ReadDeviceInfo(); +// LOG_INFO("NO.%d | MeasureNum:%d\n", DeviceInfo.InfoNum, DeviceInfo.MeasureNum); +// DeviceInfo.MeasureNum=0; +// HAL_SaveDeviceInfo(); +// +// for(uint8_t i=0; i<100; ++i) +// { +// AHT20_TemperatureValue = i*1.0 - 25.0; +// AHT20_HumidityValue = i*1.0; +// FLASH_ROM_WRITE(IFLASH_TEMP_START_ADDR+4*DeviceInfo.MeasureNum, &AHT20_TemperatureValue, 4); +// FLASH_ROM_WRITE(IFLASH_HUMI_START_ADDR+4*DeviceInfo.MeasureNum, &AHT20_HumidityValue, 4); +// ++DeviceInfo.MeasureNum; +// HAL_SaveDeviceInfo(); +// } +// +// LOG_INFO("NO.%d | MeasureNum:%d\n", DeviceInfo.InfoNum, DeviceInfo.MeasureNum); +// for(uint8_t i=0; i<100; ++i) +// { +// FLASH_ROM_READ(IFLASH_TEMP_START_ADDR+4*i, &AHT20_TemperatureValue, 4); +// FLASH_ROM_READ(IFLASH_HUMI_START_ADDR+4*i, &AHT20_HumidityValue, 4); +// PRINT("%d: %f\n", i, AHT20_TemperatureValue); +// PRINT("%d: %f\n", i, AHT20_HumidityValue); +// } + + /* Check if the USB is connected */ + GPIOA_ModeCfg(USB_CHECK_BV, GPIO_ModeIN_PD); + if(USB_CONNECT_CHECK() != 0) + { + DeviceInfo.StatusFlag = DEF_DEVICE_STATUS_FACTORY; + HAL_SaveDeviceInfo(); +// DeviceStatus = DEF_DEVICE_STATUS_USB; + +#if FUN_UDISK + /* Enable Udisk */ + Udisk_Capability = Flash_Sector_Count; + Udisk_Status |= DEF_UDISK_EN_FLAG; +#endif + +#if FUN_FILE_CREATE + { + uint8_t state; + + /* USB Libs Initialization */ + LOG_INFO( "UDisk library Initialization. \r\n" ); + state = CHRV3LibInit( ); //Initialize the file system library, the sector size set by DEMO is 512B + if(state == ERR_SUCCESS) + { + LOG_INFO( "LIB Init SUCCESS\r\n"); + } + CHRV3DiskStatus = DISK_MOUNTED; + } +#endif + + pdf_create( "TEMP.PDF" ); //Create pdf file, the file name can be changed + + while(1) + { + if(USB_CONNECT_CHECK() == 0) + { + DelayMs(10); + SYS_ResetExecute(); + } + } + } + else + { + LOG_INFO("jump\n"); + DelayMs(10); + jumpApp(); + } + + +} + + +/******************************** endfile @ main ******************************/ diff --git a/examples/usb-pdf-logger-none-os-ch592/test/README b/examples/usb-pdf-logger-none-os-ch592/test/README new file mode 100644 index 0000000..9b1e87b --- /dev/null +++ b/examples/usb-pdf-logger-none-os-ch592/test/README @@ -0,0 +1,11 @@ + +This directory is intended for PlatformIO Test Runner and project tests. + +Unit Testing is a software testing method by which individual units of +source code, sets of one or more MCU program modules together with associated +control data, usage procedures, and operating procedures, are tested to +determine whether they are fit for use. Unit testing finds problems early +in the development cycle. + +More information about PlatformIO Unit Testing: +- https://docs.platformio.org/en/latest/advanced/unit-testing/index.html