mirror of
https://github.com/Dejvino/lilybook.git
synced 2024-11-14 04:17:28 +00:00
Import of adapted loboris/ESP32_ePaper_example repository
This commit is contained in:
parent
5034fe11c6
commit
a286a6a791
33
.gitignore
vendored
33
.gitignore
vendored
@ -9,3 +9,36 @@ install_manifest.txt
|
||||
compile_commands.json
|
||||
CTestTestfile.cmake
|
||||
_deps
|
||||
.config
|
||||
*.o
|
||||
*.pyc
|
||||
*.a
|
||||
*.d
|
||||
|
||||
# gtags
|
||||
GTAGS
|
||||
GRTAGS
|
||||
GPATH
|
||||
|
||||
# emacs
|
||||
.dir-locals.el
|
||||
|
||||
# emacs temp file suffixes
|
||||
*~
|
||||
.#*
|
||||
\#*#
|
||||
|
||||
sdkconfig
|
||||
sdkconfig.old
|
||||
sdkconfig.lobo
|
||||
.cproject
|
||||
.project
|
||||
.settings
|
||||
BUILD
|
||||
build/
|
||||
temp/
|
||||
local/
|
||||
*.dis
|
||||
*.elf
|
||||
*.map
|
||||
**/.DS_Store
|
||||
|
179
README.md
179
README.md
@ -1,2 +1,177 @@
|
||||
# lilybook
|
||||
Little ePaper reader for ESP32
|
||||
|
||||
### ePaper library for ESP32
|
||||
|
||||
---
|
||||
|
||||
|
||||
#### Features
|
||||
|
||||
* Support for **GDEH029A1** / **SSD1608** based ePaper modules in 4-wire SPI mode. Support for other controllers will be added later
|
||||
* **emulated** 4-bit gray scale mode
|
||||
* **SPI displays oriented SPI driver library** based on *spi-master* driver
|
||||
* Combined **DMA SPI** transfer mode and **direct SPI** for maximal speed
|
||||
* **4-bit Grayscale mode** or **1-bit b/w mode** can be selected during runtime
|
||||
* SPI speeds up to **20 MHz** are tested and works without problems
|
||||
* **Demo application** included which demonstrates most of the library features
|
||||
|
||||
|
||||
* **Graphics drawing functions**:
|
||||
* **EPD_drawPixel** Draw pixel at given x,y coordinates
|
||||
* **EPD_drawLine** Draw line between two points
|
||||
* **EPD_drawFastVLine**, **EPD_drawFastHLine** Draw vertical or horizontal line of given lenght
|
||||
* **EPD_drawLineByAngle** Draw line on screen from (x,y) point at given angle
|
||||
* **EPD_drawRect**, **EPD_fillRect** Draw rectangle on screen or fill given rectangular screen region with color
|
||||
* **EPD_drawRoundRect**, **EPD_fillRoundRect** Draw rectangle on screen or fill given rectangular screen region with color with rounded corners
|
||||
* **EPD_drawCircle**, **EPD_fillCircle** Draw or fill circle on screen
|
||||
* **EPD_drawEllipse**, **EPD_fillEllipse** Draw or fill ellipse on screen
|
||||
* **EPD_drawTriangel**, **EPD_fillTriangle** Draw or fill triangle on screen
|
||||
* **EPD_drawArc** Draw circle arc on screen, from ~ to given angles, with given thickness. Can be outlined with different color
|
||||
* **EPD_drawPolygon** Draw poligon on screen with given number of sides (3~60). Can be outlined with different color and rotated by given angle.
|
||||
* **Fonts**:
|
||||
* **fixed** width and proportional fonts are supported; 8 fonts embeded
|
||||
* unlimited number of **fonts from file**
|
||||
* **7-segment vector font** with variable width/height is included (only numbers and few characters)
|
||||
* Proportional fonts can be used in fixed width mode.
|
||||
* Related functions:
|
||||
* **EPD_setFont** Set current font from one of embeded fonts or font file
|
||||
* **EPD_getfontsize** Returns current font height & width in pixels.
|
||||
* **EPD_getfontheight** Returns current font height in pixels.
|
||||
* **set_7seg_font_atrib** Set atributes for 7 segment vector font
|
||||
* **getFontCharacters** Get all font's characters to buffer
|
||||
* **String write function**:
|
||||
* **EPD_print** Write text to display.
|
||||
* Strings can be printed at **any angle**. Rotation of the displayed text depends on *font_ratate* variable (0~360)
|
||||
* if *font_transparent* variable is set to 1, no background pixels will be printed
|
||||
* If the text does not fit the screen/window width it will be clipped ( if *text_wrap=0* ), or continued on next line ( if *text_wrap=1* )
|
||||
* Two special characters are allowed in strings: *\r* CR (0x0D), clears the display to EOL, *\n* LF (ox0A), continues to the new line, x=0
|
||||
* Special values can be entered for X position:
|
||||
* *CENTER* centers the text
|
||||
* *RIGHT* right justifies the text horizontaly
|
||||
* *LASTX* continues from last X position; offset can be used: *LASTX+n*
|
||||
* Special values can be entered for Y:
|
||||
* *CENTER* centers the text verticaly
|
||||
* *BOTTOM* bottom justifies the text
|
||||
* *LASTY* continues from last Y position; offset can be used: *LASTY+n*
|
||||
* **EPD_getStringWidth** Returns the string width in pixels based on current font characteristics. Useful for positioning strings on the screen.
|
||||
* **EPD_clearStringRect** Fills the rectangle occupied by string with current background color
|
||||
* **Images**:
|
||||
* **EPD_jpg_image** Decodes and displays JPG images
|
||||
* Limits:
|
||||
* Baseline only. Progressive and Lossless JPEG format are not supported.
|
||||
* Image size: Up to 65520 x 65520 pixels
|
||||
* Color space: YCbCr three components only. Gray scale image is not supported.
|
||||
* Sampling factor: 4:4:4, 4:2:2 or 4:2:0.
|
||||
* Can display the image **from file** or **memory buffer**
|
||||
* Image can be **scaled** by factor 0 ~ 3 (1/1, 1/2, 1/4 or 1/8)
|
||||
* Image is displayed from X,Y position on screen/window:
|
||||
* X: image left position; constants CENTER & RIGHT can be used; *negative* value is accepted
|
||||
* Y: image top position; constants CENTER & BOTTOM can be used; *negative* value is accepted
|
||||
* Image is converted to **4-bit Gray Scale mode**
|
||||
* **Other display functions**:
|
||||
* **EPD_fillScreen** Fill the whole screen with black, white or gray scale
|
||||
* **compile_font_file** Function which compiles font c source file to font file which can be used in *EPD_setFont()* function to select external font. Created file have the same name as source file and extension *.fnt*
|
||||
|
||||
|
||||
* **Global wariables**
|
||||
* **orientation** current screen orientation
|
||||
* **font_ratate** current font rotate angle (0~395)
|
||||
* **font_transparent** if not 0 draw fonts transparent
|
||||
* **font_forceFixed** if not zero force drawing proportional fonts with fixed width
|
||||
* **text_wrap** if not 0 wrap long text to the new line, else clip
|
||||
* **_fg** current foreground color for fonts
|
||||
* **_bg** current background for non transparent fonts
|
||||
* **_angleOffset** angle offset for arc, polygon and line by angle functions
|
||||
* **image_debug** print debug messages during image decode if set to 1
|
||||
* **cfont** Currently used font structure
|
||||
* **EPD_X** X position of the next character after EPD_print() function
|
||||
* **EPD_Y** Y position of the next character after EPD_print() function
|
||||
* **_gs** use 4-bit Gray scale if set to 1
|
||||
* **_width** screen width (larger dimension) in pixels
|
||||
* **_height** screen height (smaller dimension) in pixels
|
||||
|
||||
---
|
||||
|
||||
Full functions **syntax and descriptions** can be found in *EPD.h* and *EPDspi.h* files.
|
||||
|
||||
Full **demo application**, well documented, is included, please **analyze it** to learn how to use the library functions.
|
||||
|
||||
---
|
||||
|
||||
#### Connecting the display
|
||||
|
||||
To run the demo, attach display module to ESP32. Default pins used are:
|
||||
* mosi: 23
|
||||
* sck: 18
|
||||
* CS: 5 (display CS)
|
||||
* DC: 26 (display DC)
|
||||
* RST: 27 (display RESET)
|
||||
* BUSY: 32 (display BUSY output)
|
||||
|
||||
The display can be powered from 3.3V or from **GPIO pin**. See *EPDspi.h* for configuration options.
|
||||
|
||||
**If you want to use different pins, change them in** *EPDspi.h*
|
||||
|
||||
Using *make menuconfig* **select tick rate 1000** ( → Component config → FreeRTOS → Tick rate (Hz) ) to get more accurate timings
|
||||
|
||||
---
|
||||
|
||||
#### How to build
|
||||
|
||||
Configure your esp32 build environment as for **esp-idf examples**
|
||||
|
||||
Clone the repository
|
||||
|
||||
`git clone https://github.com/loboris/ESP32_ePaper_example.git`
|
||||
|
||||
Execute menuconfig and configure your Serial flash config and other settings. Included *sdkconfig.defaults* sets some defaults to be used.
|
||||
|
||||
Navigate to **ePaper Display DEMO Configuration** and set **SPIFFS** options.
|
||||
|
||||
Select if you want to use **wifi** (recommended) to get the time from **NTP** server and set your WiFi SSID and password.
|
||||
|
||||
`make menuconfig`
|
||||
|
||||
Make and flash the example.
|
||||
|
||||
`make all && make flash`
|
||||
|
||||
---
|
||||
|
||||
#### Prepare **SPIFFS** image
|
||||
|
||||
*The demo uses some image and font files and it is necessary to flash the spiffs image*
|
||||
|
||||
**To flash already prepared image** *components/spiffs_image/spiffs_image.img* execute:
|
||||
|
||||
`make copyfs`
|
||||
|
||||
---
|
||||
|
||||
You can also prepare different SFPIFFS **image** and flash it to ESP32.
|
||||
|
||||
Files to be included on spiffs are already in **components/spiffs_image/image/** directory. You can add or remove the files you want to include.
|
||||
|
||||
Then execute:
|
||||
|
||||
`make makefs`
|
||||
|
||||
to create **spiffs image** in *build* directory **without flashing** to ESP32
|
||||
|
||||
Or execute:
|
||||
|
||||
`make flashfs`
|
||||
|
||||
to create **spiffs image** in *build* directory and **flash** it to ESP32
|
||||
|
||||
---
|
||||
|
||||
Tested on Waveshare 2.9" ePaper module connected to SparkFun ESP32 Thing board.
|
||||
![Tested on](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/2.9inch-e-paper-module-4.jpg)
|
||||
|
||||
---
|
||||
|
||||
![Fonts](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-fonts.jpg)
|
||||
![Rotated](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-Rotated.jpg)
|
||||
![7-segFont](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-7sef_font.jpg)
|
||||
![Grayscale](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD_Grayscale.jpg)
|
||||
![No power](https://raw.githubusercontent.com/loboris/ESP32_ePaper_example/master/Documents/EPD-No_power.jpg)
|
||||
|
333
components/epaper/DefaultFont.c
Normal file
333
components/epaper/DefaultFont.c
Normal file
@ -0,0 +1,333 @@
|
||||
// Default font
|
||||
|
||||
// ========================================================================
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// Header Format:
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset (start Y of visible pixels)
|
||||
// Width (width of the visible pixels)
|
||||
// Height (height of the visible pixels)
|
||||
// xOffset (start X of visible pixels)
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
// ========================================================================
|
||||
|
||||
// dejavu
|
||||
// Point Size : 12
|
||||
// Memory usage : 1158 bytes
|
||||
// # characters : 95
|
||||
|
||||
const unsigned char tft_DefaultFont[] =
|
||||
{
|
||||
0x00, 0x0B, 0x86, 0x04,
|
||||
|
||||
// ' '
|
||||
0x20,0x0A,0x00,0x00,0x00,0x04,
|
||||
|
||||
// '!'
|
||||
0x21,0x01,0x01,0x09,0x02,0x05,
|
||||
0xFD,0x80,
|
||||
// '"'
|
||||
0x22,0x01,0x03,0x03,0x01,0x05,
|
||||
0xB6,0x80,
|
||||
// '#'
|
||||
0x23,0x02,0x08,0x08,0x01,0x0A,
|
||||
0x12,0x14,0x7F,0x24,0x24,0xFE,0x28,0x48,
|
||||
// '$'
|
||||
0x24,0x01,0x06,0x0B,0x02,0x08,
|
||||
0x21,0xCA,0xA8,0xE0,0xE2,0xAA,0x70,0x82,0x00,
|
||||
// '%'
|
||||
0x25,0x01,0x0A,0x09,0x00,0x0B,
|
||||
0x61,0x24,0x89,0x22,0x50,0x6D,0x82,0x91,0x24,0x49,0x21,0x80,
|
||||
// '&'
|
||||
0x26,0x01,0x09,0x09,0x01,0x0A,
|
||||
0x30,0x24,0x10,0x0C,0x05,0x14,0x4A,0x19,0x8C,0x7B,0x00,
|
||||
// '''
|
||||
0x27,0x01,0x01,0x03,0x01,0x03,
|
||||
0xE0,
|
||||
// '('
|
||||
0x28,0x00,0x03,0x0B,0x01,0x05,
|
||||
0x69,0x49,0x24,0x48,0x80,
|
||||
// ')'
|
||||
0x29,0x00,0x03,0x0B,0x01,0x05,
|
||||
0x89,0x12,0x49,0x4A,0x00,
|
||||
// '*'
|
||||
0x2A,0x01,0x05,0x06,0x01,0x06,
|
||||
0x25,0x5C,0xEA,0x90,
|
||||
// '+'
|
||||
0x2B,0x03,0x07,0x07,0x01,0x0A,
|
||||
0x10,0x20,0x47,0xF1,0x02,0x04,0x00,
|
||||
// ','
|
||||
0x2C,0x08,0x01,0x03,0x01,0x04,
|
||||
0xE0,
|
||||
// '-'
|
||||
0x2D,0x06,0x03,0x01,0x01,0x04,
|
||||
0xE0,
|
||||
// '.'
|
||||
0x2E,0x08,0x01,0x02,0x01,0x04,
|
||||
0xC0,
|
||||
// '/'
|
||||
0x2F,0x01,0x04,0x0A,0x00,0x04,
|
||||
0x11,0x22,0x24,0x44,0x88,
|
||||
// '0'
|
||||
0x30,0x01,0x06,0x09,0x01,0x08,
|
||||
0x79,0x28,0x61,0x86,0x18,0x52,0x78,
|
||||
// '1'
|
||||
0x31,0x01,0x05,0x09,0x01,0x08,
|
||||
0xE1,0x08,0x42,0x10,0x84,0xF8,
|
||||
// '2'
|
||||
0x32,0x01,0x07,0x09,0x01,0x08,
|
||||
0x79,0x18,0x10,0x20,0x82,0x08,0x20,0xFC,
|
||||
// '3'
|
||||
0x33,0x01,0x06,0x09,0x01,0x08,
|
||||
0x7A,0x10,0x41,0x38,0x30,0x63,0x78,
|
||||
// '4'
|
||||
0x34,0x01,0x06,0x09,0x01,0x08,
|
||||
0x18,0x62,0x92,0x4A,0x2F,0xC2,0x08,
|
||||
// '5'
|
||||
0x35,0x01,0x06,0x09,0x01,0x08,
|
||||
0xFA,0x08,0x3C,0x0C,0x10,0x63,0x78,
|
||||
// '6'
|
||||
0x36,0x01,0x06,0x09,0x01,0x08,
|
||||
0x39,0x18,0x3E,0xCE,0x18,0x53,0x78,
|
||||
// '7'
|
||||
0x37,0x01,0x06,0x09,0x01,0x08,
|
||||
0xFC,0x10,0x82,0x10,0x42,0x08,0x40,
|
||||
// '8'
|
||||
0x38,0x01,0x06,0x09,0x01,0x08,
|
||||
0x7B,0x38,0x73,0x7B,0x38,0x73,0x78,
|
||||
// '9'
|
||||
0x39,0x01,0x06,0x09,0x01,0x08,
|
||||
0x7B,0x28,0x61,0xCD,0xD0,0x62,0x70,
|
||||
// ':'
|
||||
0x3A,0x04,0x01,0x06,0x01,0x04,
|
||||
0xCC,
|
||||
// ';'
|
||||
0x3B,0x04,0x01,0x07,0x01,0x04,
|
||||
0xCE,
|
||||
// '<'
|
||||
0x3C,0x03,0x08,0x06,0x01,0x0A,
|
||||
0x03,0x1E,0xE0,0xE0,0x1E,0x03,
|
||||
// '='
|
||||
0x3D,0x05,0x08,0x03,0x01,0x0A,
|
||||
0xFF,0x00,0xFF,
|
||||
// '>'
|
||||
0x3E,0x03,0x08,0x06,0x01,0x0A,
|
||||
0xC0,0x78,0x07,0x07,0x78,0xC0,
|
||||
// '?'
|
||||
0x3F,0x01,0x05,0x09,0x00,0x06,
|
||||
0x74,0x42,0x22,0x10,0x04,0x20,
|
||||
// '@'
|
||||
0x40,0x01,0x0B,0x0B,0x01,0x0D,
|
||||
0x1F,0x06,0x19,0x01,0x46,0x99,0x13,0x22,0x64,0x54,0x6C,0x40,0x04,0x10,0x7C,0x00,
|
||||
// 'A'
|
||||
0x41,0x01,0x08,0x09,0x00,0x08,
|
||||
0x18,0x18,0x24,0x24,0x24,0x42,0x7E,0x42,0x81,
|
||||
// 'B'
|
||||
0x42,0x01,0x06,0x09,0x01,0x08,
|
||||
0xFA,0x18,0x61,0xFA,0x18,0x61,0xF8,
|
||||
// 'C'
|
||||
0x43,0x01,0x06,0x09,0x01,0x08,
|
||||
0x39,0x18,0x20,0x82,0x08,0x11,0x38,
|
||||
// 'D'
|
||||
0x44,0x01,0x07,0x09,0x01,0x09,
|
||||
0xF9,0x0A,0x0C,0x18,0x30,0x60,0xC2,0xF8,
|
||||
// 'E'
|
||||
0x45,0x01,0x06,0x09,0x01,0x08,
|
||||
0xFE,0x08,0x20,0xFE,0x08,0x20,0xFC,
|
||||
// 'F'
|
||||
0x46,0x01,0x05,0x09,0x01,0x07,
|
||||
0xFC,0x21,0x0F,0xC2,0x10,0x80,
|
||||
// 'G'
|
||||
0x47,0x01,0x07,0x09,0x01,0x09,
|
||||
0x3C,0x86,0x04,0x08,0xF0,0x60,0xA1,0x3C,
|
||||
// 'H'
|
||||
0x48,0x01,0x07,0x09,0x01,0x09,
|
||||
0x83,0x06,0x0C,0x1F,0xF0,0x60,0xC1,0x82,
|
||||
// 'I'
|
||||
0x49,0x01,0x01,0x09,0x01,0x03,
|
||||
0xFF,0x80,
|
||||
// 'J'
|
||||
0x4A,0x01,0x03,0x0B,0xFF,0x03,
|
||||
0x24,0x92,0x49,0x27,0x00,
|
||||
// 'K'
|
||||
0x4B,0x01,0x07,0x09,0x01,0x07,
|
||||
0x85,0x12,0x45,0x0C,0x14,0x24,0x44,0x84,
|
||||
// 'L'
|
||||
0x4C,0x01,0x05,0x09,0x01,0x06,
|
||||
0x84,0x21,0x08,0x42,0x10,0xF8,
|
||||
// 'M'
|
||||
0x4D,0x01,0x08,0x09,0x01,0x0A,
|
||||
0x81,0xC3,0xC3,0xA5,0xA5,0x99,0x99,0x81,0x81,
|
||||
// 'N'
|
||||
0x4E,0x01,0x07,0x09,0x01,0x09,
|
||||
0xC3,0x86,0x8D,0x19,0x31,0x62,0xC3,0x86,
|
||||
// 'O'
|
||||
0x4F,0x01,0x07,0x09,0x01,0x09,
|
||||
0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38,
|
||||
// 'P'
|
||||
0x50,0x01,0x06,0x09,0x01,0x08,
|
||||
0xFA,0x38,0x63,0xFA,0x08,0x20,0x80,
|
||||
// 'Q'
|
||||
0x51,0x01,0x07,0x0B,0x01,0x09,
|
||||
0x38,0x8A,0x0C,0x18,0x30,0x60,0xA2,0x38,0x10,0x10,
|
||||
// 'R'
|
||||
0x52,0x01,0x07,0x09,0x01,0x08,
|
||||
0xF9,0x1A,0x14,0x6F,0x91,0x21,0x42,0x82,
|
||||
// 'S'
|
||||
0x53,0x01,0x06,0x09,0x01,0x08,
|
||||
0x7B,0x18,0x30,0x78,0x30,0x63,0x78,
|
||||
// 'T'
|
||||
0x54,0x01,0x07,0x09,0x00,0x07,
|
||||
0xFE,0x20,0x40,0x81,0x02,0x04,0x08,0x10,
|
||||
// 'U'
|
||||
0x55,0x01,0x07,0x09,0x01,0x09,
|
||||
0x83,0x06,0x0C,0x18,0x30,0x60,0xA2,0x38,
|
||||
// 'V'
|
||||
0x56,0x01,0x0A,0x09,0xFF,0x08,
|
||||
0x40,0x90,0x22,0x10,0x84,0x21,0x04,0x81,0x20,0x30,0x0C,0x00,
|
||||
// 'W'
|
||||
0x57,0x01,0x0B,0x09,0x00,0x0B,
|
||||
0x84,0x28,0x89,0x11,0x27,0x22,0xA8,0x55,0x0E,0xE0,0x88,0x11,0x00,
|
||||
// 'X'
|
||||
0x58,0x01,0x07,0x09,0x00,0x07,
|
||||
0xC6,0x88,0xA1,0xC1,0x07,0x0A,0x22,0x82,
|
||||
// 'Y'
|
||||
0x59,0x01,0x07,0x09,0x00,0x07,
|
||||
0x82,0x89,0x11,0x43,0x82,0x04,0x08,0x10,
|
||||
// 'Z'
|
||||
0x5A,0x01,0x07,0x09,0x01,0x09,
|
||||
0xFE,0x04,0x10,0x41,0x04,0x10,0x40,0xFE,
|
||||
// '['
|
||||
0x5B,0x01,0x02,0x0B,0x02,0x05,
|
||||
0xEA,0xAA,0xAC,
|
||||
// '\'
|
||||
0x5C,0x01,0x04,0x0A,0x00,0x04,
|
||||
0x88,0x44,0x42,0x22,0x11,
|
||||
// ']'
|
||||
0x5D,0x01,0x02,0x0B,0x01,0x05,
|
||||
0xD5,0x55,0x5C,
|
||||
// '^'
|
||||
0x5E,0x01,0x08,0x03,0x01,0x0A,
|
||||
0x18,0x24,0x42,
|
||||
// '_'
|
||||
0x5F,0x0C,0x06,0x01,0x00,0x06,
|
||||
0xFC,
|
||||
// '`'
|
||||
0x60,0x00,0x03,0x02,0x01,0x06,
|
||||
0x44,
|
||||
// 'a'
|
||||
0x61,0x03,0x06,0x07,0x01,0x08,
|
||||
0x7A,0x30,0x5F,0x86,0x37,0x40,
|
||||
// 'b'
|
||||
0x62,0x00,0x06,0x0A,0x01,0x08,
|
||||
0x82,0x08,0x2E,0xCA,0x18,0x61,0xCE,0xE0,
|
||||
// 'c'
|
||||
0x63,0x03,0x05,0x07,0x01,0x07,
|
||||
0x72,0x61,0x08,0x25,0xC0,
|
||||
// 'd'
|
||||
0x64,0x00,0x06,0x0A,0x01,0x08,
|
||||
0x04,0x10,0x5D,0xCE,0x18,0x61,0xCD,0xD0,
|
||||
// 'e'
|
||||
0x65,0x03,0x06,0x07,0x01,0x08,
|
||||
0x39,0x38,0x7F,0x81,0x13,0x80,
|
||||
// 'f'
|
||||
0x66,0x00,0x04,0x0A,0x00,0x04,
|
||||
0x34,0x4F,0x44,0x44,0x44,
|
||||
// 'g'
|
||||
0x67,0x03,0x06,0x0A,0x01,0x08,
|
||||
0x77,0x38,0x61,0x87,0x37,0x41,0x4C,0xE0,
|
||||
// 'h'
|
||||
0x68,0x00,0x06,0x0A,0x01,0x08,
|
||||
0x82,0x08,0x2E,0xC6,0x18,0x61,0x86,0x10,
|
||||
// 'i'
|
||||
0x69,0x01,0x01,0x09,0x01,0x03,
|
||||
0xBF,0x80,
|
||||
// 'j'
|
||||
0x6A,0x01,0x02,0x0C,0x00,0x03,
|
||||
0x45,0x55,0x56,
|
||||
// 'k'
|
||||
0x6B,0x00,0x06,0x0A,0x01,0x07,
|
||||
0x82,0x08,0x22,0x92,0x8E,0x28,0x92,0x20,
|
||||
// 'l'
|
||||
0x6C,0x00,0x01,0x0A,0x01,0x03,
|
||||
0xFF,0xC0,
|
||||
// 'm'
|
||||
0x6D,0x03,0x09,0x07,0x01,0x0B,
|
||||
0xB3,0x66,0x62,0x31,0x18,0x8C,0x46,0x22,
|
||||
// 'n'
|
||||
0x6E,0x03,0x06,0x07,0x01,0x08,
|
||||
0xBB,0x18,0x61,0x86,0x18,0x40,
|
||||
// 'o'
|
||||
0x6F,0x03,0x06,0x07,0x01,0x08,
|
||||
0x7B,0x38,0x61,0x87,0x37,0x80,
|
||||
// 'p'
|
||||
0x70,0x03,0x06,0x0A,0x01,0x08,
|
||||
0xBB,0x28,0x61,0x87,0x3B,0xA0,0x82,0x00,
|
||||
// 'q'
|
||||
0x71,0x03,0x06,0x0A,0x01,0x08,
|
||||
0x77,0x38,0x61,0x87,0x37,0x41,0x04,0x10,
|
||||
// 'r'
|
||||
0x72,0x03,0x04,0x07,0x01,0x05,
|
||||
0xBC,0x88,0x88,0x80,
|
||||
// 's'
|
||||
0x73,0x03,0x06,0x07,0x01,0x07,
|
||||
0x72,0x28,0x1C,0x0A,0x27,0x00,
|
||||
// 't'
|
||||
0x74,0x01,0x04,0x09,0x00,0x05,
|
||||
0x44,0xF4,0x44,0x44,0x30,
|
||||
// 'u'
|
||||
0x75,0x03,0x06,0x07,0x01,0x08,
|
||||
0x86,0x18,0x61,0x86,0x37,0x40,
|
||||
// 'v'
|
||||
0x76,0x03,0x08,0x07,0xFF,0x06,
|
||||
0x42,0x42,0x24,0x24,0x24,0x18,0x18,
|
||||
// 'w'
|
||||
0x77,0x03,0x09,0x07,0x00,0x09,
|
||||
0x88,0xC4,0x57,0x4A,0xA5,0x51,0x10,0x88,
|
||||
// 'x'
|
||||
0x78,0x03,0x06,0x07,0x00,0x06,
|
||||
0x85,0x24,0x8C,0x49,0x28,0x40,
|
||||
// 'y'
|
||||
0x79,0x03,0x08,0x0A,0xFF,0x06,
|
||||
0x42,0x42,0x24,0x24,0x14,0x18,0x08,0x08,0x10,0x60,
|
||||
// 'z'
|
||||
0x7A,0x03,0x05,0x07,0x00,0x05,
|
||||
0xF8,0x44,0x44,0x43,0xE0,
|
||||
// '{'
|
||||
0x7B,0x01,0x05,0x0B,0x02,0x08,
|
||||
0x19,0x08,0x42,0x60,0x84,0x21,0x06,
|
||||
// '|'
|
||||
0x7C,0x01,0x01,0x0C,0x02,0x04,
|
||||
0xFF,0xF0,
|
||||
// '}'
|
||||
0x7D,0x01,0x05,0x0B,0x01,0x08,
|
||||
0xC1,0x08,0x42,0x0C,0x84,0x21,0x30,
|
||||
// '~'
|
||||
0x7E,0x04,0x08,0x03,0x01,0x0A,
|
||||
0x00,0x71,0x8E,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
322
components/epaper/DejaVuSans18.c
Normal file
322
components/epaper/DejaVuSans18.c
Normal file
@ -0,0 +1,322 @@
|
||||
// ============================================================================
|
||||
// Proportional font Header Format:
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
// ============================================================================
|
||||
|
||||
// DejaVuSans
|
||||
// Point Size : 18
|
||||
// Memory usage : 1828 bytes
|
||||
// # characters : 95
|
||||
|
||||
const unsigned char tft_Dejavu18x[] =
|
||||
{
|
||||
0x00, 0x12, 0x00, 0x00,
|
||||
|
||||
// ' '
|
||||
0x20,0x0E,0x00,0x00,0x00,0x06,
|
||||
|
||||
// '!'
|
||||
0x21,0x01,0x02,0x0D,0x03,0x07,
|
||||
0xFF,0xFF,0xC3,0xC0,
|
||||
// '"'
|
||||
0x22,0x01,0x06,0x05,0x01,0x08,
|
||||
0xCF,0x3C,0xF3,0xCC,
|
||||
// '#'
|
||||
0x23,0x00,0x0C,0x0E,0x01,0x0F,
|
||||
0x04,0x40,0x44,0x0C,0xC0,0xC8,0x7F,0xF7,0xFF,0x09,0x81,0x90,0xFF,0xEF,0xFE,0x13,0x03,0x30,0x32,0x02,0x20,
|
||||
// '$'
|
||||
0x24,0x00,0x0A,0x11,0x01,0x0B,
|
||||
0x08,0x02,0x03,0xE1,0xFC,0xE9,0x32,0x0F,0x81,0xF8,0x0F,0x02,0x60,0x9A,0x2E,0xFF,0x1F,0x80,0x80,0x20,0x08,0x00,
|
||||
// '%'
|
||||
0x25,0x01,0x0F,0x0D,0x01,0x11,
|
||||
0x78,0x10,0x90,0x43,0x31,0x86,0x62,0x0C,0xC8,0x19,0x10,0x1E,0x4F,0x01,0x12,0x02,0x66,0x08,0xCC,0x31,0x98,0x41,0x21,0x03,0xC0,
|
||||
// '&'
|
||||
0x26,0x01,0x0C,0x0D,0x01,0x0D,
|
||||
0x0F,0x01,0xF8,0x30,0x83,0x00,0x38,0x03,0xC0,0x7E,0x6C,0x76,0xC3,0xCC,0x18,0xE1,0xC7,0xFE,0x3E,0x70,
|
||||
// '''
|
||||
0x27,0x01,0x02,0x05,0x01,0x04,
|
||||
0xFF,0xC0,
|
||||
// '('
|
||||
0x28,0x00,0x04,0x10,0x02,0x07,
|
||||
0x32,0x66,0x4C,0xCC,0xCC,0xC4,0x66,0x23,
|
||||
// ')'
|
||||
0x29,0x00,0x04,0x10,0x01,0x07,
|
||||
0xC4,0x66,0x23,0x33,0x33,0x32,0x66,0x4C,
|
||||
// '*'
|
||||
0x2A,0x01,0x07,0x08,0x01,0x09,
|
||||
0x11,0x25,0x51,0xC3,0x8A,0xA4,0x88,
|
||||
// '+'
|
||||
0x2B,0x02,0x0C,0x0C,0x02,0x0F,
|
||||
0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x06,0x00,0x60,
|
||||
// ','
|
||||
0x2C,0x0C,0x03,0x04,0x01,0x06,
|
||||
0x6D,0x40,
|
||||
// '-'
|
||||
0x2D,0x08,0x05,0x02,0x01,0x07,
|
||||
0xFF,0xC0,
|
||||
// '.'
|
||||
0x2E,0x0C,0x02,0x02,0x02,0x06,
|
||||
0xF0,
|
||||
// '/'
|
||||
0x2F,0x01,0x06,0x0F,0x00,0x06,
|
||||
0x0C,0x31,0x86,0x18,0xE3,0x0C,0x31,0xC6,0x18,0x63,0x0C,0x00,
|
||||
// '0'
|
||||
0x30,0x01,0x09,0x0D,0x01,0x0B,
|
||||
0x3E,0x3F,0x98,0xD8,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xD8,0xCF,0xE3,0xE0,
|
||||
// '1'
|
||||
0x31,0x01,0x08,0x0D,0x02,0x0B,
|
||||
0x38,0xF8,0xD8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF,
|
||||
// '2'
|
||||
0x32,0x01,0x09,0x0D,0x01,0x0B,
|
||||
0x7C,0x7F,0x21,0xC0,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x1F,0xEF,0xF0,
|
||||
// '3'
|
||||
0x33,0x01,0x09,0x0D,0x01,0x0B,
|
||||
0x7E,0x7F,0xA0,0xE0,0x30,0x39,0xF0,0xFC,0x07,0x01,0x80,0xE0,0xFF,0xE7,0xE0,
|
||||
// '4'
|
||||
0x34,0x01,0x0A,0x0D,0x01,0x0B,
|
||||
0x07,0x01,0xC0,0xB0,0x6C,0x13,0x08,0xC6,0x31,0x0C,0xFF,0xFF,0xF0,0x30,0x0C,0x03,0x00,
|
||||
// '5'
|
||||
0x35,0x01,0x08,0x0D,0x01,0x0B,
|
||||
0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x47,0x03,0x03,0x03,0x87,0xFE,0x7C,
|
||||
// '6'
|
||||
0x36,0x01,0x09,0x0D,0x01,0x0B,
|
||||
0x1E,0x1F,0x9C,0x5C,0x0C,0x06,0xF3,0xFD,0xC7,0xC1,0xE0,0xD8,0xEF,0xE1,0xE0,
|
||||
// '7'
|
||||
0x37,0x01,0x08,0x0D,0x01,0x0B,
|
||||
0xFF,0xFF,0x06,0x06,0x06,0x0E,0x0C,0x0C,0x1C,0x18,0x18,0x38,0x30,
|
||||
// '8'
|
||||
0x38,0x01,0x09,0x0D,0x01,0x0B,
|
||||
0x3E,0x3F,0xB8,0xF8,0x3E,0x39,0xF1,0xFD,0xC7,0xC1,0xE0,0xF8,0xEF,0xE3,0xE0,
|
||||
// '9'
|
||||
0x39,0x01,0x09,0x0D,0x01,0x0B,
|
||||
0x3C,0x3F,0xB8,0xD8,0x3C,0x1F,0x1D,0xFE,0x7B,0x01,0x81,0xD1,0xCF,0xC3,0xC0,
|
||||
// ':'
|
||||
0x3A,0x05,0x02,0x09,0x02,0x06,
|
||||
0xF0,0x03,0xC0,
|
||||
// ';'
|
||||
0x3B,0x05,0x03,0x0B,0x01,0x06,
|
||||
0x6C,0x00,0x03,0x6A,0x00,
|
||||
// '<'
|
||||
0x3C,0x04,0x0B,0x0A,0x02,0x0F,
|
||||
0x00,0x20,0x3C,0x1F,0x1F,0x0F,0x81,0xF0,0x0F,0x80,0x3E,0x01,0xE0,0x04,
|
||||
// '='
|
||||
0x3D,0x05,0x0B,0x06,0x02,0x0F,
|
||||
0xFF,0xFF,0xFC,0x00,0x00,0x0F,0xFF,0xFF,0xC0,
|
||||
// '>'
|
||||
0x3E,0x04,0x0B,0x0A,0x02,0x0F,
|
||||
0x80,0x1E,0x01,0xF0,0x07,0xC0,0x3E,0x07,0xC3,0xE3,0xE0,0xF0,0x10,0x00,
|
||||
// '?'
|
||||
0x3F,0x01,0x07,0x0D,0x01,0x0A,
|
||||
0x79,0xFA,0x38,0x30,0x61,0x86,0x18,0x30,0x60,0x01,0x83,0x00,
|
||||
// '@'
|
||||
0x40,0x01,0x10,0x10,0x01,0x12,
|
||||
0x07,0xE0,0x1F,0xF8,0x3C,0x1C,0x70,0x06,0x60,0x07,0xE3,0x63,0xC7,0xE3,0xC6,0x63,0xC6,0x66,0xC7,0xFC,0xE3,0x70,0x60,0x00,0x70,0x00,0x3C,0x30,0x1F,0xF0,0x07,0xC0,
|
||||
// 'A'
|
||||
0x41,0x01,0x0C,0x0D,0x00,0x0C,
|
||||
0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30,
|
||||
// 'B'
|
||||
0x42,0x01,0x09,0x0D,0x02,0x0C,
|
||||
0xFC,0x7F,0xB0,0xD8,0x6C,0x37,0xF3,0xF9,0x86,0xC1,0xE0,0xF0,0xFF,0xEF,0xE0,
|
||||
// 'C'
|
||||
0x43,0x01,0x0B,0x0D,0x01,0x0D,
|
||||
0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC,
|
||||
// 'D'
|
||||
0x44,0x01,0x0B,0x0D,0x02,0x0E,
|
||||
0xFE,0x1F,0xF3,0x07,0x60,0x6C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1B,0x07,0x7F,0xCF,0xE0,
|
||||
// 'E'
|
||||
0x45,0x01,0x08,0x0D,0x02,0x0B,
|
||||
0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'F'
|
||||
0x46,0x01,0x08,0x0D,0x02,0x0A,
|
||||
0xFF,0xFF,0xC0,0xC0,0xC0,0xFE,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
// 'G'
|
||||
0x47,0x01,0x0B,0x0D,0x01,0x0E,
|
||||
0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x87,0xF0,0xFE,0x03,0xC0,0x6C,0x0D,0xC1,0x9F,0xE0,0xF8,
|
||||
// 'H'
|
||||
0x48,0x01,0x0A,0x0D,0x02,0x0E,
|
||||
0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xFF,0xFF,0xFF,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xC0,
|
||||
// 'I'
|
||||
0x49,0x01,0x02,0x0D,0x02,0x06,
|
||||
0xFF,0xFF,0xFF,0xC0,
|
||||
// 'J'
|
||||
0x4A,0x01,0x05,0x11,0xFF,0x06,
|
||||
0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0xFE,0xE0,
|
||||
// 'K'
|
||||
0x4B,0x01,0x0B,0x0D,0x02,0x0C,
|
||||
0xC1,0x98,0x63,0x18,0x66,0x0D,0x81,0xE0,0x3C,0x06,0xC0,0xCC,0x18,0xC3,0x0C,0x60,0xCC,0x0C,
|
||||
// 'L'
|
||||
0x4C,0x01,0x08,0x0D,0x02,0x0A,
|
||||
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'M'
|
||||
0x4D,0x01,0x0C,0x0D,0x02,0x10,
|
||||
0xE0,0x7F,0x0F,0xF0,0xFD,0x8B,0xD9,0xBD,0x9B,0xCF,0x3C,0xF3,0xC6,0x3C,0x63,0xC0,0x3C,0x03,0xC0,0x30,
|
||||
// 'N'
|
||||
0x4E,0x01,0x0A,0x0D,0x02,0x0E,
|
||||
0xE0,0xF8,0x3F,0x0F,0xC3,0xD8,0xF6,0x3C,0xCF,0x1B,0xC6,0xF0,0xFC,0x3F,0x07,0xC1,0xC0,
|
||||
// 'O'
|
||||
0x4F,0x01,0x0C,0x0D,0x01,0x0E,
|
||||
0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,
|
||||
// 'P'
|
||||
0x50,0x01,0x08,0x0D,0x02,0x0B,
|
||||
0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
// 'Q'
|
||||
0x51,0x01,0x0C,0x0F,0x01,0x0E,
|
||||
0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,0x18,0x00,0xC0,
|
||||
// 'R'
|
||||
0x52,0x01,0x0A,0x0D,0x02,0x0D,
|
||||
0xFC,0x3F,0x8C,0x73,0x0C,0xC3,0x31,0xCF,0xE3,0xF0,0xC6,0x30,0xCC,0x33,0x06,0xC1,0xC0,
|
||||
// 'S'
|
||||
0x53,0x01,0x0A,0x0D,0x01,0x0B,
|
||||
0x3E,0x1F,0xCE,0x13,0x00,0xC0,0x1F,0x03,0xF0,0x0E,0x01,0x80,0x68,0x3B,0xFC,0x7E,0x00,
|
||||
// 'T'
|
||||
0x54,0x01,0x0C,0x0D,0x00,0x0C,
|
||||
0xFF,0xFF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,
|
||||
// 'U'
|
||||
0x55,0x01,0x0A,0x0D,0x02,0x0E,
|
||||
0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x36,0x19,0xFE,0x1E,0x00,
|
||||
// 'V'
|
||||
0x56,0x01,0x0C,0x0D,0x00,0x0C,
|
||||
0xC0,0x36,0x06,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,0x06,0x00,
|
||||
// 'W'
|
||||
0x57,0x01,0x11,0x0D,0x01,0x13,
|
||||
0xC1,0xC1,0xE0,0xE0,0xD8,0xF8,0xCC,0x6C,0x66,0x36,0x33,0x1B,0x18,0xD8,0xD8,0x6C,0x6C,0x36,0x36,0x1F,0x1F,0x07,0x07,0x03,0x83,0x81,0xC1,0xC0,
|
||||
// 'X'
|
||||
0x58,0x01,0x0B,0x0D,0x01,0x0D,
|
||||
0x70,0xE6,0x18,0xE6,0x0D,0xC0,0xF0,0x1C,0x03,0x80,0x78,0x1B,0x07,0x30,0xC7,0x30,0x6E,0x0E,
|
||||
// 'Y'
|
||||
0x59,0x01,0x0C,0x0D,0x00,0x0C,
|
||||
0xE0,0x76,0x06,0x30,0xC1,0x98,0x19,0x80,0xF0,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x01,0x0B,0x0D,0x01,0x0D,
|
||||
0xFF,0xFF,0xFC,0x07,0x01,0xC0,0x30,0x0E,0x03,0x80,0xE0,0x18,0x06,0x01,0xC0,0x7F,0xFF,0xFE,
|
||||
// '['
|
||||
0x5B,0x00,0x04,0x10,0x01,0x07,
|
||||
0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF,
|
||||
// '\'
|
||||
0x5C,0x01,0x06,0x0F,0x00,0x06,
|
||||
0xC3,0x06,0x18,0x61,0xC3,0x0C,0x30,0xE1,0x86,0x18,0x30,0xC0,
|
||||
// ']'
|
||||
0x5D,0x00,0x04,0x10,0x02,0x07,
|
||||
0xFF,0x33,0x33,0x33,0x33,0x33,0x33,0xFF,
|
||||
// '^'
|
||||
0x5E,0x01,0x0B,0x05,0x02,0x0F,
|
||||
0x0E,0x03,0xE0,0xC6,0x30,0x6C,0x06,
|
||||
// '_'
|
||||
0x5F,0x10,0x09,0x02,0x00,0x09,
|
||||
0xFF,0xFF,0xC0,
|
||||
// '`'
|
||||
0x60,0x00,0x04,0x03,0x02,0x09,
|
||||
0xC6,0x30,
|
||||
// 'a'
|
||||
0x61,0x04,0x08,0x0A,0x01,0x0A,
|
||||
0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'b'
|
||||
0x62,0x00,0x09,0x0E,0x02,0x0B,
|
||||
0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF0,
|
||||
// 'c'
|
||||
0x63,0x04,0x08,0x0A,0x01,0x09,
|
||||
0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E,
|
||||
// 'd'
|
||||
0x64,0x00,0x09,0x0E,0x01,0x0B,
|
||||
0x01,0x80,0xC0,0x60,0x33,0xDB,0xFF,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x77,0xF9,0xEC,
|
||||
// 'e'
|
||||
0x65,0x04,0x0A,0x0A,0x01,0x0B,
|
||||
0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,
|
||||
// 'f'
|
||||
0x66,0x00,0x07,0x0E,0x00,0x06,
|
||||
0x1E,0x7C,0xC1,0x8F,0xFF,0xCC,0x18,0x30,0x60,0xC1,0x83,0x06,0x00,
|
||||
// 'g'
|
||||
0x67,0x04,0x09,0x0E,0x01,0x0B,
|
||||
0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x68,0x67,0xF1,0xF0,
|
||||
// 'h'
|
||||
0x68,0x00,0x08,0x0E,0x02,0x0B,
|
||||
0xC0,0xC0,0xC0,0xC0,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
|
||||
// 'i'
|
||||
0x69,0x00,0x02,0x0E,0x02,0x05,
|
||||
0xF0,0xFF,0xFF,0xF0,
|
||||
// 'j'
|
||||
0x6A,0x00,0x04,0x12,0x00,0x05,
|
||||
0x33,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0xEC,
|
||||
// 'k'
|
||||
0x6B,0x00,0x09,0x0E,0x02,0x0A,
|
||||
0xC0,0x60,0x30,0x18,0x0C,0x36,0x33,0x31,0xB0,0xF0,0x78,0x36,0x19,0x8C,0x66,0x18,
|
||||
// 'l'
|
||||
0x6C,0x00,0x02,0x0E,0x02,0x05,
|
||||
0xFF,0xFF,0xFF,0xF0,
|
||||
// 'm'
|
||||
0x6D,0x04,0x0E,0x0A,0x02,0x11,
|
||||
0xDC,0x7B,0xFB,0xEE,0x79,0xF0,0xC3,0xC3,0x0F,0x0C,0x3C,0x30,0xF0,0xC3,0xC3,0x0F,0x0C,0x30,
|
||||
// 'n'
|
||||
0x6E,0x04,0x08,0x0A,0x02,0x0B,
|
||||
0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
|
||||
// 'o'
|
||||
0x6F,0x04,0x0A,0x0A,0x01,0x0B,
|
||||
0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'p'
|
||||
0x70,0x04,0x09,0x0E,0x02,0x0B,
|
||||
0xDE,0x7F,0xB8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0xFF,0x6F,0x30,0x18,0x0C,0x06,0x00,
|
||||
// 'q'
|
||||
0x71,0x04,0x09,0x0E,0x01,0x0B,
|
||||
0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x60,0x30,0x18,0x0C,
|
||||
// 'r'
|
||||
0x72,0x04,0x06,0x0A,0x02,0x08,
|
||||
0xDF,0xFE,0x30,0xC3,0x0C,0x30,0xC3,0x00,
|
||||
// 's'
|
||||
0x73,0x04,0x08,0x0A,0x01,0x08,
|
||||
0x7C,0xFE,0xC2,0xE0,0x7C,0x1E,0x06,0x86,0xFE,0x78,
|
||||
// 't'
|
||||
0x74,0x01,0x06,0x0D,0x01,0x07,
|
||||
0x61,0x86,0x3F,0xFD,0x86,0x18,0x61,0x86,0x1F,0x3C,
|
||||
// 'u'
|
||||
0x75,0x04,0x08,0x0A,0x02,0x0B,
|
||||
0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,
|
||||
// 'v'
|
||||
0x76,0x04,0x0C,0x0A,0x00,0x0B,
|
||||
0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,
|
||||
// 'w'
|
||||
0x77,0x04,0x0F,0x0A,0x01,0x10,
|
||||
0x63,0x8C,0xC7,0x19,0x8E,0x31,0xB6,0xC3,0x6D,0x86,0xDB,0x0F,0x1E,0x0E,0x38,0x1C,0x70,0x38,0xE0,
|
||||
// 'x'
|
||||
0x78,0x04,0x0A,0x0A,0x01,0x0B,
|
||||
0xE1,0xD8,0x63,0x30,0xCC,0x1E,0x07,0x83,0x30,0xCC,0x61,0xB8,0x70,
|
||||
// 'y'
|
||||
0x79,0x04,0x0C,0x0E,0x00,0x0B,
|
||||
0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,
|
||||
// 'z'
|
||||
0x7A,0x04,0x08,0x0A,0x01,0x09,
|
||||
0xFF,0xFF,0x06,0x0C,0x1C,0x38,0x30,0x70,0xFF,0xFF,
|
||||
// '{'
|
||||
0x7B,0x00,0x08,0x11,0x02,0x0B,
|
||||
0x0F,0x1F,0x18,0x18,0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x18,0x18,0x18,0x1F,0x0F,
|
||||
// '|'
|
||||
0x7C,0x00,0x02,0x12,0x02,0x06,
|
||||
0xFF,0xFF,0xFF,0xFF,0xF0,
|
||||
// '}'
|
||||
0x7D,0x00,0x08,0x11,0x02,0x0B,
|
||||
0xF0,0xF8,0x18,0x18,0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0xF8,0xF0,
|
||||
// '~'
|
||||
0x7E,0x05,0x0B,0x05,0x02,0x0F,
|
||||
0x00,0x0F,0x87,0xFF,0xC3,0xE0,0x00,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
331
components/epaper/DejaVuSans24.c
Normal file
331
components/epaper/DejaVuSans24.c
Normal file
@ -0,0 +1,331 @@
|
||||
// ========================================================================
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// Header Format:
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
// ========================================================================
|
||||
|
||||
// dejavu
|
||||
// Point Size : 24
|
||||
// Memory usage : 2724 bytes
|
||||
// # characters : 95
|
||||
|
||||
const unsigned char tft_Dejavu24[] =
|
||||
{
|
||||
0x00, 0x17, 0x00, 0x00,
|
||||
|
||||
// ' '
|
||||
0x20,0x13,0x00,0x00,0x00,0x08,
|
||||
|
||||
// '!'
|
||||
0x21,0x01,0x02,0x12,0x04,0x0A,
|
||||
0xFF,0xFF,0xFF,0x03,0xF0,
|
||||
// '"'
|
||||
0x22,0x01,0x06,0x07,0x02,0x0B,
|
||||
0xCF,0x3C,0xF3,0xCF,0x3C,0xC0,
|
||||
// '#'
|
||||
0x23,0x01,0x10,0x12,0x02,0x14,
|
||||
0x03,0x08,0x03,0x18,0x03,0x18,0x03,0x18,0x02,0x18,0x7F,0xFF,0x7F,0xFF,0x06,0x30,0x04,0x30,0x0C,0x20,0x0C,0x60,0xFF,0xFE,0xFF,0xFE,0x18,0x40,0x18,0xC0,0x18,0xC0,0x18,0xC0,0x10,0xC0,
|
||||
// '$'
|
||||
0x24,0x01,0x0B,0x16,0x02,0x0F,
|
||||
0x04,0x00,0x80,0x10,0x0F,0xC7,0xFD,0xC8,0xB1,0x06,0x20,0xE4,0x0F,0x80,0xFE,0x03,0xE0,0x4E,0x08,0xC1,0x1E,0x27,0xFF,0xC7,0xE0,0x10,0x02,0x00,0x40,0x08,0x00,
|
||||
// '%'
|
||||
0x25,0x01,0x14,0x12,0x01,0x17,
|
||||
0x3C,0x03,0x06,0x60,0x60,0xC3,0x06,0x0C,0x30,0xC0,0xC3,0x1C,0x0C,0x31,0x80,0xC3,0x38,0x0C,0x33,0x00,0x66,0x63,0xC3,0xC6,0x66,0x00,0xCC,0x30,0x1C,0xC3,0x01,0x8C,0x30,0x38,0xC3,0x03,0x0C,0x30,0x60,0xC3,0x06,0x06,0x60,0xC0,0x3C,
|
||||
// '&'
|
||||
0x26,0x01,0x10,0x12,0x01,0x13,
|
||||
0x07,0xC0,0x1F,0xE0,0x38,0x20,0x30,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x1C,0x00,0x3E,0x00,0x77,0x06,0xE3,0x86,0xC1,0xCC,0xC0,0xFC,0xC0,0x78,0xE0,0x78,0x70,0xFC,0x3F,0xCE,0x0F,0x87,
|
||||
// '''
|
||||
0x27,0x01,0x02,0x07,0x02,0x07,
|
||||
0xFF,0xFC,
|
||||
// '('
|
||||
0x28,0x01,0x05,0x15,0x02,0x09,
|
||||
0x19,0x8C,0xC6,0x31,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x0C,0x61,0x80,
|
||||
// ')'
|
||||
0x29,0x01,0x05,0x15,0x02,0x09,
|
||||
0xC3,0x18,0x63,0x18,0x43,0x18,0xC6,0x31,0x8C,0x46,0x31,0x98,0xCC,0x00,
|
||||
// '*'
|
||||
0x2A,0x01,0x0B,0x0A,0x00,0x0C,
|
||||
0x04,0x00,0x83,0x11,0xBA,0xE1,0xF0,0x3E,0x1D,0x76,0x23,0x04,0x00,0x80,
|
||||
// '+'
|
||||
0x2B,0x03,0x10,0x10,0x03,0x14,
|
||||
0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0xFF,0xFF,0xFF,0xFF,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,
|
||||
// ','
|
||||
0x2C,0x10,0x03,0x06,0x02,0x08,
|
||||
0x6D,0xBD,0x80,
|
||||
// '-'
|
||||
0x2D,0x0B,0x06,0x02,0x01,0x09,
|
||||
0xFF,0xF0,
|
||||
// '.'
|
||||
0x2E,0x10,0x02,0x03,0x03,0x08,
|
||||
0xFC,
|
||||
// '/'
|
||||
0x2F,0x01,0x08,0x14,0x00,0x08,
|
||||
0x03,0x07,0x06,0x06,0x06,0x0C,0x0C,0x0C,0x18,0x18,0x18,0x18,0x30,0x30,0x30,0x60,0x60,0x60,0xE0,0xC0,
|
||||
// '0'
|
||||
0x30,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x0F,0x03,0xFC,0x70,0xE6,0x06,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x60,0x67,0x0E,0x3F,0xC0,0xF0,
|
||||
// '1'
|
||||
0x31,0x01,0x0A,0x12,0x03,0x0F,
|
||||
0x3C,0x3F,0x0C,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,
|
||||
// '2'
|
||||
0x32,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x3F,0x0F,0xF8,0xC1,0xC0,0x0E,0x00,0x60,0x06,0x00,0x60,0x0C,0x01,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFE,
|
||||
// '3'
|
||||
0x33,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x3F,0x07,0xFC,0x41,0xC0,0x06,0x00,0x60,0x06,0x00,0x60,0x0C,0x1F,0x81,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x78,0x0E,0xFF,0xC3,0xF0,
|
||||
// '4'
|
||||
0x34,0x01,0x0D,0x12,0x01,0x0F,
|
||||
0x01,0xC0,0x1E,0x00,0xB0,0x0D,0x80,0xCC,0x06,0x60,0x63,0x03,0x18,0x30,0xC3,0x06,0x18,0x31,0x81,0x8F,0xFF,0xFF,0xFC,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,
|
||||
// '5'
|
||||
0x35,0x01,0x0B,0x12,0x02,0x0F,
|
||||
0x7F,0xCF,0xF9,0x80,0x30,0x06,0x00,0xC0,0x1F,0xC3,0xFC,0x41,0xC0,0x1C,0x01,0x80,0x30,0x06,0x00,0xC0,0x3C,0x0E,0xFF,0x8F,0xC0,
|
||||
// '6'
|
||||
0x36,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x07,0xC1,0xFE,0x38,0x27,0x00,0x60,0x0C,0x00,0xCF,0x8D,0xFC,0xF8,0xEF,0x07,0xE0,0x3E,0x03,0xE0,0x36,0x03,0x70,0x77,0x8E,0x3F,0xC0,0xF8,
|
||||
// '7'
|
||||
0x37,0x01,0x0B,0x12,0x02,0x0F,
|
||||
0xFF,0xFF,0xFC,0x03,0x00,0x60,0x1C,0x03,0x00,0x60,0x18,0x03,0x00,0xE0,0x18,0x03,0x00,0xC0,0x18,0x07,0x00,0xC0,0x18,0x06,0x00,
|
||||
// '8'
|
||||
0x38,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x1F,0x87,0xFE,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x3F,0xC3,0xFC,0x70,0xEC,0x03,0xC0,0x3C,0x03,0xC0,0x37,0x0E,0x7F,0xE1,0xF8,
|
||||
// '9'
|
||||
0x39,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x1F,0x03,0xFC,0x71,0xCE,0x0E,0xC0,0x6C,0x07,0xC0,0x7C,0x07,0xE0,0xF7,0x1F,0x3F,0xB1,0xF3,0x00,0x30,0x06,0x00,0xE4,0x1C,0x7F,0x83,0xE0,
|
||||
// ':'
|
||||
0x3A,0x07,0x02,0x0C,0x03,0x08,
|
||||
0xFC,0x00,0x3F,
|
||||
// ';'
|
||||
0x3B,0x07,0x03,0x0F,0x02,0x08,
|
||||
0x6D,0x80,0x00,0x0D,0xB7,0xB0,
|
||||
// '<'
|
||||
0x3C,0x05,0x0F,0x0D,0x03,0x14,
|
||||
0x00,0x02,0x00,0x3C,0x03,0xF0,0x3F,0x01,0xF8,0x1F,0x80,0x3C,0x00,0x7E,0x00,0x1F,0x80,0x0F,0xC0,0x03,0xF0,0x00,0xF0,0x00,0x20,
|
||||
// '='
|
||||
0x3D,0x08,0x0F,0x07,0x03,0x14,
|
||||
0xFF,0xFF,0xFF,0xFC,0x00,0x00,0x00,0x00,0x00,0x1F,0xFF,0xFF,0xFF,0x80,
|
||||
// '>'
|
||||
0x3E,0x05,0x0F,0x0D,0x03,0x14,
|
||||
0x80,0x01,0xE0,0x01,0xF8,0x00,0x7E,0x00,0x3F,0x00,0x0F,0xC0,0x07,0x80,0x3F,0x03,0xF0,0x1F,0x81,0xF8,0x07,0x80,0x08,0x00,0x00,
|
||||
// '?'
|
||||
0x3F,0x01,0x09,0x12,0x02,0x0D,
|
||||
0x3E,0x3F,0xB0,0xF0,0x30,0x18,0x0C,0x0C,0x0E,0x0E,0x0E,0x06,0x03,0x01,0x80,0x00,0x00,0x30,0x18,0x0C,0x00,
|
||||
// '@'
|
||||
0x40,0x02,0x15,0x15,0x02,0x18,
|
||||
0x00,0xFC,0x00,0x3F,0xF8,0x03,0xC0,0xF0,0x38,0x01,0xC3,0x80,0x07,0x38,0x79,0x99,0x8F,0xEC,0xFC,0x71,0xE3,0xC7,0x07,0x1E,0x30,0x18,0xF1,0x80,0xC7,0x8C,0x06,0x3C,0x70,0x73,0x71,0xC7,0xB9,0x8F,0xEF,0x8E,0x1E,0x70,0x38,0x00,0x00,0xE0,0x04,0x03,0xC0,0xE0,0x0F,0xFE,0x00,0x0F,0x80,0x00,
|
||||
// 'A'
|
||||
0x41,0x01,0x10,0x12,0x00,0x10,
|
||||
0x03,0xC0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x38,0x1C,0x3F,0xFC,0x3F,0xFC,0x60,0x06,0x60,0x06,0x60,0x06,0xC0,0x03,
|
||||
// 'B'
|
||||
0x42,0x01,0x0C,0x12,0x02,0x10,
|
||||
0xFF,0x0F,0xFC,0xC0,0xEC,0x06,0xC0,0x6C,0x06,0xC0,0x6C,0x0C,0xFF,0x8F,0xFC,0xC0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x06,0xFF,0xEF,0xF8,
|
||||
// 'C'
|
||||
0x43,0x01,0x0E,0x12,0x01,0x11,
|
||||
0x07,0xE0,0x7F,0xE3,0xC1,0xDC,0x01,0x60,0x01,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0x60,0x01,0x80,0x07,0x00,0x4F,0x07,0x1F,0xF8,0x1F,0x80,
|
||||
// 'D'
|
||||
0x44,0x01,0x0F,0x12,0x02,0x12,
|
||||
0xFF,0x81,0xFF,0xE3,0x01,0xE6,0x00,0xEC,0x00,0xD8,0x01,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0xF8,0x01,0xB0,0x07,0x60,0x3C,0xFF,0xF1,0xFF,0x00,
|
||||
// 'E'
|
||||
0x45,0x01,0x0B,0x12,0x02,0x0F,
|
||||
0xFF,0xFF,0xFF,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xDF,0xFB,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC,
|
||||
// 'F'
|
||||
0x46,0x01,0x0A,0x12,0x02,0x0E,
|
||||
0xFF,0xFF,0xFC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xFF,0xBF,0xEC,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x00,
|
||||
// 'G'
|
||||
0x47,0x01,0x0F,0x12,0x01,0x13,
|
||||
0x07,0xE0,0x3F,0xF0,0xE0,0x73,0x80,0x26,0x00,0x1C,0x00,0x30,0x00,0x60,0x00,0xC0,0x7F,0x80,0xFF,0x00,0x1E,0x00,0x36,0x00,0x6C,0x00,0xDC,0x01,0x9E,0x07,0x1F,0xFC,0x0F,0xE0,
|
||||
// 'H'
|
||||
0x48,0x01,0x0D,0x12,0x02,0x12,
|
||||
0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xFF,0xFF,0xFF,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xC0,
|
||||
// 'I'
|
||||
0x49,0x01,0x02,0x12,0x02,0x07,
|
||||
0xFF,0xFF,0xFF,0xFF,0xF0,
|
||||
// 'J'
|
||||
0x4A,0x01,0x06,0x17,0xFE,0x07,
|
||||
0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x1B,0xEF,0x00,
|
||||
// 'K'
|
||||
0x4B,0x01,0x0F,0x12,0x02,0x10,
|
||||
0xC0,0x71,0x81,0xC3,0x07,0x06,0x1C,0x0C,0x70,0x19,0xC0,0x37,0x00,0x7C,0x00,0xF8,0x01,0xB0,0x03,0x38,0x06,0x38,0x0C,0x38,0x18,0x38,0x30,0x38,0x60,0x38,0xC0,0x39,0x80,0x38,
|
||||
// 'L'
|
||||
0x4C,0x01,0x0B,0x12,0x02,0x0D,
|
||||
0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xFF,0xFC,
|
||||
// 'M'
|
||||
0x4D,0x01,0x10,0x12,0x02,0x15,
|
||||
0xE0,0x07,0xF0,0x0F,0xF0,0x0F,0xF8,0x1F,0xD8,0x1B,0xD8,0x1B,0xCC,0x33,0xCC,0x33,0xCC,0x33,0xC6,0x63,0xC6,0x63,0xC7,0xE3,0xC3,0xC3,0xC3,0xC3,0xC1,0x83,0xC0,0x03,0xC0,0x03,0xC0,0x03,
|
||||
// 'N'
|
||||
0x4E,0x01,0x0D,0x12,0x02,0x12,
|
||||
0xE0,0x1F,0x80,0xFC,0x07,0xF0,0x3D,0x81,0xE6,0x0F,0x30,0x78,0xC3,0xC6,0x1E,0x18,0xF0,0xC7,0x83,0x3C,0x19,0xE0,0x6F,0x03,0x78,0x0F,0xC0,0x7E,0x01,0xC0,
|
||||
// 'O'
|
||||
0x4F,0x01,0x10,0x12,0x01,0x13,
|
||||
0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x06,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xE0,
|
||||
// 'P'
|
||||
0x50,0x01,0x0B,0x12,0x02,0x0E,
|
||||
0xFF,0x1F,0xFB,0x07,0x60,0x3C,0x07,0x80,0xF0,0x1E,0x0E,0xFF,0xDF,0xE3,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00,
|
||||
// 'Q'
|
||||
0x51,0x01,0x10,0x15,0x01,0x13,
|
||||
0x07,0xE0,0x1F,0xF8,0x3C,0x3C,0x70,0x0E,0x60,0x06,0x60,0x06,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x60,0x07,0x60,0x06,0x70,0x0E,0x3C,0x3C,0x1F,0xF8,0x07,0xF0,0x00,0x38,0x00,0x18,0x00,0x0C,
|
||||
// 'R'
|
||||
0x52,0x01,0x0D,0x12,0x02,0x11,
|
||||
0xFF,0x07,0xFE,0x30,0x31,0x80,0xCC,0x06,0x60,0x33,0x01,0x98,0x18,0xFF,0xC7,0xFC,0x30,0x71,0x81,0x8C,0x06,0x60,0x33,0x01,0xD8,0x06,0xC0,0x36,0x00,0xC0,
|
||||
// 'S'
|
||||
0x53,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0x1F,0x87,0xFE,0x70,0x6C,0x00,0xC0,0x0C,0x00,0xC0,0x07,0x00,0x7F,0x01,0xFC,0x00,0xE0,0x07,0x00,0x30,0x03,0x00,0x3C,0x0E,0xFF,0xE3,0xF8,
|
||||
// 'T'
|
||||
0x54,0x01,0x0E,0x12,0x00,0x0F,
|
||||
0xFF,0xFF,0xFF,0xF0,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,
|
||||
// 'U'
|
||||
0x55,0x01,0x0D,0x12,0x02,0x12,
|
||||
0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x0D,0x80,0xCE,0x0E,0x3F,0xE0,0x7C,0x00,
|
||||
// 'V'
|
||||
0x56,0x01,0x10,0x12,0x00,0x10,
|
||||
0xC0,0x03,0x60,0x06,0x60,0x06,0x60,0x06,0x30,0x0C,0x30,0x0C,0x38,0x1C,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x07,0x60,0x03,0xC0,0x03,0xC0,0x03,0xC0,
|
||||
// 'W'
|
||||
0x57,0x01,0x16,0x12,0x01,0x18,
|
||||
0xC0,0x78,0x0F,0x01,0xE0,0x36,0x07,0x81,0x98,0x1E,0x06,0x60,0xEC,0x19,0x83,0x30,0x63,0x0C,0xC3,0x0C,0x33,0x0C,0x30,0xCE,0x30,0xC6,0x18,0xC1,0x98,0x66,0x06,0x61,0x98,0x19,0x86,0x60,0x6C,0x0D,0x80,0xF0,0x3C,0x03,0xC0,0xF0,0x0F,0x03,0xC0,0x38,0x07,0x00,
|
||||
// 'X'
|
||||
0x58,0x01,0x0F,0x12,0x01,0x11,
|
||||
0x70,0x0E,0x60,0x18,0x60,0x60,0xE1,0xC0,0xC7,0x00,0xCC,0x01,0xF0,0x01,0xE0,0x03,0x80,0x07,0x80,0x1F,0x00,0x37,0x00,0xC6,0x03,0x86,0x0E,0x0E,0x18,0x0C,0x60,0x0D,0xC0,0x1C,
|
||||
// 'Y'
|
||||
0x59,0x01,0x0E,0x12,0x00,0x0F,
|
||||
0xE0,0x1D,0x80,0x63,0x03,0x0E,0x1C,0x18,0x60,0x33,0x00,0xFC,0x01,0xE0,0x07,0x80,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x01,0x0E,0x12,0x01,0x10,
|
||||
0xFF,0xFF,0xFF,0xF0,0x01,0x80,0x0E,0x00,0x70,0x01,0x80,0x0C,0x00,0x60,0x03,0x80,0x1C,0x00,0x60,0x03,0x00,0x18,0x00,0xE0,0x07,0x00,0x18,0x00,0xFF,0xFF,0xFF,0xF0,
|
||||
// '['
|
||||
0x5B,0x01,0x05,0x15,0x02,0x09,
|
||||
0xFF,0xF1,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0xFF,0x80,
|
||||
// '\'
|
||||
0x5C,0x01,0x08,0x14,0x00,0x08,
|
||||
0xC0,0xE0,0x60,0x60,0x60,0x30,0x30,0x30,0x18,0x18,0x18,0x18,0x0C,0x0C,0x0C,0x06,0x06,0x06,0x07,0x03,
|
||||
// ']'
|
||||
0x5D,0x01,0x05,0x15,0x02,0x09,
|
||||
0xFF,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC7,0xFF,0x80,
|
||||
// '^'
|
||||
0x5E,0x01,0x0F,0x07,0x03,0x14,
|
||||
0x03,0x80,0x0F,0x80,0x3B,0x80,0xE3,0x83,0x83,0x8E,0x03,0xB8,0x03,0x80,
|
||||
// '_'
|
||||
0x5F,0x17,0x0C,0x02,0x00,0x0C,
|
||||
0xFF,0xFF,0xFF,
|
||||
// '`'
|
||||
0x60,0x00,0x06,0x04,0x02,0x0C,
|
||||
0x60,0xC1,0x83,
|
||||
// 'a'
|
||||
0x61,0x06,0x0B,0x0D,0x01,0x0E,
|
||||
0x3F,0x0F,0xF9,0x03,0x00,0x30,0x06,0x3F,0xDF,0xFF,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6,
|
||||
// 'b'
|
||||
0x62,0x01,0x0C,0x12,0x02,0x0F,
|
||||
0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0xF8,0xFF,0xCF,0x0E,0xE0,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xE0,0x6F,0x0E,0xFF,0xCC,0xF8,
|
||||
// 'c'
|
||||
0x63,0x06,0x0A,0x0D,0x01,0x0D,
|
||||
0x0F,0x8F,0xF7,0x05,0x80,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x18,0x07,0x04,0xFF,0x0F,0x80,
|
||||
// 'd'
|
||||
0x64,0x01,0x0C,0x12,0x01,0x0F,
|
||||
0x00,0x30,0x03,0x00,0x30,0x03,0x00,0x31,0xF3,0x3F,0xF7,0x0F,0x60,0x7C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0F,0x3F,0xF1,0xF3,
|
||||
// 'e'
|
||||
0x65,0x06,0x0C,0x0D,0x01,0x0E,
|
||||
0x0F,0x83,0xFC,0x70,0xE6,0x07,0xC0,0x3F,0xFF,0xFF,0xFC,0x00,0xC0,0x06,0x00,0x70,0x23,0xFE,0x0F,0xC0,
|
||||
// 'f'
|
||||
0x66,0x01,0x08,0x12,0x01,0x08,
|
||||
0x0F,0x1F,0x38,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,
|
||||
// 'g'
|
||||
0x67,0x06,0x0C,0x12,0x01,0x0F,
|
||||
0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x72,0x0E,0x3F,0xC1,0xF8,
|
||||
// 'h'
|
||||
0x68,0x01,0x0B,0x12,0x02,0x0F,
|
||||
0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x9F,0x3F,0xF7,0x87,0xE0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0C,
|
||||
// 'i'
|
||||
0x69,0x01,0x02,0x12,0x02,0x07,
|
||||
0xFC,0x3F,0xFF,0xFF,0xF0,
|
||||
// 'j'
|
||||
0x6A,0x01,0x05,0x17,0xFF,0x07,
|
||||
0x18,0xC6,0x00,0x0C,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x33,0xFB,0x80,
|
||||
// 'k'
|
||||
0x6B,0x01,0x0C,0x12,0x02,0x0E,
|
||||
0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x1C,0xC3,0x8C,0x70,0xCE,0x0D,0xC0,0xF8,0x0F,0x80,0xDC,0x0C,0xE0,0xC7,0x0C,0x38,0xC1,0xCC,0x0E,
|
||||
// 'l'
|
||||
0x6C,0x01,0x02,0x12,0x02,0x06,
|
||||
0xFF,0xFF,0xFF,0xFF,0xF0,
|
||||
// 'm'
|
||||
0x6D,0x06,0x14,0x0D,0x02,0x18,
|
||||
0xCF,0x87,0xCF,0xFC,0xFE,0xF0,0xF8,0x7E,0x07,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x3C,0x06,0x03,0xC0,0x60,0x30,
|
||||
// 'n'
|
||||
0x6E,0x06,0x0B,0x0D,0x02,0x0F,
|
||||
0xCF,0x9F,0xFB,0xC3,0xF0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x06,
|
||||
// 'o'
|
||||
0x6F,0x06,0x0C,0x0D,0x01,0x0E,
|
||||
0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,
|
||||
// 'p'
|
||||
0x70,0x06,0x0C,0x12,0x02,0x0F,
|
||||
0xCF,0x8F,0xFC,0xF0,0xEE,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x3E,0x06,0xF0,0xEF,0xFC,0xCF,0x8C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,
|
||||
// 'q'
|
||||
0x71,0x06,0x0C,0x12,0x01,0x0F,
|
||||
0x1F,0x33,0xFF,0x70,0xF6,0x07,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x07,0x70,0xF3,0xFF,0x1F,0x30,0x03,0x00,0x30,0x03,0x00,0x30,0x03,
|
||||
// 'r'
|
||||
0x72,0x06,0x08,0x0D,0x02,0x0A,
|
||||
0xCF,0xFF,0xF0,0xE0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
// 's'
|
||||
0x73,0x06,0x0B,0x0D,0x01,0x0C,
|
||||
0x3F,0x0F,0xF3,0x82,0x60,0x0C,0x00,0xF0,0x0F,0xC0,0x3C,0x00,0xC0,0x1A,0x07,0x7F,0xC7,0xF0,
|
||||
// 't'
|
||||
0x74,0x02,0x08,0x11,0x00,0x09,
|
||||
0x30,0x30,0x30,0x30,0xFF,0xFF,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x1F,0x0F,
|
||||
// 'u'
|
||||
0x75,0x06,0x0B,0x0D,0x02,0x0F,
|
||||
0xC0,0x78,0x0F,0x01,0xE0,0x3C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1F,0x87,0xBF,0xF3,0xE6,
|
||||
// 'v'
|
||||
0x76,0x06,0x0D,0x0D,0x01,0x0F,
|
||||
0xC0,0x1B,0x01,0x98,0x0C,0xC0,0x63,0x06,0x18,0x30,0x63,0x03,0x18,0x18,0xC0,0x6C,0x03,0x60,0x1F,0x00,0x70,0x00,
|
||||
// 'w'
|
||||
0x77,0x06,0x12,0x0D,0x01,0x14,
|
||||
0xC1,0xE0,0xF0,0x78,0x36,0x1E,0x19,0x87,0x86,0x63,0x31,0x9C,0xCC,0xE3,0x33,0x30,0xCC,0xCC,0x36,0x1B,0x07,0x87,0x81,0xE1,0xE0,0x78,0x78,0x1C,0x0E,0x00,
|
||||
// 'x'
|
||||
0x78,0x06,0x0D,0x0D,0x01,0x0F,
|
||||
0xE0,0x3B,0x83,0x8E,0x38,0x31,0x80,0xD8,0x07,0xC0,0x1C,0x01,0xF0,0x1D,0xC0,0xC6,0x0C,0x18,0xE0,0xEE,0x03,0x80,
|
||||
// 'y'
|
||||
0x79,0x06,0x0D,0x12,0x01,0x0F,
|
||||
0xC0,0x1B,0x01,0x98,0x0C,0xE0,0xE3,0x06,0x18,0x70,0x63,0x03,0x18,0x0D,0x80,0x6C,0x03,0xE0,0x0E,0x00,0x70,0x03,0x00,0x18,0x01,0x80,0x7C,0x03,0xC0,0x00,
|
||||
// 'z'
|
||||
0x7A,0x06,0x0B,0x0D,0x01,0x0D,
|
||||
0xFF,0xFF,0xFC,0x03,0x00,0xE0,0x38,0x0E,0x03,0x80,0xE0,0x38,0x0E,0x01,0x80,0x7F,0xFF,0xFE,
|
||||
// '{'
|
||||
0x7B,0x01,0x09,0x16,0x03,0x0F,
|
||||
0x03,0x83,0xC3,0x81,0x80,0xC0,0x60,0x30,0x18,0x0C,0x0E,0x3E,0x1F,0x01,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0xC0,0x78,0x1C,
|
||||
// '|'
|
||||
0x7C,0x01,0x02,0x18,0x03,0x08,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
// '}'
|
||||
0x7D,0x01,0x09,0x16,0x03,0x0F,
|
||||
0xE0,0x78,0x0E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0E,0x03,0xE1,0xF1,0xC0,0xC0,0x60,0x30,0x18,0x0C,0x06,0x07,0x0F,0x07,0x00,
|
||||
// '~'
|
||||
0x7E,0x09,0x0F,0x05,0x03,0x14,
|
||||
0x00,0x00,0x7C,0x05,0xFE,0x1E,0x1F,0xE0,0x0F,0x80,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
2322
components/epaper/EPD.c
Normal file
2322
components/epaper/EPD.c
Normal file
File diff suppressed because it is too large
Load Diff
571
components/epaper/EPD.h
Normal file
571
components/epaper/EPD.h
Normal file
@ -0,0 +1,571 @@
|
||||
/*
|
||||
* High level EPD functions
|
||||
* Author: LoBo 06/2017, https://github/loboris
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _EPD_H_
|
||||
#define _EPD_H_
|
||||
|
||||
#include <stdlib.h>
|
||||
#include "EPDspi.h"
|
||||
|
||||
typedef uint8_t color_t;
|
||||
|
||||
typedef struct {
|
||||
uint16_t x1;
|
||||
uint16_t y1;
|
||||
uint16_t x2;
|
||||
uint16_t y2;
|
||||
} dispWin_t;
|
||||
|
||||
typedef struct {
|
||||
uint8_t *font;
|
||||
uint8_t x_size;
|
||||
uint8_t y_size;
|
||||
uint8_t offset;
|
||||
uint16_t numchars;
|
||||
uint16_t size;
|
||||
uint8_t max_x_size;
|
||||
uint8_t bitmap;
|
||||
color_t color;
|
||||
} Font_t;
|
||||
|
||||
|
||||
|
||||
//==========================================================================================
|
||||
// ==== Global variables ===================================================================
|
||||
//==========================================================================================
|
||||
uint8_t orientation; // current screen orientation
|
||||
uint16_t font_rotate; // current font font_rotate angle (0~395)
|
||||
uint8_t font_transparent; // if not 0 draw fonts transparent
|
||||
uint8_t font_forceFixed; // if not zero force drawing proportional fonts with fixed width
|
||||
uint8_t font_buffered_char;
|
||||
uint8_t font_line_space; // additional spacing between text lines; added to font height
|
||||
uint8_t text_wrap; // if not 0 wrap long text to the new line, else clip
|
||||
color_t _fg; // current foreground color for fonts
|
||||
color_t _bg; // current background for non transparent fonts
|
||||
dispWin_t dispWin; // display clip window
|
||||
float _angleOffset; // angle offset for arc, polygon and line by angle functions
|
||||
|
||||
Font_t cfont; // Current font structure
|
||||
uint8_t image_debug;
|
||||
|
||||
int EPD_X; // X position of the next character after EPD_print() function
|
||||
int EPD_Y; // Y position of the next character after EPD_print() function
|
||||
// =========================================================================================
|
||||
|
||||
|
||||
// Buffer is created during jpeg decode for sending data
|
||||
// Total size of the buffer is 2 * (JPG_IMAGE_LINE_BUF_SIZE * 3)
|
||||
// The size must be multiple of 256 bytes !!
|
||||
#define JPG_IMAGE_LINE_BUF_SIZE 512
|
||||
|
||||
// --- Constants for ellipse function ---
|
||||
#define EPD_ELLIPSE_UPPER_RIGHT 0x01
|
||||
#define EPD_ELLIPSE_UPPER_LEFT 0x02
|
||||
#define EPD_ELLIPSE_LOWER_LEFT 0x04
|
||||
#define EPD_ELLIPSE_LOWER_RIGHT 0x08
|
||||
|
||||
// Constants for Arc function
|
||||
// number representing the maximum angle (e.g. if 100, then if you pass in start=0 and end=50, you get a half circle)
|
||||
// this can be changed with setArcParams function at runtime
|
||||
#define DEFAULT_ARC_ANGLE_MAX 360
|
||||
// rotational offset in degrees defining position of value 0 (-90 will put it at the top of circle)
|
||||
// this can be changed with setAngleOffset function at runtime
|
||||
#define DEFAULT_ANGLE_OFFSET -90
|
||||
|
||||
#define PI 3.14159265359
|
||||
|
||||
#define MIN_POLIGON_SIDES 3
|
||||
#define MAX_POLIGON_SIDES 60
|
||||
|
||||
// === Color names constants ===
|
||||
#define EPD_BLACK 15
|
||||
#define EPD_WHITE 0
|
||||
|
||||
// === Color invert constants ===
|
||||
#define INVERT_ON 1
|
||||
#define INVERT_OFF 0
|
||||
|
||||
// === Screen orientation constants ===
|
||||
#define LANDSCAPE_0 1
|
||||
#define LANDSCAPE_180 2
|
||||
|
||||
// === Special coordinates constants ===
|
||||
#define CENTER -9003
|
||||
#define RIGHT -9004
|
||||
#define BOTTOM -9004
|
||||
|
||||
#define LASTX 7000
|
||||
#define LASTY 8000
|
||||
|
||||
// === Embedded fonts constants ===
|
||||
#define DEFAULT_FONT 0
|
||||
#define DEJAVU18_FONT 1
|
||||
#define DEJAVU24_FONT 2
|
||||
#define UBUNTU16_FONT 3
|
||||
#define COMIC24_FONT 4
|
||||
#define MINYA24_FONT 5
|
||||
#define TOONEY32_FONT 6
|
||||
#define SMALL_FONT 7
|
||||
#define FONT_7SEG 8
|
||||
#define USER_FONT 9 // font will be read from file
|
||||
|
||||
|
||||
|
||||
// ===== PUBLIC FUNCTIONS =========================================================================
|
||||
|
||||
/*
|
||||
* Draw pixel at given x,y coordinates
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal position
|
||||
* y: vertical position
|
||||
* color: pixel color
|
||||
*/
|
||||
//------------------------------------------------------
|
||||
void EPD_drawPixel(int16_t x, int16_t y, color_t color);
|
||||
|
||||
/*
|
||||
* Read pixel color value from display GRAM at given x,y coordinates
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal position
|
||||
* y: vertical position
|
||||
*
|
||||
* Returns:
|
||||
* pixel color at x,y
|
||||
*/
|
||||
//------------------------------------------
|
||||
color_t EPD_readPixel(int16_t x, int16_t y);
|
||||
|
||||
/*
|
||||
* Draw vertical line at given x,y coordinates
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal start position
|
||||
* y: vertical start position
|
||||
* h: line height in pixels
|
||||
* color: line color
|
||||
*/
|
||||
//---------------------------------------------------------------------
|
||||
void EPD_drawFastVLine(int16_t x, int16_t y, int16_t h, color_t color);
|
||||
|
||||
/*
|
||||
* Draw horizontal line at given x,y coordinates
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal start position
|
||||
* y: vertical start position
|
||||
* w: line width in pixels
|
||||
* color: line color
|
||||
*/
|
||||
//---------------------------------------------------------------------
|
||||
void EPD_drawFastHLine(int16_t x, int16_t y, int16_t w, color_t color);
|
||||
|
||||
/*
|
||||
* Draw line on screen
|
||||
*
|
||||
* Params:
|
||||
* x0: horizontal start position
|
||||
* y0: vertical start position
|
||||
* x1: horizontal end position
|
||||
* y1: vertical end position
|
||||
* color: line color
|
||||
*/
|
||||
//-------------------------------------------------------------------------------
|
||||
void EPD_drawLine(int16_t x0, int16_t y0, int16_t x1, int16_t y1, color_t color);
|
||||
|
||||
|
||||
/*
|
||||
* Draw line on screen from (x,y) point at given angle
|
||||
* Line drawing angle starts at lower right quadrant of the screen and is offseted by
|
||||
* '_angleOffset' global variable (default: -90 degrees)
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal start position
|
||||
* y: vertical start position
|
||||
* start: start offset from (x,y)
|
||||
* len: length of the line
|
||||
* angle: line angle in degrees
|
||||
* color: line color
|
||||
*/
|
||||
//-----------------------------------------------------------------------------------------------------------
|
||||
void EPD_drawLineByAngle(uint16_t x, uint16_t y, uint16_t start, uint16_t len, uint16_t angle, color_t color);
|
||||
|
||||
/*
|
||||
* Fill given rectangular screen region with color
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal rect start position
|
||||
* y: vertical rect start position
|
||||
* w: rectangle width
|
||||
* h: rectangle height
|
||||
* color: fill color
|
||||
*/
|
||||
//---------------------------------------------------------------------------
|
||||
void EPD_fillRect(int16_t x, int16_t y, int16_t w, int16_t h, color_t color);
|
||||
|
||||
/*
|
||||
* Draw rectangle on screen
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal rect start position
|
||||
* y: vertical rect start position
|
||||
* w: rectangle width
|
||||
* h: rectangle height
|
||||
* color: rect line color
|
||||
*/
|
||||
//------------------------------------------------------------------------------
|
||||
void EPD_drawRect(uint16_t x1,uint16_t y1,uint16_t w,uint16_t h, color_t color);
|
||||
|
||||
/*
|
||||
* Draw rectangle with rounded corners on screen
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal rect start position
|
||||
* y: vertical rect start position
|
||||
* w: rectangle width
|
||||
* h: rectangle height
|
||||
* r: corner radius
|
||||
* color: rectangle color
|
||||
*/
|
||||
//----------------------------------------------------------------------------------------------
|
||||
void EPD_drawRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color);
|
||||
|
||||
/*
|
||||
* Fill given rectangular screen region with rounded corners with color
|
||||
*
|
||||
* Params:
|
||||
* x: horizontal rect start position
|
||||
* y: vertical rect start position
|
||||
* w: rectangle width
|
||||
* h: rectangle height
|
||||
* r: corner radius
|
||||
* color: fill color
|
||||
*/
|
||||
//----------------------------------------------------------------------------------------------
|
||||
void EPD_fillRoundRect(int16_t x, int16_t y, uint16_t w, uint16_t h, uint16_t r, color_t color);
|
||||
|
||||
/*
|
||||
* Fill the whole screen with color
|
||||
*
|
||||
* Params:
|
||||
* color: fill color
|
||||
*/
|
||||
//--------------------------------
|
||||
void EPD_fillScreen(color_t color);
|
||||
|
||||
/*
|
||||
* Fill the current clip window with color
|
||||
*
|
||||
* Params:
|
||||
* color: fill color
|
||||
*/
|
||||
//---------------------------------
|
||||
void EPD_fillWindow(color_t color);
|
||||
|
||||
/*
|
||||
* Draw triangle on screen
|
||||
*
|
||||
* Params:
|
||||
* x0: first triangle point x position
|
||||
* y0: first triangle point y position
|
||||
* x0: second triangle point x position
|
||||
* y0: second triangle point y position
|
||||
* x0: third triangle point x position
|
||||
* y0: third triangle point y position
|
||||
* color: triangle color
|
||||
*/
|
||||
//-----------------------------------------------------------------------------------------------------------------
|
||||
void EPD_drawTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color);
|
||||
|
||||
/*
|
||||
* Fill triangular screen region with color
|
||||
*
|
||||
* Params:
|
||||
* x0: first triangle point x position
|
||||
* y0: first triangle point y position
|
||||
* x0: second triangle point x position
|
||||
* y0: second triangle point y position
|
||||
* x0: third triangle point x position
|
||||
* y0: third triangle point y position
|
||||
* color: fill color
|
||||
*/
|
||||
//-----------------------------------------------------------------------------------------------------------------
|
||||
void EPD_fillTriangle(uint16_t x0, uint16_t y0, uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2, color_t color);
|
||||
|
||||
/*
|
||||
* Draw circle on screen
|
||||
*
|
||||
* Params:
|
||||
* x: circle center x position
|
||||
* y: circle center x position
|
||||
* r: circle radius
|
||||
* color: circle color
|
||||
*/
|
||||
//-------------------------------------------------------------------
|
||||
void EPD_drawCircle(int16_t x, int16_t y, int radius, color_t color);
|
||||
|
||||
/*
|
||||
* Fill circle on screen with color
|
||||
*
|
||||
* Params:
|
||||
* x: circle center x position
|
||||
* y: circle center x position
|
||||
* r: circle radius
|
||||
* color: circle fill color
|
||||
*/
|
||||
//-------------------------------------------------------------------
|
||||
void EPD_fillCircle(int16_t x, int16_t y, int radius, color_t color);
|
||||
|
||||
/*
|
||||
* Draw ellipse on screen
|
||||
*
|
||||
* Params:
|
||||
* x0: ellipse center x position
|
||||
* y0: ellipse center x position
|
||||
* rx: ellipse horizontal radius
|
||||
* ry: ellipse vertical radius
|
||||
* option: drawing options, multiple options can be combined
|
||||
1 (TFT_ELLIPSE_UPPER_RIGHT) draw upper right corner
|
||||
2 (TFT_ELLIPSE_UPPER_LEFT) draw upper left corner
|
||||
4 (TFT_ELLIPSE_LOWER_LEFT) draw lower left corner
|
||||
8 (TFT_ELLIPSE_LOWER_RIGHT) draw lower right corner
|
||||
to draw the whole ellipse use option value 15 (1 | 2 | 4 | 8)
|
||||
*
|
||||
* color: circle color
|
||||
*/
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
void EPD_drawEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option);
|
||||
|
||||
/*
|
||||
* Fill elliptical region on screen
|
||||
*
|
||||
* Params:
|
||||
* x0: ellipse center x position
|
||||
* y0: ellipse center x position
|
||||
* rx: ellipse horizontal radius
|
||||
* ry: ellipse vertical radius
|
||||
* option: drawing options, multiple options can be combined
|
||||
1 (TFT_ELLIPSE_UPPER_RIGHT) fill upper right corner
|
||||
2 (TFT_ELLIPSE_UPPER_LEFT) fill upper left corner
|
||||
4 (TFT_ELLIPSE_LOWER_LEFT) fill lower left corner
|
||||
8 (TFT_ELLIPSE_LOWER_RIGHT) fill lower right corner
|
||||
to fill the whole ellipse use option value 15 (1 | 2 | 4 | 8)
|
||||
*
|
||||
* color: fill color
|
||||
*/
|
||||
//------------------------------------------------------------------------------------------------------
|
||||
void EPD_fillEllipse(uint16_t x0, uint16_t y0, uint16_t rx, uint16_t ry, color_t color, uint8_t option);
|
||||
|
||||
|
||||
/*
|
||||
* Draw circle arc on screen
|
||||
* Arc drawing angle starts at lower right quadrant of the screen and is offseted by
|
||||
* '_angleOffset' global variable (default: -90 degrees)
|
||||
*
|
||||
* Params:
|
||||
* cx: arc center X position
|
||||
* cy: arc center Y position
|
||||
* th: thickness of the drawn arc
|
||||
* ry: arc vertical radius
|
||||
* start: arc start angle in degrees
|
||||
* end: arc end angle in degrees
|
||||
* color: arc outline color
|
||||
* fillcolor: arc fill color
|
||||
*/
|
||||
//----------------------------------------------------------------------------------------------------------------------------
|
||||
void EPD_drawArc(uint16_t cx, uint16_t cy, uint16_t r, uint16_t th, float start, float end, color_t color, color_t fillcolor);
|
||||
|
||||
|
||||
/*
|
||||
* Draw polygon on screen
|
||||
*
|
||||
* Params:
|
||||
* cx: polygon center X position
|
||||
* cy: arc center Y position
|
||||
* sides: number of polygon sides; MAX_POLIGON_SIDES ~ MAX_POLIGON_SIDES (3 ~ 60)
|
||||
* diameter: diameter of the circle inside which the polygon is drawn
|
||||
* color: polygon outline color
|
||||
* fill: polygon fill color; if same as color, polygon is not filled
|
||||
* deg: polygon rotation angle; 0 ~ 360
|
||||
* th: thickness of the polygon outline
|
||||
*/
|
||||
//--------------------------------------------------------------------------------------------------------------
|
||||
void EPD_drawPolygon(int cx, int cy, int sides, int diameter, color_t color, color_t fill, int deg, uint8_t th);
|
||||
|
||||
|
||||
//--------------------------------------------------------------------------------------
|
||||
//void EPD_drawStar(int cx, int cy, int diameter, color_t color, bool fill, float factor);
|
||||
|
||||
|
||||
/*
|
||||
* Set the font used for writing the text to display.
|
||||
*
|
||||
* ------------------------------------------------------------------------------------
|
||||
* For 7 segment font only characters 0,1,2,3,4,5,6,7,8,9, . , - , : , / are available.
|
||||
* Character ‘/‘ draws the degree sign.
|
||||
* ------------------------------------------------------------------------------------
|
||||
*
|
||||
* Params:
|
||||
* font: font number; use defined font names
|
||||
* font_file: pointer to font file name; NULL for embeded fonts
|
||||
*/
|
||||
//----------------------------------------------------
|
||||
void EPD_setFont(uint8_t font, const char *font_file);
|
||||
|
||||
/*
|
||||
* Returns current font height & width in pixels.
|
||||
*
|
||||
* Params:
|
||||
* width: pointer to returned font width
|
||||
* height: pointer to returned font height
|
||||
*/
|
||||
//-------------------------------------------
|
||||
int EPD_getfontsize(int *width, int* height);
|
||||
|
||||
|
||||
/*
|
||||
* Returns current font height in pixels.
|
||||
*
|
||||
*/
|
||||
//----------------------
|
||||
int EPD_getfontheight();
|
||||
|
||||
/*
|
||||
* Write text to display.
|
||||
*
|
||||
* Rotation of the displayed text depends on 'font_rotate' variable (0~360)
|
||||
* if 'font_transparent' variable is set to 1, no background pixels will be printed
|
||||
*
|
||||
* If the text does not fit the screen width it will be clipped (if text_wrap=0),
|
||||
* or continued on next line (if text_wrap=1)
|
||||
*
|
||||
* Two special characters are allowed in strings:
|
||||
* ‘\r’ CR (0x0D), clears the display to EOL
|
||||
* ‘\n’ LF (ox0A), continues to the new line, x=0
|
||||
*
|
||||
* Params:
|
||||
* st: pointer to null terminated string to be printed
|
||||
* x: horizontal position of the upper left point in pixels
|
||||
* Special values can be entered:
|
||||
* CENTER, centers the text
|
||||
* RIGHT, right justifies the text
|
||||
* LASTX, continues from last X position; offset can be used: LASTX+n
|
||||
* y: vertical position of the upper left point in pixels
|
||||
* Special values can be entered:
|
||||
* CENTER, centers the text
|
||||
* BOTTOM, bottom justifies the text
|
||||
* LASTY, continues from last Y position; offset can be used: LASTY+n
|
||||
*
|
||||
*/
|
||||
//-------------------------------------
|
||||
void EPD_print(char *st, int x, int y);
|
||||
|
||||
/*
|
||||
* Set atributes for 7 segment vector font
|
||||
* == 7 segment font must be the current font to this function to have effect ==
|
||||
*
|
||||
* Params:
|
||||
* l: 6~40; distance between bars in pixels
|
||||
* w: 1~12, max l/2; bar width in pixels
|
||||
* outline: draw font outline if set to 1
|
||||
* color: font outline color, only used if outline=1
|
||||
*
|
||||
*/
|
||||
//-------------------------------------------------------------------------
|
||||
void set_7seg_font_atrib(uint8_t l, uint8_t w, int outline, color_t color);
|
||||
|
||||
/*
|
||||
* Sets the clipping area coordinates.
|
||||
* All writing to screen is clipped to that area.
|
||||
* Starting x & y in all functions will be adjusted to the clipping area.
|
||||
*
|
||||
* Params:
|
||||
* x1,y1: upper left point of the clipping area
|
||||
* x2,y2: bottom right point of the clipping area
|
||||
*
|
||||
*/
|
||||
//----------------------------------------------------------------------
|
||||
void EPD_setclipwin(uint16_t x1, uint16_t y1, uint16_t x2, uint16_t y2);
|
||||
|
||||
/*
|
||||
* Resets the clipping area to full screen (0,0),(_wodth,_height)
|
||||
*
|
||||
*/
|
||||
//----------------------
|
||||
void EPD_resetclipwin();
|
||||
|
||||
/*
|
||||
* Save current clipping area to temporary variable
|
||||
*
|
||||
*/
|
||||
//---------------------
|
||||
void EPD_saveClipWin();
|
||||
|
||||
/*
|
||||
* Restore current clipping area from temporary variable
|
||||
*
|
||||
*/
|
||||
//------------------------
|
||||
void EPD_restoreClipWin();
|
||||
|
||||
/*
|
||||
* returns the string width in pixels.
|
||||
* Useful for positions strings on the screen.
|
||||
*/
|
||||
//--------------------------------
|
||||
int EPD_getStringWidth(char* str);
|
||||
|
||||
|
||||
/*
|
||||
* Fills the rectangle occupied by string with current background color
|
||||
*/
|
||||
void EPD_clearStringRect(int x, int y, char *str);
|
||||
|
||||
|
||||
/*
|
||||
* Compile font c source file to .fnt file
|
||||
* which can be used in EPD_setFont() function to select external font
|
||||
* Created file have the same name as source file and extension .fnt
|
||||
*
|
||||
* Params:
|
||||
* fontfile: pointer to c source font file name; must have .c extension
|
||||
* dbg: if set to 1, prints debug information
|
||||
*
|
||||
* Returns:
|
||||
* 0 on success
|
||||
* err no on error
|
||||
*
|
||||
*/
|
||||
//------------------------------------------------
|
||||
int compile_font_file(char *fontfile, uint8_t dbg);
|
||||
|
||||
/*
|
||||
* Get all font's characters to buffer
|
||||
*/
|
||||
void getFontCharacters(uint8_t *buf);
|
||||
|
||||
/*
|
||||
* Decodes and displays JPG image. RGB colors are converted to 4-bit Gray scale
|
||||
* Limits:
|
||||
* Baseline only. Progressive and Lossless JPEG format are not supported.
|
||||
* Image size: Up to 65520 x 65520 pixels
|
||||
* Color space: YCbCr three components only. Gray scale image is not supported.
|
||||
* Sampling factor: 4:4:4, 4:2:2 or 4:2:0.
|
||||
*
|
||||
* Params:
|
||||
* x: image left position; constants CENTER & RIGHT can be used; negative value is accepted
|
||||
* y: image top position; constants CENTER & BOTTOM can be used; negative value is accepted
|
||||
* scale: image scale factor: 0~3; if scale>0, image is scaled by factor 1/(2^scale) (1/2, 1/4 or 1/8)
|
||||
* fname: pointer to the name of the file from which the image will be read
|
||||
* if set to NULL, image will be read from memory buffer pointed to by 'buf'
|
||||
* buf: pointer to the memory buffer from which the image will be read; used if fname=NULL
|
||||
* size: size of the memory buffer from which the image will be read; used if fname=NULL & buf!=NULL
|
||||
*
|
||||
*/
|
||||
int EPD_jpg_image(int x, int y, uint8_t scale, char *fname, uint8_t *buf, int size);
|
||||
|
||||
#endif
|
759
components/epaper/EPDspi.c
Normal file
759
components/epaper/EPDspi.c
Normal file
@ -0,0 +1,759 @@
|
||||
/*
|
||||
* Author: LoBo (loboris@gmail.com, loboris.github)
|
||||
*
|
||||
* Module supporting SPI ePaper displays
|
||||
*
|
||||
* HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS
|
||||
* USING DIRECT or DMA SPI TRANSFER MODEs
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include "spi_master_lobo.h"
|
||||
#include <errno.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <string.h>
|
||||
#include "esp_system.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/task.h"
|
||||
#include "esp_heap_alloc_caps.h"
|
||||
#include "soc/spi_reg.h"
|
||||
#include "EPDspi.h"
|
||||
|
||||
#define EPD_DEBUG 1
|
||||
|
||||
#define EPD2X9 1
|
||||
|
||||
#define xDot 128
|
||||
#define yDot 296
|
||||
#define DELAYTIME 1500
|
||||
|
||||
static uint8_t GDOControl[] = {0x01, (yDot-1)%256, (yDot-1)/256, 0x00};
|
||||
static uint8_t softstart[4] = {0x0c, 0xd7, 0xd6, 0x9d};
|
||||
static uint8_t VCOMVol[2] = {0x2c, 0xa8}; // VCOM 7c
|
||||
static uint8_t DummyLine[2] = {0x3a, 0x1a}; // 4 dummy line per gate
|
||||
static uint8_t Gatetime[2] = {0x3b, 0x08}; // 2us per line
|
||||
static uint8_t RamDataEntryMode[2] = {0x11, 0x01}; // Ram data entry mode
|
||||
static uint8_t Border[2] = {0x3c, 0x61}; // Border control ( 0x61: white border; 0x51: black border
|
||||
|
||||
/*
|
||||
There are totally 20 phases for programmable Source waveform of different phase length.
|
||||
The phase period defined as TP [n] * T FRAME , where TP [n] range from 0 to 15.
|
||||
TP [n] = 0 indicates phase skipped
|
||||
Source Voltage Level: VS [n-XY] is constant in each phase
|
||||
VS [n-XY] indicates the voltage in phase n for transition from GS X to GS Y
|
||||
00 – VSS
|
||||
01 – VSH
|
||||
10 – VSL
|
||||
11 – NA
|
||||
VS [n-XY] and TP[n] are stored in waveform lookup table register [LUT].
|
||||
|
||||
VS coding: VS[0-11] VS[0-10] VS[0-01] VS[0-00]
|
||||
|
||||
*/
|
||||
// --- VS ---- ---- TP ----
|
||||
//uint8_t LUTDefault_full[31] = {0x32, 0x02,0x02,0x01,0x11,0x12,0x12,0x22,0x22,0x66,0x69,0x69,0x59,0x58,0x99,0x99,0x88,0x00,0x00,0x00,0x00, 0xF8,0xB4,0x13,0x51,0x35,0x51,0x51,0x19,0x01,0x00};
|
||||
uint8_t LUTDefault_full[31] = {0x32, 0x11,0x11,0x10,0x02,0x02,0x22,0x22,0x22,0x22,0x22,0x51,0x51,0x55,0x88,0x08,0x08,0x88,0x88,0x00,0x00, 0x34,0x23,0x12,0x21,0x24,0x28,0x22,0x21,0xA1,0x01};
|
||||
uint8_t LUTDefault_part[31] = {0x32, 0x10,0x18,0x18,0x08,0x18,0x18,0x08,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x13,0x14,0x44,0x12,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint8_t LUT_gs[31] = {0x32, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
uint8_t LUTFastest[31] = {0x32, 0x99,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, 0x0f,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
|
||||
|
||||
uint8_t lvl_buf[16] = {32,70,110,150,185,210,220,225,230,235,240,243,248,251,253,255};
|
||||
uint8_t lvl_buf_jpg[16] = {4,8,12,16,22,30,40,60,80,110,140,180,220,240,250,255};
|
||||
|
||||
uint8_t *LUT_part = LUTDefault_part;
|
||||
spi_lobo_device_handle_t disp_spi = NULL;
|
||||
uint8_t *gs_disp_buffer = NULL;
|
||||
uint8_t *disp_buffer = NULL;
|
||||
uint8_t *drawBuff = NULL;
|
||||
uint8_t *gs_drawBuff = NULL;
|
||||
int _width = EPD_DISPLAY_WIDTH;
|
||||
int _height = EPD_DISPLAY_HEIGHT;
|
||||
uint8_t _gs = 0;
|
||||
|
||||
uint16_t gs_used_shades = 0;
|
||||
|
||||
//-----------------------------------------------------------
|
||||
static void IRAM_ATTR _dma_send(uint8_t *data, uint32_t size)
|
||||
{
|
||||
//Fill DMA descriptors
|
||||
spi_lobo_dmaworkaround_transfer_active(disp_spi->host->dma_chan); //mark channel as active
|
||||
spi_lobo_setup_dma_desc_links(disp_spi->host->dmadesc_tx, size, data, false);
|
||||
disp_spi->host->hw->user.usr_mosi_highpart=0;
|
||||
disp_spi->host->hw->dma_out_link.addr=(int)(&disp_spi->host->dmadesc_tx[0]) & 0xFFFFF;
|
||||
disp_spi->host->hw->dma_out_link.start=1;
|
||||
disp_spi->host->hw->user.usr_mosi_highpart=0;
|
||||
|
||||
disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = (size * 8) - 1;
|
||||
|
||||
// Start transfer
|
||||
disp_spi->host->hw->cmd.usr = 1;
|
||||
// Wait for SPI bus ready
|
||||
while (disp_spi->host->hw->cmd.usr);
|
||||
|
||||
//Tell common code DMA workaround that our DMA channel is idle. If needed, the code will do a DMA reset.
|
||||
if (disp_spi->host->dma_chan) spi_lobo_dmaworkaround_idle(disp_spi->host->dma_chan);
|
||||
|
||||
// Reset DMA
|
||||
disp_spi->host->hw->dma_conf.val |= SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST;
|
||||
disp_spi->host->hw->dma_out_link.start=0;
|
||||
disp_spi->host->hw->dma_in_link.start=0;
|
||||
disp_spi->host->hw->dma_conf.val &= ~(SPI_OUT_RST|SPI_IN_RST|SPI_AHBM_RST|SPI_AHBM_FIFO_RST);
|
||||
disp_spi->host->hw->dma_conf.out_data_burst_en=1;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------
|
||||
static void IRAM_ATTR _direct_send(uint8_t *data, uint32_t len, uint8_t rep)
|
||||
{
|
||||
uint32_t cidx = 0; // buffer index
|
||||
uint32_t wd = 0;
|
||||
int idx = 0;
|
||||
int bits = 0;
|
||||
int wbits = 0;
|
||||
|
||||
taskDISABLE_INTERRUPTS();
|
||||
|
||||
while (len) {
|
||||
|
||||
wd |= (uint32_t)data[idx] << wbits;
|
||||
wbits += 8;
|
||||
if (wbits == 32) {
|
||||
bits += wbits;
|
||||
wbits = 0;
|
||||
disp_spi->host->hw->data_buf[idx++] = wd;
|
||||
wd = 0;
|
||||
}
|
||||
len--; // Decrement data counter
|
||||
if (rep == 0) cidx++; // if not repeating data, increment buffer index
|
||||
}
|
||||
if (bits) {
|
||||
while (disp_spi->host->hw->cmd.usr); // Wait for SPI bus ready
|
||||
// Load send buffer
|
||||
disp_spi->host->hw->user.usr_mosi_highpart = 0;
|
||||
disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = bits-1;
|
||||
disp_spi->host->hw->user.usr_mosi = 1;
|
||||
disp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0;
|
||||
disp_spi->host->hw->user.usr_miso = 0;
|
||||
disp_spi->host->hw->cmd.usr = 1; // Start transfer
|
||||
}
|
||||
// Wait for SPI bus ready
|
||||
while (disp_spi->host->hw->cmd.usr);
|
||||
taskENABLE_INTERRUPTS();
|
||||
}
|
||||
|
||||
// ================================================================
|
||||
// === Main function to send data to display ======================
|
||||
// If rep==true: repeat sending data to display 'len' times
|
||||
// If rep==false: send 'len' data bytes from buffer to display
|
||||
// ** Device must already be selected and address window set **
|
||||
// ================================================================
|
||||
//---------------------------------------------------------------------------
|
||||
static void IRAM_ATTR SPI_send_data(uint8_t *data, uint32_t len, uint8_t rep)
|
||||
{
|
||||
if (len == 0) return;
|
||||
|
||||
if ((len*8) <= 512) _direct_send(data, len, rep);
|
||||
else if (rep == 0) _dma_send(data, len);
|
||||
else {
|
||||
// ==== Repeat data, more than 512 bits total ====
|
||||
uint8_t *transbuf = pvPortMallocCaps(len, MALLOC_CAP_DMA);
|
||||
if (transbuf == NULL) return;
|
||||
|
||||
memset(transbuf, data[0], len);
|
||||
_dma_send(transbuf, len);
|
||||
free(transbuf);
|
||||
}
|
||||
}
|
||||
|
||||
// Send one byte to display
|
||||
//-------------------------------------
|
||||
void IRAM_ATTR SPI_Write(uint8_t value)
|
||||
{
|
||||
disp_spi->host->hw->data_buf[0] = (uint32_t)value;
|
||||
// Load send buffer
|
||||
disp_spi->host->hw->user.usr_mosi_highpart = 0;
|
||||
disp_spi->host->hw->mosi_dlen.usr_mosi_dbitlen = 7;
|
||||
disp_spi->host->hw->user.usr_mosi = 1;
|
||||
disp_spi->host->hw->miso_dlen.usr_miso_dbitlen = 0;
|
||||
disp_spi->host->hw->user.usr_miso = 0;
|
||||
// Start transfer
|
||||
disp_spi->host->hw->cmd.usr = 1;
|
||||
// Wait for SPI bus ready
|
||||
while (disp_spi->host->hw->cmd.usr);
|
||||
}
|
||||
|
||||
// Check display busy line and wait while busy
|
||||
//-----------------------
|
||||
static uint8_t ReadBusy()
|
||||
{
|
||||
for (int i=0; i<400; i++){
|
||||
if (isEPD_BUSY == EPD_BUSY_LEVEL) return 1;
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//-----------------------
|
||||
static uint8_t WaitBusy()
|
||||
{
|
||||
if (isEPD_BUSY != EPD_BUSY_LEVEL) return 1;
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
if (isEPD_BUSY != EPD_BUSY_LEVEL) return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write one command without parameters
|
||||
//---------------------------------------
|
||||
static void EPD_WriteCMD(uint8_t command)
|
||||
{
|
||||
spi_lobo_device_select(disp_spi, 0);
|
||||
EPD_DC_0; // command write
|
||||
SPI_Write(command);
|
||||
}
|
||||
|
||||
// Write command with one paramet
|
||||
//---------------------------------------
|
||||
static void EPD_WriteCMD_p1(uint8_t command,uint8_t para)
|
||||
{
|
||||
spi_lobo_device_select(disp_spi, 0);
|
||||
//ReadBusy();
|
||||
EPD_DC_0; // command write
|
||||
SPI_Write(command);
|
||||
EPD_DC_1; // data write
|
||||
SPI_Write(para);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
}
|
||||
|
||||
//----------------
|
||||
void EPD_PowerOn()
|
||||
{
|
||||
EPD_WriteCMD_p1(0x22,0xc0);
|
||||
EPD_WriteCMD(0x20);
|
||||
//EPD_WriteCMD(0xff);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
#if EPD_DEBUG
|
||||
if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
|
||||
if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
|
||||
#else
|
||||
WaitBusy();
|
||||
ReadBusy();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-----------------
|
||||
void EPD_PowerOff()
|
||||
{
|
||||
EPD_WriteCMD_p1(0x22,0x03);
|
||||
EPD_WriteCMD(0x20);
|
||||
//EPD_WriteCMD(0xff);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
#if EPD_DEBUG
|
||||
if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
|
||||
if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
|
||||
#else
|
||||
WaitBusy();
|
||||
ReadBusy();
|
||||
#endif
|
||||
#if POWER_Pin
|
||||
gpio_set_level(DC_Pin, 0);
|
||||
gpio_set_level(MOSI_Pin, 0);
|
||||
gpio_set_level(SCK_Pin, 0);
|
||||
gpio_set_level(RST_Pin, 0);
|
||||
gpio_set_level(CS_Pin, 0);
|
||||
gpio_set_level(POWER_Pin, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Send command with multiple parameters
|
||||
//----------------------------------------------------
|
||||
static void EPD_Write(uint8_t *value, uint8_t datalen)
|
||||
{
|
||||
uint8_t i = 0;
|
||||
uint8_t *ptemp;
|
||||
|
||||
ptemp = value;
|
||||
spi_lobo_device_select(disp_spi, 0);
|
||||
//ReadBusy();
|
||||
EPD_DC_0; // When DC is 0, write command
|
||||
SPI_Write(*ptemp); //The first byte is written with the command value
|
||||
ptemp++;
|
||||
EPD_DC_1; // When DC is 1, write data
|
||||
for(i= 0;i<datalen-1;i++){ // sub the data
|
||||
SPI_Write(*ptemp);
|
||||
ptemp++;
|
||||
}
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
}
|
||||
|
||||
// Send data buffer to display
|
||||
//----------------------------------------------------------------------------
|
||||
static void EPD_WriteDispRam(uint8_t XSize, uint16_t YSize, uint8_t *Dispbuff)
|
||||
{
|
||||
if (XSize%8 != 0) XSize = XSize+(8-XSize%8);
|
||||
XSize = XSize/8;
|
||||
|
||||
spi_lobo_device_select(disp_spi, 0);
|
||||
//ReadBusy();
|
||||
EPD_DC_0; //command write
|
||||
SPI_Write(0x24);
|
||||
EPD_DC_1; //data write
|
||||
SPI_send_data(Dispbuff, XSize*YSize, 0);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
}
|
||||
|
||||
// Fill the display with value
|
||||
//-------------------------------------------------------------------------------
|
||||
static void EPD_WriteDispRamMono(uint8_t XSize, uint16_t YSize, uint8_t dispdata)
|
||||
{
|
||||
if (XSize%8 != 0) XSize = XSize+(8-XSize%8);
|
||||
XSize = XSize/8;
|
||||
|
||||
spi_lobo_device_select(disp_spi, 0);
|
||||
//ReadBusy();
|
||||
EPD_DC_0; // command write
|
||||
SPI_Write(0x24);
|
||||
EPD_DC_1; // data write
|
||||
SPI_send_data(&dispdata, XSize*YSize, 1);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
}
|
||||
|
||||
/*
|
||||
=== Set RAM X - Address Start / End Position (44h) ===
|
||||
Specify the start/end positions of the window address in the X direction by 8 times address unit.
|
||||
Data is written to the RAM within the area determined by the addresses specified by XSA [4:0] and XEA [4:0].
|
||||
These addresses must be set before the RAM write. It allows on XEA [4:0] ≤ XSA [4:0].
|
||||
The settings follow the condition on 00h ≤ XSA [4:0], XEA [4:0] ≤ 1Dh.
|
||||
The windows is followed by the control setting of Data Entry Setting (R11h)
|
||||
|
||||
=== Set RAM Y - Address Start / End Position (45h) ===
|
||||
Specify the start/end positions of the window address in the Y direction by an address unit.
|
||||
Data is written to the RAM within the area determined by the addresses specified by YSA [8:0] and YEA [8:0].
|
||||
These addresses must be set before the RAM write.
|
||||
It allows YEA [8:0] ≤ YSA [8:0].
|
||||
The settings follow the condition on 00h ≤ YSA [8:0], YEA [8:0] ≤ 13Fh.
|
||||
The windows is followed by the control setting of Data Entry Setting (R11h)
|
||||
*/
|
||||
//--------------------------------------------------------------------------------------
|
||||
static void EPD_SetRamArea(uint8_t Xstart, uint8_t Xend, uint16_t Ystart, uint16_t Yend)
|
||||
{
|
||||
uint8_t RamAreaX[3]; // X start and end
|
||||
uint8_t RamAreaY[5]; // Y start and end
|
||||
RamAreaX[0] = 0x44; // command
|
||||
RamAreaX[1] = Xstart;
|
||||
RamAreaX[2] = Xend;
|
||||
RamAreaY[0] = 0x45; // command
|
||||
RamAreaY[1] = Ystart & 0xFF;
|
||||
RamAreaY[2] = Ystart >> 8;
|
||||
RamAreaY[3] = Yend & 0xFF;
|
||||
RamAreaY[4] = Yend >> 8;
|
||||
EPD_Write(RamAreaX, sizeof(RamAreaX));
|
||||
EPD_Write(RamAreaY, sizeof(RamAreaY));
|
||||
}
|
||||
|
||||
//Set RAM X and Y address counter
|
||||
/*
|
||||
=== Set RAM Address Counter (4Eh-4Fh) ===
|
||||
adrX[4:0]: Make initial settings for the RAM X address in the address counter (AC).
|
||||
adrY[8:0]: Make initial settings for the RAM Y address in the address counter (AC).
|
||||
After RAM data is written, the address counter is automatically updated according to the settings with AM, ID
|
||||
bits and setting for a new RAM address is not required in the address counter.
|
||||
Therefore, data is written consecutively without setting an address.
|
||||
The address counter is not automatically updated when data is read out from the RAM.
|
||||
RAM address setting cannot be made during the standby mode.
|
||||
The address setting should be made within the area designated with window addresses which is controlled
|
||||
by the Data Entry Setting (R11h) {AM, ID[1:0]} ; RAM Address XStart / XEnd Position (R44h) and RAM Address Ystart /Yend Position (R45h).
|
||||
Otherwise undesirable image will be displayed on the Panel.
|
||||
*/
|
||||
//----------------------------------------------------------
|
||||
static void EPD_SetRamPointer(uint8_t addrX, uint16_t addrY)
|
||||
{
|
||||
uint8_t RamPointerX[2]; // default (0,0)
|
||||
uint8_t RamPointerY[3];
|
||||
//Set RAM X address counter
|
||||
RamPointerX[0] = 0x4e;
|
||||
RamPointerX[1] = addrX;
|
||||
//Set RAM Y address counter
|
||||
RamPointerY[0] = 0x4f;
|
||||
RamPointerY[1] = addrY & 0xFF;
|
||||
RamPointerY[2] = addrY >> 8;
|
||||
|
||||
EPD_Write(RamPointerX, sizeof(RamPointerX));
|
||||
EPD_Write(RamPointerY, sizeof(RamPointerY));
|
||||
}
|
||||
|
||||
|
||||
//Set RAM X and Y address Start / End position
|
||||
//Set RAM X and Y address counter
|
||||
//----------------------------------------------------------------------------------------------
|
||||
static void part_display(uint8_t RAM_XST, uint8_t RAM_XEND ,uint16_t RAM_YST, uint16_t RAM_YEND)
|
||||
{
|
||||
EPD_SetRamArea(RAM_XST, RAM_XEND, RAM_YST, RAM_YEND);
|
||||
EPD_SetRamPointer (RAM_XST, RAM_YST);
|
||||
}
|
||||
|
||||
//Initialize the display
|
||||
//--------------------
|
||||
static void EPD_Init()
|
||||
{
|
||||
#if POWER_Pin
|
||||
gpio_set_level(POWER_Pin, 1);
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
#else
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
#endif
|
||||
// reset
|
||||
EPD_RST_0;
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
#endif
|
||||
EPD_RST_1;
|
||||
for (int n=0; n<50; n++) {
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
if (isEPD_BUSY == EPD_BUSY_LEVEL) break;
|
||||
}
|
||||
|
||||
SPI_Write(0x12); // software reset
|
||||
vTaskDelay(10 / portTICK_RATE_MS);
|
||||
ReadBusy();
|
||||
|
||||
// set registers
|
||||
EPD_Write(GDOControl, sizeof(GDOControl)); // Panel configuration, Gate selection
|
||||
EPD_Write(softstart, sizeof(softstart)); // X decrease, Y decrease
|
||||
EPD_Write(VCOMVol, sizeof(VCOMVol)); // VCOM setting
|
||||
EPD_Write(DummyLine, sizeof(DummyLine)); // dummy line per gate
|
||||
EPD_Write(Gatetime, sizeof(Gatetime)); // Gate time setting
|
||||
EPD_Write(Border, sizeof(Border));
|
||||
EPD_Write(RamDataEntryMode, sizeof(RamDataEntryMode)); // X increase, Y decrease
|
||||
|
||||
EPD_SetRamArea(0x00, (xDot-1)/8, yDot-1, 0);
|
||||
EPD_SetRamPointer(0x00, yDot-1);
|
||||
#if EPD_DEBUG
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Init: %u ms\r\n", t1);
|
||||
#endif
|
||||
}
|
||||
|
||||
//------------------------------
|
||||
static void EPD_UpdateFull(void)
|
||||
{
|
||||
/*
|
||||
+ Enable Clock Signal,
|
||||
+ Then Enable CP
|
||||
- Then Load Temperature value
|
||||
- Then Load LUT
|
||||
- Then INITIAL DISPLAY
|
||||
+ Then PATTERN DISPLAY
|
||||
+ Then Disable CP
|
||||
+ Then Disable OSC
|
||||
*/
|
||||
EPD_WriteCMD_p1(0x22,0xC7);
|
||||
EPD_WriteCMD(0x20);
|
||||
//EPD_WriteCMD(0xff);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
|
||||
#if EPD_DEBUG
|
||||
if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
|
||||
if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
|
||||
#else
|
||||
WaitBusy();
|
||||
ReadBusy();
|
||||
#endif
|
||||
}
|
||||
|
||||
//-------------------------------
|
||||
static void EPD_Update_Part(void)
|
||||
{
|
||||
/*
|
||||
- Enable Clock Signal,
|
||||
- Then Enable CP
|
||||
- Then Load Temperature value
|
||||
- Then Load LUT
|
||||
- Then INITIAL DISPLAY
|
||||
+ Then PATTERN DISPLAY
|
||||
- Then Disable CP
|
||||
- Then Disable OSC
|
||||
*/
|
||||
EPD_WriteCMD_p1(0x22,0x04);
|
||||
EPD_WriteCMD(0x20);
|
||||
//EPD_WriteCMD(0xff);
|
||||
spi_lobo_device_deselect(disp_spi);
|
||||
|
||||
#if EPD_DEBUG
|
||||
if (!WaitBusy()) printf("[EPD] NOT BUSY\r\n");
|
||||
if (!ReadBusy()) printf("[EPD] NOT READY\r\n");
|
||||
#else
|
||||
WaitBusy();
|
||||
ReadBusy();
|
||||
#endif
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Full screen initialization
|
||||
********************************************************************************/
|
||||
static void EPD_init_Full(void)
|
||||
{
|
||||
EPD_Init(); // Reset and set register
|
||||
EPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));
|
||||
|
||||
EPD_PowerOn();
|
||||
}
|
||||
|
||||
/*******************************************************************************
|
||||
Part screen initialization
|
||||
********************************************************************************/
|
||||
static void EPD_init_Part(void)
|
||||
{
|
||||
EPD_Init(); // display
|
||||
EPD_Write((uint8_t *)LUT_part, 31);
|
||||
EPD_PowerOn();
|
||||
}
|
||||
/********************************************************************************
|
||||
parameter:
|
||||
Label :
|
||||
=1 Displays the contents of the DisBuffer
|
||||
=0 Displays the contents of the first byte in DisBuffer,
|
||||
********************************************************************************/
|
||||
static void EPD_Dis_Full(uint8_t *DisBuffer,uint8_t type)
|
||||
{
|
||||
EPD_SetRamPointer(0x00, yDot-1); // set ram pointer
|
||||
if (type == 0){
|
||||
// Fill screen with white
|
||||
EPD_WriteDispRamMono(xDot, yDot, 0xff);
|
||||
}
|
||||
else {
|
||||
// Fill screen from buffer
|
||||
EPD_WriteDispRam(xDot, yDot, (uint8_t *)DisBuffer);
|
||||
}
|
||||
EPD_UpdateFull();
|
||||
|
||||
}
|
||||
|
||||
/********************************************************************************
|
||||
WARNING: X is smaller screen dimension (0~127) !
|
||||
Y is larger screen dimension (0~295) !
|
||||
parameter:
|
||||
xStart : X direction Start coordinate
|
||||
xEnd : X direction end coordinate
|
||||
yStart : Y direction Start coordinate
|
||||
yEnd : Y direction end coordinate
|
||||
DisBuffer : Display content
|
||||
type :
|
||||
=1 Displays the contents of the DisBuffer
|
||||
=0 Displays the contents of the first byte in DisBuffer,
|
||||
********************************************************************************/
|
||||
static void EPD_Dis_Part(uint8_t xStart, uint8_t xEnd, uint16_t yStart, uint16_t yEnd, uint8_t *DisBuffer, uint8_t type)
|
||||
{
|
||||
if (type == 0) {
|
||||
// Repeated color
|
||||
part_display(xStart/8, xEnd/8, yEnd, yStart);
|
||||
EPD_WriteDispRamMono(xEnd-xStart+1, yEnd-yStart+1, DisBuffer[0]);
|
||||
EPD_Update_Part();
|
||||
part_display(xStart/8, xEnd/8, yEnd, yStart);
|
||||
EPD_WriteDispRamMono(xEnd-xStart+1, yEnd-yStart+1, DisBuffer[0]);
|
||||
}
|
||||
else {
|
||||
// From buffer
|
||||
part_display(xStart/8, xEnd/8, yEnd, yStart);
|
||||
EPD_WriteDispRam(xEnd-xStart+1, yEnd-yStart+1,DisBuffer);
|
||||
EPD_Update_Part();
|
||||
part_display(xStart/8, xEnd/8, yEnd, yStart);
|
||||
EPD_WriteDispRam(xEnd-xStart+1, yEnd-yStart+1,DisBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
//======================================================================================================================================
|
||||
|
||||
// Clear full screen
|
||||
//=========================
|
||||
void EPD_DisplayClearFull()
|
||||
{
|
||||
uint8_t m;
|
||||
EPD_init_Full();
|
||||
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
#endif
|
||||
m = 0x00;
|
||||
EPD_Dis_Full(&m, 0); //all black
|
||||
#if EPD_DEBUG
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Clear black: %u ms\r\n", t1);
|
||||
t1 = clock();
|
||||
#endif
|
||||
m = 0xff;
|
||||
EPD_Dis_Full(&m, 0); //all white
|
||||
#if EPD_DEBUG
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Clear white: %u ms\r\n", t1);
|
||||
#endif
|
||||
}
|
||||
|
||||
// Partial clear screen
|
||||
//=========================
|
||||
void EPD_DisplayClearPart()
|
||||
{
|
||||
uint8_t m = 0xFF;
|
||||
EPD_init_Part();
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
|
||||
m = 0x00;
|
||||
EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all black
|
||||
m = 0xFF;
|
||||
EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Part Clear: %u ms\r\n", t1);
|
||||
#else
|
||||
EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
|
||||
m = 0x00;
|
||||
EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all black
|
||||
m = 0xFF;
|
||||
EPD_Dis_Part(0, xDot-1, 0, yDot-1, &m, 0); //all white
|
||||
#endif
|
||||
}
|
||||
|
||||
//==================================
|
||||
void EPD_DisplaySetFull(uint8_t val)
|
||||
{
|
||||
EPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
EPD_Dis_Full(&val, 0);
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Display Set Full: %u ms [%02x]\r\n", t1, val);
|
||||
#else
|
||||
EPD_Dis_Full(&val, 0);
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================================================================
|
||||
void EPD_DisplaySetPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t val)
|
||||
{
|
||||
EPD_Write((uint8_t *)LUT_part, 31);
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
EPD_Dis_Part(yStart,yEnd,xStart,xEnd, &val,0);
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Display Set Part: %u ms [%02x]\r\n", t1, val);
|
||||
#else
|
||||
EPD_Dis_Part(yStart,yEnd,xStart,xEnd, &val,0);
|
||||
#endif
|
||||
}
|
||||
|
||||
//======================================
|
||||
void EPD_DisplayFull(uint8_t *DisBuffer)
|
||||
{
|
||||
EPD_Write((uint8_t *)LUTDefault_full,sizeof(LUTDefault_full));
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
EPD_Dis_Full((uint8_t *)DisBuffer,1);
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Display Full: %u ms\r\n", t1);
|
||||
#else
|
||||
EPD_Dis_Full((uint8_t *)DisBuffer,1);
|
||||
#endif
|
||||
}
|
||||
|
||||
//==========================================================================================
|
||||
void EPD_DisplayPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t *DisBuffer)
|
||||
{
|
||||
EPD_Write((uint8_t *)LUT_part, 31);
|
||||
#if EPD_DEBUG
|
||||
uint32_t t1 = clock();
|
||||
EPD_Dis_Part(yStart,yEnd,xStart,xEnd,(uint8_t *)DisBuffer,1);
|
||||
t1 = clock() - t1;
|
||||
printf("[EPD] Display Part: %u ms [%02x:%02x]\r\n", t1, LUT_gs[1], LUT_gs[21]);
|
||||
#else
|
||||
EPD_Dis_Part(yStart,yEnd,xStart,xEnd,(uint8_t *)DisBuffer,1);
|
||||
#endif
|
||||
}
|
||||
|
||||
//============
|
||||
void EPD_Cls()
|
||||
{
|
||||
EPD_DisplaySetPart(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1, 0xFF);
|
||||
memset(disp_buffer, 0xFF, _width * (_height/8));
|
||||
memset(gs_disp_buffer, 0, _width * _height);
|
||||
gs_used_shades = 0;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------------
|
||||
void EPD_gsUpdate(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t gs)
|
||||
{
|
||||
uint8_t val, buf_val, new_val;
|
||||
int count=0, changed=0;
|
||||
int x;
|
||||
uint8_t y;
|
||||
for (x=xStart; x<=xEnd; x++) {
|
||||
for (y=yStart; y<=yEnd; y++) {
|
||||
val = gs_drawBuff[(y * (xEnd-xStart+1)) + x];
|
||||
if (val > 15) val >>= 4;
|
||||
if (val == gs) {
|
||||
buf_val = drawBuff[(x * ((yEnd-yStart+1)>>3)) + (y>>3)];
|
||||
new_val = buf_val;
|
||||
if (gs > 0) new_val &= (0x80 >> (y % 8)) ^ 0xFF;
|
||||
else new_val |= (0x80 >> (y % 8));
|
||||
if (new_val != buf_val) {
|
||||
drawBuff[(x * (_height>>3)) + (y>>3)] = new_val;
|
||||
changed++;
|
||||
}
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (changed) {
|
||||
#if EPD_DEBUG
|
||||
printf("[EPD] GS Update %02x, count=%d changed=%d\r\n", gs, count, changed);
|
||||
#endif
|
||||
uint8_t *_lutPart = LUT_part;
|
||||
memset(LUT_gs+1, 0, 30);
|
||||
if (gs > 0) {
|
||||
if (gs > 0) {
|
||||
LUT_gs[1] = 0x18;
|
||||
LUT_gs[21] = gs;
|
||||
}
|
||||
}
|
||||
else {
|
||||
LUT_gs[1] = 0x28;
|
||||
LUT_gs[2] = 0x00;
|
||||
LUT_gs[21] = 15;
|
||||
}
|
||||
LUT_part = LUT_gs;
|
||||
EPD_DisplayPart(xStart, xEnd, yStart, yEnd, drawBuff);
|
||||
|
||||
LUT_part = _lutPart;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------
|
||||
void EPD_Update(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd)
|
||||
{
|
||||
if (_gs == 0) EPD_DisplayPart(xStart, xEnd, yStart, yEnd, drawBuff);
|
||||
else {
|
||||
for (int n=0; n<16; n++) {
|
||||
if (gs_used_shades & (1<<n)) EPD_gsUpdate(xStart, xEnd, yStart, yEnd, n);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------
|
||||
void EPD_UpdateScreen()
|
||||
{
|
||||
EPD_Update(0, EPD_DISPLAY_WIDTH-1, 0, EPD_DISPLAY_HEIGHT-1);
|
||||
}
|
||||
|
||||
//------------------------
|
||||
void EPD_wait(uint32_t ms)
|
||||
{
|
||||
if (ms < 100) ms = 100;
|
||||
uint32_t n = 0;
|
||||
while (n < ms) {
|
||||
vTaskDelay(100 / portTICK_RATE_MS);
|
||||
n += 100;
|
||||
}
|
||||
}
|
||||
|
||||
|
86
components/epaper/EPDspi.h
Normal file
86
components/epaper/EPDspi.h
Normal file
@ -0,0 +1,86 @@
|
||||
/*
|
||||
* Author: LoBo (loboris@gmail.com, loboris.github)
|
||||
*
|
||||
* Module supporting SPI ePaper displays
|
||||
*
|
||||
* HIGH SPEED LOW LEVEL DISPLAY FUNCTIONS
|
||||
* USING DIRECT or DMA SPI TRANSFER MODEs
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _EPDSPI_H_
|
||||
#define _EPDSPI_H_
|
||||
|
||||
#include <stdint.h>
|
||||
#include "spi_master_lobo.h"
|
||||
|
||||
#define EPD_DISPLAY_WIDTH 296
|
||||
#define EPD_DISPLAY_HEIGHT 128
|
||||
|
||||
#define SCK_Pin 18
|
||||
#define MOSI_Pin 23
|
||||
//#define MISO_Pin 19
|
||||
#define DC_Pin 17//26
|
||||
#define BUSY_Pin 4//32
|
||||
#define RST_Pin 16//27
|
||||
#define CS_Pin 5
|
||||
// ePaper display can be powered from GPIO
|
||||
// if powered directly from Vcc, set this to 0
|
||||
#define POWER_Pin 22
|
||||
|
||||
#define DC_VAL (1 << DC_Pin)
|
||||
|
||||
#define EPD_CS_0 gpio_set_level(CS_Pin, 0)
|
||||
#define EPD_CS_1 gpio_set_level(CS_Pin, 1)
|
||||
#define isEPD_CS gpio_get_level(CS_Pin)
|
||||
|
||||
#define EPD_RST_0 gpio_set_level(RST_Pin, 0)
|
||||
#define EPD_RST_1 gpio_set_level(RST_Pin, 1)
|
||||
#define isEPD_RST gpio_get_level(RST_Pin)
|
||||
|
||||
#define EPD_DC_0 gpio_set_level(DC_Pin, 0)
|
||||
#define EPD_DC_1 gpio_set_level(DC_Pin, 1)
|
||||
|
||||
#define isEPD_BUSY gpio_get_level(BUSY_Pin)
|
||||
|
||||
#define EPD_BUSY_LEVEL 0
|
||||
|
||||
// ==================================================
|
||||
// Define which spi bus to use VSPI_HOST or HSPI_HOST
|
||||
#define SPI_BUS VSPI_HOST
|
||||
// ==================================================
|
||||
|
||||
spi_lobo_device_handle_t disp_spi;
|
||||
uint8_t *gs_disp_buffer;
|
||||
uint8_t *disp_buffer;
|
||||
uint8_t *gs_drawBuff;
|
||||
uint8_t *drawBuff;
|
||||
int _width;
|
||||
int _height;
|
||||
uint16_t gs_used_shades;
|
||||
uint8_t _gs;
|
||||
uint8_t *LUT_part;
|
||||
uint8_t LUTDefault_fastest[31];
|
||||
uint8_t LUTDefault_part[31];
|
||||
uint8_t LUT_gs[31];
|
||||
uint8_t LUTDefault_full[31];
|
||||
uint8_t lvl_buf[16];
|
||||
uint8_t lvl_buf_jpg[16];
|
||||
|
||||
void EPD_wait(uint32_t ms);
|
||||
void EPD_DisplaySetFull(uint8_t val);
|
||||
void EPD_DisplaySetPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t val);
|
||||
void EPD_DisplayClearFull();
|
||||
void EPD_DisplayClearPart();
|
||||
void EPD_DisplayFull(uint8_t *DisBuffer);
|
||||
void EPD_DisplayPart(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t *DisBuffer);
|
||||
void EPD_gsUpdate(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd, uint8_t gs);
|
||||
void EPD_Update(int xStart, int xEnd, uint8_t yStart, uint8_t yEnd);
|
||||
void EPD_UpdateScreen();
|
||||
void EPD_Cls();
|
||||
void EPD_PowerOn();
|
||||
void EPD_PowerOff();
|
||||
|
||||
|
||||
#endif
|
120
components/epaper/SmallFont.c
Normal file
120
components/epaper/SmallFont.c
Normal file
@ -0,0 +1,120 @@
|
||||
// SmallFont.c
|
||||
// Font type : Full (95 characters)
|
||||
// Font size : 8x12 pixels
|
||||
// Memory usage : 1144 bytes
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
#define fontdatatype const uint8_t
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PROGMEM
|
||||
#define fontdatatype const unsigned char
|
||||
#elif defined(__arm__)
|
||||
#define PROGMEM
|
||||
#define fontdatatype const unsigned char
|
||||
#endif
|
||||
|
||||
const unsigned char tft_SmallFont[1144] =
|
||||
{
|
||||
0x08,0x0C,0x20,0x5F,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space>
|
||||
0x00,0x00,0x20,0x20,0x20,0x20,0x20,0x20,0x00,0x20,0x00,0x00, // !
|
||||
0x00,0x28,0x50,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "
|
||||
0x00,0x00,0x28,0x28,0xFC,0x28,0x50,0xFC,0x50,0x50,0x00,0x00, // #
|
||||
0x00,0x20,0x78,0xA8,0xA0,0x60,0x30,0x28,0xA8,0xF0,0x20,0x00, // $
|
||||
0x00,0x00,0x48,0xA8,0xB0,0x50,0x28,0x34,0x54,0x48,0x00,0x00, // %
|
||||
0x00,0x00,0x20,0x50,0x50,0x78,0xA8,0xA8,0x90,0x6C,0x00,0x00, // &
|
||||
0x00,0x40,0x40,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // '
|
||||
0x00,0x04,0x08,0x10,0x10,0x10,0x10,0x10,0x10,0x08,0x04,0x00, // (
|
||||
0x00,0x40,0x20,0x10,0x10,0x10,0x10,0x10,0x10,0x20,0x40,0x00, // )
|
||||
0x00,0x00,0x00,0x20,0xA8,0x70,0x70,0xA8,0x20,0x00,0x00,0x00, // *
|
||||
0x00,0x00,0x20,0x20,0x20,0xF8,0x20,0x20,0x20,0x00,0x00,0x00, // +
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x40,0x80, // ,
|
||||
0x00,0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00, // -
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x40,0x00,0x00, // .
|
||||
0x00,0x08,0x10,0x10,0x10,0x20,0x20,0x40,0x40,0x40,0x80,0x00, // /
|
||||
|
||||
0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // 0
|
||||
0x00,0x00,0x20,0x60,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // 1
|
||||
0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x40,0x80,0xF8,0x00,0x00, // 2
|
||||
0x00,0x00,0x70,0x88,0x08,0x30,0x08,0x08,0x88,0x70,0x00,0x00, // 3
|
||||
0x00,0x00,0x10,0x30,0x50,0x50,0x90,0x78,0x10,0x18,0x00,0x00, // 4
|
||||
0x00,0x00,0xF8,0x80,0x80,0xF0,0x08,0x08,0x88,0x70,0x00,0x00, // 5
|
||||
0x00,0x00,0x70,0x90,0x80,0xF0,0x88,0x88,0x88,0x70,0x00,0x00, // 6
|
||||
0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x20,0x20,0x20,0x00,0x00, // 7
|
||||
0x00,0x00,0x70,0x88,0x88,0x70,0x88,0x88,0x88,0x70,0x00,0x00, // 8
|
||||
0x00,0x00,0x70,0x88,0x88,0x88,0x78,0x08,0x48,0x70,0x00,0x00, // 9
|
||||
0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x00,0x20,0x00,0x00, // :
|
||||
0x00,0x00,0x00,0x00,0x00,0x20,0x00,0x00,0x00,0x20,0x20,0x00, // ;
|
||||
0x00,0x04,0x08,0x10,0x20,0x40,0x20,0x10,0x08,0x04,0x00,0x00, // <
|
||||
0x00,0x00,0x00,0x00,0xF8,0x00,0x00,0xF8,0x00,0x00,0x00,0x00, // =
|
||||
0x00,0x40,0x20,0x10,0x08,0x04,0x08,0x10,0x20,0x40,0x00,0x00, // >
|
||||
0x00,0x00,0x70,0x88,0x88,0x10,0x20,0x20,0x00,0x20,0x00,0x00, // ?
|
||||
|
||||
0x00,0x00,0x70,0x88,0x98,0xA8,0xA8,0xB8,0x80,0x78,0x00,0x00, // @
|
||||
0x00,0x00,0x20,0x20,0x30,0x50,0x50,0x78,0x48,0xCC,0x00,0x00, // A
|
||||
0x00,0x00,0xF0,0x48,0x48,0x70,0x48,0x48,0x48,0xF0,0x00,0x00, // B
|
||||
0x00,0x00,0x78,0x88,0x80,0x80,0x80,0x80,0x88,0x70,0x00,0x00, // C
|
||||
0x00,0x00,0xF0,0x48,0x48,0x48,0x48,0x48,0x48,0xF0,0x00,0x00, // D
|
||||
0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x48,0xF8,0x00,0x00, // E
|
||||
0x00,0x00,0xF8,0x48,0x50,0x70,0x50,0x40,0x40,0xE0,0x00,0x00, // F
|
||||
0x00,0x00,0x38,0x48,0x80,0x80,0x9C,0x88,0x48,0x30,0x00,0x00, // G
|
||||
0x00,0x00,0xCC,0x48,0x48,0x78,0x48,0x48,0x48,0xCC,0x00,0x00, // H
|
||||
0x00,0x00,0xF8,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // I
|
||||
0x00,0x00,0x7C,0x10,0x10,0x10,0x10,0x10,0x10,0x90,0xE0,0x00, // J
|
||||
0x00,0x00,0xEC,0x48,0x50,0x60,0x50,0x50,0x48,0xEC,0x00,0x00, // K
|
||||
0x00,0x00,0xE0,0x40,0x40,0x40,0x40,0x40,0x44,0xFC,0x00,0x00, // L
|
||||
0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // M
|
||||
0x00,0x00,0xDC,0x48,0x68,0x68,0x58,0x58,0x48,0xE8,0x00,0x00, // N
|
||||
0x00,0x00,0x70,0x88,0x88,0x88,0x88,0x88,0x88,0x70,0x00,0x00, // O
|
||||
|
||||
0x00,0x00,0xF0,0x48,0x48,0x70,0x40,0x40,0x40,0xE0,0x00,0x00, // P
|
||||
0x00,0x00,0x70,0x88,0x88,0x88,0x88,0xE8,0x98,0x70,0x18,0x00, // Q
|
||||
0x00,0x00,0xF0,0x48,0x48,0x70,0x50,0x48,0x48,0xEC,0x00,0x00, // R
|
||||
0x00,0x00,0x78,0x88,0x80,0x60,0x10,0x08,0x88,0xF0,0x00,0x00, // S
|
||||
0x00,0x00,0xF8,0xA8,0x20,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // T
|
||||
0x00,0x00,0xCC,0x48,0x48,0x48,0x48,0x48,0x48,0x30,0x00,0x00, // U
|
||||
0x00,0x00,0xCC,0x48,0x48,0x50,0x50,0x30,0x20,0x20,0x00,0x00, // V
|
||||
0x00,0x00,0xA8,0xA8,0xA8,0x70,0x50,0x50,0x50,0x50,0x00,0x00, // W
|
||||
0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x50,0x50,0xD8,0x00,0x00, // X
|
||||
0x00,0x00,0xD8,0x50,0x50,0x20,0x20,0x20,0x20,0x70,0x00,0x00, // Y
|
||||
0x00,0x00,0xF8,0x90,0x10,0x20,0x20,0x40,0x48,0xF8,0x00,0x00, // Z
|
||||
0x00,0x38,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x38,0x00, // [
|
||||
0x00,0x40,0x40,0x40,0x20,0x20,0x10,0x10,0x10,0x08,0x00,0x00, // <backslash>
|
||||
0x00,0x70,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x70,0x00, // ]
|
||||
0x00,0x20,0x50,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFC, // _
|
||||
|
||||
0x00,0x20,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // `
|
||||
0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x38,0x48,0x3C,0x00,0x00, // a
|
||||
0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0x70,0x00,0x00, // b
|
||||
0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x40,0x40,0x38,0x00,0x00, // c
|
||||
0x00,0x00,0x18,0x08,0x08,0x38,0x48,0x48,0x48,0x3C,0x00,0x00, // d
|
||||
0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x78,0x40,0x38,0x00,0x00, // e
|
||||
0x00,0x00,0x1C,0x20,0x20,0x78,0x20,0x20,0x20,0x78,0x00,0x00, // f
|
||||
0x00,0x00,0x00,0x00,0x00,0x3C,0x48,0x30,0x40,0x78,0x44,0x38, // g
|
||||
0x00,0x00,0xC0,0x40,0x40,0x70,0x48,0x48,0x48,0xEC,0x00,0x00, // h
|
||||
0x00,0x00,0x20,0x00,0x00,0x60,0x20,0x20,0x20,0x70,0x00,0x00, // i
|
||||
0x00,0x00,0x10,0x00,0x00,0x30,0x10,0x10,0x10,0x10,0x10,0xE0, // j
|
||||
0x00,0x00,0xC0,0x40,0x40,0x5C,0x50,0x70,0x48,0xEC,0x00,0x00, // k
|
||||
0x00,0x00,0xE0,0x20,0x20,0x20,0x20,0x20,0x20,0xF8,0x00,0x00, // l
|
||||
0x00,0x00,0x00,0x00,0x00,0xF0,0xA8,0xA8,0xA8,0xA8,0x00,0x00, // m
|
||||
0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0xEC,0x00,0x00, // n
|
||||
0x00,0x00,0x00,0x00,0x00,0x30,0x48,0x48,0x48,0x30,0x00,0x00, // o
|
||||
|
||||
0x00,0x00,0x00,0x00,0x00,0xF0,0x48,0x48,0x48,0x70,0x40,0xE0, // p
|
||||
0x00,0x00,0x00,0x00,0x00,0x38,0x48,0x48,0x48,0x38,0x08,0x1C, // q
|
||||
0x00,0x00,0x00,0x00,0x00,0xD8,0x60,0x40,0x40,0xE0,0x00,0x00, // r
|
||||
0x00,0x00,0x00,0x00,0x00,0x78,0x40,0x30,0x08,0x78,0x00,0x00, // s
|
||||
0x00,0x00,0x00,0x20,0x20,0x70,0x20,0x20,0x20,0x18,0x00,0x00, // t
|
||||
0x00,0x00,0x00,0x00,0x00,0xD8,0x48,0x48,0x48,0x3C,0x00,0x00, // u
|
||||
0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x00,0x00, // v
|
||||
0x00,0x00,0x00,0x00,0x00,0xA8,0xA8,0x70,0x50,0x50,0x00,0x00, // w
|
||||
0x00,0x00,0x00,0x00,0x00,0xD8,0x50,0x20,0x50,0xD8,0x00,0x00, // x
|
||||
0x00,0x00,0x00,0x00,0x00,0xEC,0x48,0x50,0x30,0x20,0x20,0xC0, // y
|
||||
0x00,0x00,0x00,0x00,0x00,0x78,0x10,0x20,0x20,0x78,0x00,0x00, // z
|
||||
0x00,0x18,0x10,0x10,0x10,0x20,0x10,0x10,0x10,0x10,0x18,0x00, // {
|
||||
0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10,0x10, // |
|
||||
0x00,0x60,0x20,0x20,0x20,0x10,0x20,0x20,0x20,0x20,0x60,0x00, // }
|
||||
0x40,0xA4,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~
|
||||
};
|
331
components/epaper/Ubuntu16.c
Normal file
331
components/epaper/Ubuntu16.c
Normal file
@ -0,0 +1,331 @@
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// on Arduinos. It can however handle any ttf font that has been converted
|
||||
// using the conversion program. These could be fixed width or proportional
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// Ubuntu16.c
|
||||
// Point Size : 16
|
||||
// Memory usage : 1433 bytes
|
||||
// # characters : 95
|
||||
|
||||
// Header Format (to make Arduino UTFT Compatible):
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
const unsigned char tft_Ubuntu16[] =
|
||||
{
|
||||
0x00, 0x10, 0x00, 0x00,
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
|
||||
// ' '
|
||||
0x20,0x0D,0x00,0x00,0x00,0x04,
|
||||
|
||||
// '!'
|
||||
0x21,0x02,0x01,0x0B,0x01,0x04,
|
||||
0xFC,0x60,
|
||||
// '"'
|
||||
0x22,0x00,0x04,0x04,0x01,0x07,
|
||||
0x99,0x99,
|
||||
// '#'
|
||||
0x23,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0x11,0x08,0x84,0x5F,0xF2,0x21,0x10,0x89,0xFF,0x44,0x22,0x11,0x00,
|
||||
// '$'
|
||||
0x24,0x00,0x07,0x10,0x01,0x09,
|
||||
0x10,0x20,0xF6,0x08,0x10,0x18,0x08,0x0C,0x0C,0x08,0x3F,0xC2,0x04,0x00,
|
||||
// '%'
|
||||
0x25,0x02,0x0C,0x0B,0x01,0x0E,
|
||||
0x70,0x4D,0x88,0x89,0x08,0x90,0xDA,0x07,0x4E,0x05,0xB0,0x91,0x09,0x11,0x1B,0x20,0xE0,
|
||||
// '&'
|
||||
0x26,0x02,0x0A,0x0B,0x01,0x0B,
|
||||
0x3C,0x18,0x84,0x21,0x08,0x2C,0x0C,0x04,0x8A,0x10,0x83,0x30,0xC7,0xC8,
|
||||
// '''
|
||||
0x27,0x00,0x01,0x04,0x01,0x04,
|
||||
0xF0,
|
||||
// '('
|
||||
0x28,0x00,0x04,0x10,0x01,0x05,
|
||||
0x02,0x44,0x48,0x88,0x88,0x84,0x44,0x20,
|
||||
// ')'
|
||||
0x29,0x00,0x04,0x10,0x00,0x05,
|
||||
0x04,0x22,0x21,0x11,0x11,0x12,0x22,0x40,
|
||||
// '*'
|
||||
0x2A,0x02,0x09,0x06,0x00,0x08,
|
||||
0x08,0x24,0x8F,0x83,0x81,0x41,0x10,
|
||||
// '+'
|
||||
0x2B,0x05,0x07,0x07,0x01,0x09,
|
||||
0x10,0x20,0x47,0xF1,0x02,0x04,0x00,
|
||||
// ','
|
||||
0x2C,0x0B,0x02,0x05,0x00,0x04,
|
||||
0x54,0x80,
|
||||
// '-'
|
||||
0x2D,0x08,0x04,0x01,0x01,0x06,
|
||||
0xF0,
|
||||
// '.'
|
||||
0x2E,0x0B,0x01,0x02,0x01,0x04,
|
||||
0xC0,
|
||||
// '/'
|
||||
0x2F,0x00,0x07,0x10,0x00,0x06,
|
||||
0x02,0x08,0x10,0x20,0x81,0x02,0x08,0x10,0x40,0x81,0x04,0x08,0x10,0x40,
|
||||
// '0'
|
||||
0x30,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x38,0x8B,0x1C,0x18,0x30,0x60,0xC1,0x86,0x88,0xE0,
|
||||
// '1'
|
||||
0x31,0x02,0x04,0x0B,0x01,0x09,
|
||||
0x13,0x59,0x11,0x11,0x11,0x10,
|
||||
// '2'
|
||||
0x32,0x02,0x06,0x0B,0x01,0x09,
|
||||
0x7A,0x30,0x41,0x08,0x21,0x08,0x42,0x0F,0xC0,
|
||||
// '3'
|
||||
0x33,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x78,0x08,0x08,0x10,0x47,0x01,0x01,0x02,0x0B,0xE0,
|
||||
// '4'
|
||||
0x34,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x04,0x18,0x51,0x22,0x48,0xA1,0x7F,0x04,0x08,0x10,
|
||||
// '5'
|
||||
0x35,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x7E,0x81,0x02,0x07,0x81,0x80,0x81,0x02,0x0B,0xE0,
|
||||
// '6'
|
||||
0x36,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x1C,0x61,0x00,0x0F,0x90,0xA0,0xC1,0x82,0x88,0xE0,
|
||||
// '7'
|
||||
0x37,0x02,0x07,0x0B,0x01,0x09,
|
||||
0xFE,0x04,0x10,0x40,0x82,0x04,0x08,0x20,0x40,0x80,
|
||||
// '8'
|
||||
0x38,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x39,0x8A,0x0C,0x14,0x47,0x11,0x41,0x83,0x89,0xE0,
|
||||
// '9'
|
||||
0x39,0x02,0x07,0x0B,0x01,0x09,
|
||||
0x38,0x8A,0x0C,0x18,0x28,0x4F,0x81,0x04,0x11,0xC0,
|
||||
// ':'
|
||||
0x3A,0x05,0x01,0x08,0x01,0x04,
|
||||
0xC3,
|
||||
// ';'
|
||||
0x3B,0x05,0x02,0x0B,0x00,0x04,
|
||||
0x50,0x05,0x48,
|
||||
// '<'
|
||||
0x3C,0x05,0x08,0x07,0x01,0x09,
|
||||
0x02,0x0C,0x30,0x60,0x30,0x0C,0x02,
|
||||
// '='
|
||||
0x3D,0x06,0x07,0x04,0x01,0x09,
|
||||
0xFE,0x00,0x07,0xF0,
|
||||
// '>'
|
||||
0x3E,0x05,0x09,0x07,0x00,0x09,
|
||||
0x40,0x1C,0x01,0x80,0x70,0x61,0xC1,0x00,
|
||||
// '?'
|
||||
0x3F,0x02,0x06,0x0B,0x01,0x07,
|
||||
0x78,0x30,0x41,0x18,0xC2,0x00,0x00,0x82,0x00,
|
||||
// '@'
|
||||
0x40,0x02,0x0D,0x0D,0x01,0x0F,
|
||||
0x0F,0x81,0x83,0x10,0x0C,0x8F,0xA8,0x84,0xC8,0x26,0x41,0x32,0x09,0x88,0x5A,0x3F,0x90,0x00,0x60,0x00,0xFC,0x00,
|
||||
// 'A'
|
||||
0x41,0x02,0x0B,0x0B,0x00,0x0B,
|
||||
0x04,0x01,0xC0,0x28,0x08,0x81,0x10,0x61,0x08,0x21,0xFC,0x60,0x48,0x0B,0x00,0x80,
|
||||
// 'B'
|
||||
0x42,0x02,0x08,0x0B,0x01,0x0A,
|
||||
0xF8,0x86,0x82,0x82,0x86,0xFC,0x82,0x81,0x81,0x82,0xFC,
|
||||
// 'C'
|
||||
0x43,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x01,0x00,0x40,0x30,0x07,0xC0,
|
||||
// 'D'
|
||||
0x44,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0xFC,0x41,0x20,0x50,0x18,0x0C,0x06,0x03,0x01,0x81,0x41,0x3F,0x00,
|
||||
// 'E'
|
||||
0x45,0x02,0x07,0x0B,0x01,0x09,
|
||||
0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x03,0xF8,
|
||||
// 'F'
|
||||
0x46,0x02,0x07,0x0B,0x01,0x09,
|
||||
0xFF,0x02,0x04,0x08,0x1F,0xA0,0x40,0x81,0x02,0x00,
|
||||
// 'G'
|
||||
0x47,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0x1F,0x10,0x10,0x10,0x08,0x04,0x02,0x03,0x01,0x40,0xB0,0x47,0xE0,
|
||||
// 'H'
|
||||
0x48,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0x80,0xC0,0x60,0x30,0x18,0x0F,0xFE,0x03,0x01,0x80,0xC0,0x60,0x20,
|
||||
// 'I'
|
||||
0x49,0x02,0x01,0x0B,0x01,0x03,
|
||||
0xFF,0xE0,
|
||||
// 'J'
|
||||
0x4A,0x02,0x07,0x0B,0x00,0x08,
|
||||
0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x02,0x09,0xE0,
|
||||
// 'K'
|
||||
0x4B,0x02,0x09,0x0B,0x01,0x0A,
|
||||
0x81,0x41,0x23,0x12,0x0A,0x06,0x02,0xC1,0x10,0x86,0x40,0xA0,0x20,
|
||||
// 'L'
|
||||
0x4C,0x02,0x07,0x0B,0x01,0x08,
|
||||
0x81,0x02,0x04,0x08,0x10,0x20,0x40,0x81,0x03,0xF8,
|
||||
// 'M'
|
||||
0x4D,0x02,0x0B,0x0B,0x01,0x0D,
|
||||
0x40,0x4C,0x19,0x01,0x28,0xA5,0x14,0x94,0xB2,0x9C,0x33,0x84,0x30,0x06,0x00,0x80,
|
||||
// 'N'
|
||||
0x4E,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0x80,0xE0,0x68,0x32,0x19,0x0C,0x46,0x13,0x05,0x82,0xC0,0xE0,0x20,
|
||||
// 'O'
|
||||
0x4F,0x02,0x0B,0x0B,0x01,0x0D,
|
||||
0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x7C,0x00,
|
||||
// 'P'
|
||||
0x50,0x02,0x08,0x0B,0x01,0x0A,
|
||||
0xFC,0x82,0x81,0x81,0x81,0x82,0xFC,0x80,0x80,0x80,0x80,
|
||||
// 'Q'
|
||||
0x51,0x02,0x0B,0x0E,0x01,0x0D,
|
||||
0x1F,0x04,0x11,0x01,0x40,0x18,0x03,0x00,0x60,0x0C,0x01,0x40,0x44,0x10,0x78,0x02,0x00,0x30,0x01,0x80,
|
||||
// 'R'
|
||||
0x52,0x02,0x09,0x0B,0x01,0x0A,
|
||||
0xFC,0x41,0x20,0x50,0x28,0x14,0x13,0xF1,0x08,0x82,0x40,0xA0,0x20,
|
||||
// 'S'
|
||||
0x53,0x02,0x08,0x0B,0x01,0x09,
|
||||
0x3C,0xC2,0x80,0x80,0x40,0x1C,0x06,0x02,0x02,0x06,0x78,
|
||||
// 'T'
|
||||
0x54,0x02,0x09,0x0B,0x00,0x09,
|
||||
0xFF,0x84,0x02,0x01,0x00,0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x00,
|
||||
// 'U'
|
||||
0x55,0x02,0x09,0x0B,0x01,0x0B,
|
||||
0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xA0,0x8F,0x80,
|
||||
// 'V'
|
||||
0x56,0x02,0x09,0x0B,0x00,0x09,
|
||||
0x80,0xE0,0xD0,0x48,0x26,0x21,0x10,0x88,0x28,0x14,0x0E,0x02,0x00,
|
||||
// 'W'
|
||||
0x57,0x02,0x0D,0x0B,0x00,0x0D,
|
||||
0x80,0x0E,0x10,0xD0,0x84,0x8E,0x24,0x51,0x22,0x88,0xA2,0x85,0x14,0x38,0xE0,0xC2,0x04,0x10,
|
||||
// 'X'
|
||||
0x58,0x02,0x09,0x0B,0x00,0x09,
|
||||
0xC1,0xA0,0x88,0x86,0xC1,0x40,0x60,0x70,0x6C,0x22,0x20,0xB0,0x60,
|
||||
// 'Y'
|
||||
0x59,0x02,0x09,0x0B,0x00,0x09,
|
||||
0x80,0xA0,0x90,0x44,0x41,0x40,0xA0,0x20,0x10,0x08,0x04,0x02,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x02,0x07,0x0B,0x01,0x09,
|
||||
0xFE,0x04,0x10,0x41,0x02,0x08,0x00,0x41,0x03,0xF8,
|
||||
// '['
|
||||
0x5B,0x00,0x03,0x10,0x02,0x05,
|
||||
0xF2,0x49,0x24,0x92,0x49,0x27,
|
||||
// '\'
|
||||
0x5C,0x00,0x07,0x10,0x00,0x06,
|
||||
0x80,0x81,0x02,0x02,0x04,0x08,0x08,0x10,0x10,0x20,0x40,0x40,0x81,0x01,
|
||||
// ']'
|
||||
0x5D,0x00,0x03,0x10,0x00,0x05,
|
||||
0xE4,0x92,0x49,0x24,0x92,0x4F,
|
||||
// '^'
|
||||
0x5E,0x02,0x07,0x06,0x01,0x09,
|
||||
0x10,0x70,0xA2,0x24,0x50,0x40,
|
||||
// '_'
|
||||
0x5F,0x0F,0x08,0x01,0x00,0x08,
|
||||
0xFF,
|
||||
// '`'
|
||||
0x60,0x01,0x04,0x03,0x01,0x06,
|
||||
0x86,0x10,
|
||||
// 'a'
|
||||
0x61,0x05,0x06,0x08,0x01,0x08,
|
||||
0x78,0x30,0x5F,0xC6,0x18,0x5F,
|
||||
// 'b'
|
||||
0x62,0x01,0x07,0x0C,0x01,0x09,
|
||||
0x81,0x02,0x04,0x0F,0x90,0xA0,0xC1,0x83,0x06,0x17,0xC0,
|
||||
// 'c'
|
||||
0x63,0x05,0x06,0x08,0x01,0x08,
|
||||
0x3D,0x08,0x20,0x82,0x04,0x0F,
|
||||
// 'd'
|
||||
0x64,0x01,0x07,0x0C,0x01,0x09,
|
||||
0x02,0x04,0x08,0x13,0xE8,0x60,0xC1,0x83,0x05,0x09,0xF0,
|
||||
// 'e'
|
||||
0x65,0x05,0x07,0x08,0x01,0x09,
|
||||
0x3C,0x8A,0x0F,0xF8,0x10,0x10,0x1E,
|
||||
// 'f'
|
||||
0x66,0x01,0x05,0x0C,0x01,0x06,
|
||||
0x7E,0x21,0x0F,0xC2,0x10,0x84,0x21,0x00,
|
||||
// 'g'
|
||||
0x67,0x05,0x07,0x0B,0x01,0x09,
|
||||
0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x0B,0xE0,
|
||||
// 'h'
|
||||
0x68,0x01,0x07,0x0C,0x01,0x09,
|
||||
0x81,0x02,0x04,0x0F,0x90,0xE0,0xC1,0x83,0x06,0x0C,0x10,
|
||||
// 'i'
|
||||
0x69,0x01,0x03,0x0C,0x00,0x03,
|
||||
0x48,0x04,0x92,0x49,0x20,
|
||||
// 'j'
|
||||
0x6A,0x01,0x04,0x0F,0xFF,0x03,
|
||||
0x22,0x00,0x22,0x22,0x22,0x22,0x22,0xC0,
|
||||
// 'k'
|
||||
0x6B,0x01,0x06,0x0C,0x01,0x08,
|
||||
0x82,0x08,0x20,0x8A,0x4A,0x30,0xA2,0x48,0xA1,
|
||||
// 'l'
|
||||
0x6C,0x01,0x04,0x0C,0x01,0x04,
|
||||
0x88,0x88,0x88,0x88,0x88,0x86,
|
||||
// 'm'
|
||||
0x6D,0x05,0x0B,0x08,0x01,0x0D,
|
||||
0xFB,0xD1,0x8E,0x10,0xC2,0x18,0x43,0x08,0x61,0x0C,0x21,
|
||||
// 'n'
|
||||
0x6E,0x05,0x07,0x08,0x01,0x09,
|
||||
0xFD,0x0E,0x0C,0x18,0x30,0x60,0xC1,
|
||||
// 'o'
|
||||
0x6F,0x05,0x08,0x08,0x01,0x0A,
|
||||
0x3C,0x42,0x81,0x81,0x81,0x81,0x42,0x3C,
|
||||
// 'p'
|
||||
0x70,0x05,0x07,0x0B,0x01,0x09,
|
||||
0xF9,0x0A,0x0C,0x18,0x30,0x61,0x7C,0x81,0x02,0x00,
|
||||
// 'q'
|
||||
0x71,0x05,0x07,0x0B,0x01,0x09,
|
||||
0x3E,0x86,0x0C,0x18,0x30,0x50,0x9F,0x02,0x04,0x08,
|
||||
// 'r'
|
||||
0x72,0x05,0x05,0x08,0x01,0x06,
|
||||
0xFC,0x21,0x08,0x42,0x10,
|
||||
// 's'
|
||||
0x73,0x05,0x05,0x08,0x01,0x07,
|
||||
0x7C,0x20,0xC3,0x04,0x3E,
|
||||
// 't'
|
||||
0x74,0x02,0x05,0x0B,0x01,0x07,
|
||||
0x84,0x21,0xF8,0x42,0x10,0x84,0x1E,
|
||||
// 'u'
|
||||
0x75,0x05,0x07,0x08,0x01,0x09,
|
||||
0x83,0x06,0x0C,0x18,0x30,0x50,0xBF,
|
||||
// 'v'
|
||||
0x76,0x05,0x07,0x08,0x00,0x07,
|
||||
0x83,0x05,0x12,0x22,0x85,0x0E,0x08,
|
||||
// 'w'
|
||||
0x77,0x05,0x0D,0x08,0x00,0x0D,
|
||||
0x82,0x0C,0x10,0x51,0xC4,0x8A,0x26,0x5B,0x14,0x50,0xE3,0x82,0x08,
|
||||
// 'x'
|
||||
0x78,0x05,0x08,0x08,0x00,0x08,
|
||||
0xC3,0x66,0x24,0x18,0x18,0x24,0x42,0xC3,
|
||||
// 'y'
|
||||
0x79,0x05,0x07,0x0B,0x00,0x07,
|
||||
0x82,0x89,0x12,0x22,0x85,0x04,0x08,0x10,0x43,0x00,
|
||||
// 'z'
|
||||
0x7A,0x05,0x06,0x08,0x01,0x08,
|
||||
0xFC,0x10,0x84,0x21,0x08,0x3F,
|
||||
// '{'
|
||||
0x7B,0x00,0x05,0x10,0x00,0x05,
|
||||
0x19,0x08,0x42,0x10,0x98,0x61,0x08,0x42,0x10,0x83,
|
||||
// '|'
|
||||
0x7C,0x00,0x01,0x10,0x02,0x05,
|
||||
0xFF,0xFF,
|
||||
// '}'
|
||||
0x7D,0x00,0x05,0x10,0x00,0x05,
|
||||
0xC1,0x08,0x42,0x10,0x83,0x31,0x08,0x42,0x10,0x98,
|
||||
// '~'
|
||||
0x7E,0x07,0x07,0x02,0x01,0x09,
|
||||
0x73,0x18,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
331
components/epaper/comic24.c
Normal file
331
components/epaper/comic24.c
Normal file
@ -0,0 +1,331 @@
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// on Arduinos. It can however handle any ttf font that has been converted
|
||||
// using the conversion program. These could be fixed width or proportional
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// comic.c
|
||||
// Point Size : 24
|
||||
// Memory usage : 2814 bytes
|
||||
// # characters : 95
|
||||
|
||||
// Header Format (to make Arduino UTFT Compatible):
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
unsigned char tft_Comic24[] =
|
||||
{
|
||||
0x00, 0x19, 0x00, 0x00,
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
|
||||
// ' '
|
||||
0x20,0x15,0x00,0x00,0x00,0x07,
|
||||
|
||||
// '!'
|
||||
0x21,0x02,0x02,0x14,0x01,0x06,
|
||||
0xFF,0xFF,0xFF,0xFC,0x2D,
|
||||
// '"'
|
||||
0x22,0x03,0x06,0x08,0x02,0x0A,
|
||||
0xCF,0x3C,0xF3,0xCF,0x3C,0xF3,
|
||||
// '#'
|
||||
0x23,0x03,0x14,0x12,0x01,0x14,
|
||||
0x01,0x81,0x80,0x18,0x18,0x01,0x81,0x80,0x30,0x30,0x03,0x03,0x07,0xFF,0xFF,0x7F,0xFF,0xF0,0x60,0x60,0x06,0x06,0x00,0xC0,0xC0,0x0C,0x0C,0x0F,0xFF,0xFE,0xFF,0xFF,0xE1,0x81,0x80,0x18,0x18,0x03,0x83,0x00,0x30,0x30,0x03,0x03,0x00,
|
||||
// '$'
|
||||
0x24,0x00,0x0B,0x19,0x02,0x11,
|
||||
0x0C,0x01,0x80,0x30,0x0F,0x83,0xFC,0xD9,0xBB,0x06,0x60,0xCC,0x19,0x83,0xB0,0x3F,0x83,0xFC,0x1B,0x83,0x18,0x63,0x0C,0x71,0x9F,0x37,0x7F,0xC3,0xF0,0x18,0x03,0x00,0x60,0x0C,0x00,
|
||||
// '%'
|
||||
0x25,0x01,0x11,0x14,0x02,0x14,
|
||||
0x00,0x00,0x00,0x0C,0x0E,0x0E,0x0F,0x86,0x0C,0x67,0x06,0x33,0x03,0x19,0x80,0xF9,0x80,0x38,0xC0,0x00,0xE0,0x00,0x60,0x00,0x70,0x00,0x31,0xE0,0x39,0xF8,0x19,0xCE,0x1C,0xC3,0x0C,0x61,0x86,0x39,0xC6,0x0F,0xC3,0x03,0xC0,
|
||||
// '&'
|
||||
0x26,0x03,0x0F,0x13,0x01,0x10,
|
||||
0x01,0xC0,0x07,0xC0,0x19,0x80,0x33,0x00,0x6E,0x00,0xF8,0x01,0xE0,0x07,0x80,0x1F,0x8C,0x73,0x19,0xC3,0x37,0x07,0xEC,0x07,0xD8,0x07,0x30,0x0E,0x38,0x7E,0x3F,0xEC,0x3F,0x0C,0x00,0x18,
|
||||
// '''
|
||||
0x27,0x03,0x02,0x06,0x03,0x09,
|
||||
0xFF,0xF0,
|
||||
// '('
|
||||
0x28,0x02,0x07,0x18,0x01,0x09,
|
||||
0x06,0x1C,0x71,0xC3,0x0E,0x18,0x30,0xE1,0x83,0x06,0x0C,0x18,0x30,0x60,0xE0,0xC1,0x83,0x83,0x83,0x87,0x83,
|
||||
// ')'
|
||||
0x29,0x02,0x06,0x18,0x02,0x09,
|
||||
0xC3,0x86,0x0C,0x30,0x61,0x86,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x61,0x86,0x31,0xCE,0x30,
|
||||
// '*'
|
||||
0x2A,0x03,0x0B,0x09,0x01,0x0D,
|
||||
0x0C,0x01,0x83,0xBF,0xFF,0xF3,0xFC,0x3C,0x0F,0xC3,0x9C,0x61,0x80,
|
||||
// '+'
|
||||
0x2B,0x09,0x0A,0x0A,0x00,0x0C,
|
||||
0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00,
|
||||
// ','
|
||||
0x2C,0x13,0x04,0x06,0x02,0x07,
|
||||
0x37,0x66,0xEC,
|
||||
// '-'
|
||||
0x2D,0x0E,0x08,0x02,0x01,0x0A,
|
||||
0xFF,0xFF,
|
||||
// '.'
|
||||
0x2E,0x12,0x03,0x03,0x02,0x06,
|
||||
0xFF,0x80,
|
||||
// '/'
|
||||
0x2F,0x01,0x0A,0x15,0x01,0x0C,
|
||||
0x00,0x00,0x30,0x0C,0x06,0x01,0x80,0x60,0x30,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x18,0x0E,0x03,0x00,0xC0,0x00,
|
||||
// '0'
|
||||
0x30,0x03,0x0D,0x12,0x01,0x0F,
|
||||
0x0F,0x80,0xFF,0x0E,0x18,0xE0,0x66,0x03,0x70,0x0F,0x00,0x78,0x03,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x03,0xB0,0x19,0x81,0xC7,0x1C,0x3F,0xC0,0x7C,0x00,
|
||||
// '1'
|
||||
0x31,0x03,0x06,0x12,0x03,0x0B,
|
||||
0x10,0xC7,0x3C,0xB0,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0xFF,0xF0,
|
||||
// '2'
|
||||
0x32,0x03,0x0B,0x12,0x02,0x0F,
|
||||
0x1F,0x07,0xFB,0xC3,0xE0,0x30,0x06,0x00,0xC0,0x38,0x0E,0x07,0x81,0xE0,0xF8,0x3C,0x07,0x01,0xC0,0x30,0x06,0x00,0xFF,0xDF,0xFC,
|
||||
// '3'
|
||||
0x33,0x03,0x0B,0x12,0x02,0x0F,
|
||||
0x1F,0x0F,0xF9,0xC3,0x80,0x30,0x06,0x00,0xC0,0x78,0x7E,0x0F,0x80,0x78,0x03,0x80,0x30,0x06,0x00,0xF0,0x1F,0x0E,0x7F,0x83,0xE0,
|
||||
// '4'
|
||||
0x34,0x03,0x0D,0x12,0x02,0x0F,
|
||||
0x01,0xC0,0x0E,0x00,0xF0,0x0F,0x80,0x6C,0x07,0x60,0x33,0x03,0x98,0x38,0xC1,0x86,0x1C,0x31,0xFF,0xFF,0xFF,0x80,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,
|
||||
// '5'
|
||||
0x35,0x02,0x0C,0x13,0x02,0x0F,
|
||||
0x00,0x0F,0xFE,0xFF,0xE6,0x00,0x60,0x0E,0x00,0xEF,0x8F,0xFC,0xF8,0x6E,0x07,0xC0,0x30,0x03,0x00,0x30,0x03,0x00,0x7C,0x06,0xE1,0xE7,0xFC,0x3F,0x00,
|
||||
// '6'
|
||||
0x36,0x03,0x0C,0x12,0x01,0x0F,
|
||||
0x03,0x00,0x70,0x0E,0x01,0xC0,0x38,0x03,0x00,0x60,0x06,0xF8,0xFF,0xEE,0x0E,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x77,0x0E,0x3F,0xC1,0xF8,
|
||||
// '7'
|
||||
0x37,0x02,0x0D,0x13,0x01,0x0F,
|
||||
0x00,0x07,0xFF,0xFF,0xFE,0x00,0xE0,0x0E,0x00,0x60,0x06,0x00,0x30,0x03,0x80,0x18,0x01,0xC0,0x0C,0x00,0x60,0x07,0x00,0x30,0x03,0x80,0x18,0x00,0xC0,0x04,0x00,
|
||||
// '8'
|
||||
0x38,0x02,0x0C,0x13,0x01,0x0F,
|
||||
0x00,0x00,0xFC,0x3F,0xE3,0x07,0x60,0x36,0x03,0x60,0x37,0x8F,0x3F,0xE1,0xFE,0x38,0xE7,0x07,0x60,0x36,0x03,0x60,0x36,0x03,0x30,0x63,0xFE,0x0F,0x80,
|
||||
// '9'
|
||||
0x39,0x03,0x0D,0x13,0x01,0x0F,
|
||||
0x0F,0x01,0xFE,0x1C,0x38,0xC0,0xCC,0x07,0x60,0x1B,0x00,0xD8,0x06,0xE0,0x73,0x87,0x8F,0xF8,0x3E,0xC0,0x0E,0x00,0x60,0x07,0x00,0xF0,0x1F,0x03,0xE0,0x1C,0x00,
|
||||
// ':'
|
||||
0x3A,0x09,0x03,0x0B,0x02,0x07,
|
||||
0xFF,0x80,0x00,0xFF,0x80,
|
||||
// ';'
|
||||
0x3B,0x09,0x04,0x0E,0x02,0x07,
|
||||
0xEE,0xE0,0x00,0x00,0x03,0x7E,0xCC,
|
||||
// '<'
|
||||
0x3C,0x09,0x07,0x0A,0x01,0x09,
|
||||
0x06,0x1C,0x71,0xC7,0x1E,0x1E,0x0E,0x0E,0x0C,
|
||||
// '='
|
||||
0x3D,0x0A,0x09,0x09,0x01,0x0C,
|
||||
0xFF,0xFF,0xC0,0x00,0x00,0x00,0x03,0xFF,0xFF,0x00,0x00,
|
||||
// '>'
|
||||
0x3E,0x08,0x08,0x0B,0x01,0x0A,
|
||||
0x60,0x70,0x38,0x3C,0x1E,0x0F,0x06,0x0C,0x38,0x70,0xC0,
|
||||
// '?'
|
||||
0x3F,0x04,0x0B,0x12,0x01,0x0D,
|
||||
0x1E,0x0F,0xE3,0xC6,0x60,0x60,0x06,0x00,0xC0,0x18,0x07,0x01,0xE0,0xF8,0x3E,0x0F,0x01,0x80,0x00,0x00,0x01,0x80,0x30,0x06,0x00,
|
||||
// '@'
|
||||
0x40,0x02,0x13,0x14,0x01,0x16,
|
||||
0x03,0xF8,0x01,0xFF,0xC0,0x78,0x3C,0x1C,0x01,0xC3,0x00,0x1C,0xC1,0xC1,0x98,0xF8,0x1E,0x3C,0x03,0xC6,0x30,0x79,0x8E,0x0F,0x31,0xC1,0xE6,0x78,0x6C,0x7F,0xFC,0xC7,0x3E,0x18,0x00,0x01,0x80,0x00,0x38,0x00,0x03,0xC0,0xE0,0x1F,0xFC,0x00,0xFE,0x00,
|
||||
// 'A'
|
||||
0x41,0x03,0x0E,0x12,0x01,0x11,
|
||||
0x00,0x80,0x07,0x00,0x1C,0x00,0xF0,0x03,0xC0,0x1D,0x80,0x76,0x03,0x98,0x0E,0x20,0x70,0xC1,0xFF,0x0F,0xFC,0x7C,0x19,0xC0,0x67,0x01,0xB8,0x07,0xE0,0x0F,0x00,0x30,
|
||||
// 'B'
|
||||
0x42,0x03,0x0B,0x13,0x03,0x0F,
|
||||
0x7C,0x1F,0xE3,0x0E,0x60,0xEC,0x0D,0x81,0xB0,0x36,0x0E,0xC3,0x9F,0xE3,0xFC,0x61,0xEC,0x0F,0x80,0xF0,0x1E,0x0E,0xC7,0xDF,0xE3,0xF0,0x00,
|
||||
// 'C'
|
||||
0x43,0x03,0x0D,0x12,0x01,0x0E,
|
||||
0x01,0xF8,0x3F,0xC3,0xC6,0x38,0x31,0x80,0x1C,0x01,0xC0,0x0C,0x00,0x60,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x19,0x81,0xCE,0x3C,0x3F,0xC0,0xF8,0x00,
|
||||
// 'D'
|
||||
0x44,0x03,0x0D,0x12,0x02,0x11,
|
||||
0x60,0x07,0xC0,0x37,0x81,0x8F,0x0C,0x1C,0x60,0x73,0x01,0xD8,0x06,0xC0,0x1E,0x00,0xF0,0x07,0x80,0x3C,0x01,0xE0,0x1B,0x01,0xDC,0x1C,0xFF,0xC1,0xF8,0x00,
|
||||
// 'E'
|
||||
0x45,0x03,0x0D,0x12,0x02,0x0F,
|
||||
0xFF,0xF7,0xFF,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x7E,0xFF,0xF7,0xE0,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0x7F,0xF1,0xFF,0x80,
|
||||
// 'F'
|
||||
0x46,0x03,0x0C,0x12,0x02,0x0F,
|
||||
0xFF,0xCF,0xFF,0xC0,0x7C,0x00,0xC0,0x0C,0x00,0xC0,0x0D,0xFE,0xFF,0xEF,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,0xC0,0x0C,0x00,
|
||||
// 'G'
|
||||
0x47,0x03,0x0F,0x12,0x01,0x10,
|
||||
0x03,0xE0,0x0F,0xF0,0x38,0xE0,0xE0,0x03,0x80,0x06,0x00,0x18,0x00,0x30,0x00,0x61,0xFF,0x9F,0xFF,0x3C,0x36,0x00,0x6C,0x01,0x98,0x07,0x30,0x0C,0x30,0x70,0x7F,0xC0,0x3E,0x00,
|
||||
// 'H'
|
||||
0x48,0x03,0x0F,0x12,0x02,0x12,
|
||||
0xC0,0x03,0x80,0x0F,0x00,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0xFF,0xFF,0xFF,0xFC,0x1E,0x00,0x3C,0x00,0x78,0x00,0xF0,0x01,0xE0,0x03,0xC0,0x07,0x80,0x0C,
|
||||
// 'I'
|
||||
0x49,0x03,0x0C,0x12,0x00,0x0D,
|
||||
0xFF,0xEF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0xFF,0xFF,0xFF,
|
||||
// 'J'
|
||||
0x4A,0x03,0x0E,0x12,0x01,0x10,
|
||||
0x1F,0xFC,0x7F,0xF0,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0x00,0xC0,0x03,0x00,0x0C,0x00,0x30,0xC0,0xC3,0x06,0x0E,0x18,0x1C,0x60,0x3F,0x80,0x3C,0x00,
|
||||
// 'K'
|
||||
0x4B,0x03,0x0C,0x12,0x03,0x0F,
|
||||
0xC0,0x6C,0x0E,0xC1,0xCC,0x38,0xC7,0x0C,0xE0,0xDC,0x0F,0x80,0xF0,0x0F,0x00,0xF8,0x0F,0xC0,0xDE,0x0C,0xF0,0xC7,0x8C,0x1E,0xC0,0xFC,0x07,
|
||||
// 'L'
|
||||
0x4C,0x03,0x0B,0x12,0x01,0x0D,
|
||||
0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xFF,0xEF,0xFC,
|
||||
// 'M'
|
||||
0x4D,0x03,0x13,0x13,0x01,0x15,
|
||||
0x0C,0x06,0x01,0x80,0xC0,0x78,0x3C,0x0F,0x07,0x81,0xE0,0xF0,0x3C,0x1E,0x07,0x83,0xC1,0xD8,0xEC,0x3B,0x1D,0x87,0x63,0xB0,0xCC,0xE6,0x38,0xDC,0x47,0x1B,0x8C,0xE3,0xF1,0xB8,0x3C,0x37,0x07,0x86,0xE0,0xF0,0x7C,0x1E,0x0F,0x01,0x81,0x80,
|
||||
// 'N'
|
||||
0x4E,0x03,0x11,0x12,0x01,0x13,
|
||||
0x60,0x01,0x38,0x00,0xDE,0x00,0x6F,0x00,0x37,0xC0,0x1B,0x70,0x0D,0x9C,0x06,0xCF,0x03,0x63,0x81,0xB0,0xE0,0xD8,0x38,0x6C,0x0E,0x36,0x03,0x9B,0x00,0xED,0x80,0x3E,0xC0,0x0F,0x60,0x03,0xB0,0x00,0xC0,
|
||||
// 'O'
|
||||
0x4F,0x03,0x11,0x12,0x01,0x13,
|
||||
0x01,0xF8,0x03,0xFF,0x07,0x81,0xC3,0x00,0x63,0x00,0x1B,0x80,0x0D,0x80,0x07,0xC0,0x03,0xC0,0x01,0xE0,0x00,0xF0,0x00,0xF8,0x00,0x6C,0x00,0x33,0x00,0x31,0xC0,0x38,0x70,0x78,0x1F,0xF8,0x03,0xF0,0x00,
|
||||
// 'P'
|
||||
0x50,0x03,0x0B,0x12,0x01,0x0D,
|
||||
0xFE,0x1F,0xF3,0x0F,0x60,0x7C,0x07,0x80,0xF0,0x1E,0x06,0xC3,0xDF,0xF3,0xF8,0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x00,
|
||||
// 'Q'
|
||||
0x51,0x03,0x14,0x17,0x01,0x15,
|
||||
0x01,0xF8,0x00,0x7F,0xE0,0x1E,0x07,0x03,0x80,0x18,0x30,0x01,0xC6,0x00,0x0C,0x60,0x00,0xEC,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0xC0,0x00,0x6C,0x00,0x06,0x60,0xE0,0xE7,0x0F,0x0C,0x38,0x79,0xC1,0xC3,0xF8,0x0F,0xFF,0x00,0x3F,0x78,0x00,0x03,0xC0,0x00,0x1E,0x00,0x00,0xF0,0x00,0x07,0x00,0x00,0x20,
|
||||
// 'R'
|
||||
0x52,0x02,0x0D,0x13,0x01,0x0F,
|
||||
0x00,0x03,0xE0,0x3F,0xC1,0x8F,0x0C,0x0E,0x60,0x33,0x00,0xD8,0x06,0xC0,0x36,0x03,0xB0,0x79,0xFF,0x8F,0xF0,0x7F,0x83,0x1F,0x18,0x3C,0xC0,0xF6,0x01,0xF0,0x06,
|
||||
// 'S'
|
||||
0x53,0x03,0x0F,0x13,0x01,0x11,
|
||||
0x01,0xF0,0x07,0xF8,0x18,0x70,0x60,0x01,0x80,0x03,0x00,0x06,0x00,0x0E,0x00,0x0F,0xF0,0x07,0xF0,0x00,0xF0,0x00,0x70,0x00,0x60,0x00,0xD8,0x01,0xB8,0x06,0x78,0x3C,0x7F,0xE0,0x3F,0x00,
|
||||
// 'T'
|
||||
0x54,0x02,0x0F,0x13,0x01,0x10,
|
||||
0x00,0x01,0xFF,0xFD,0xFF,0xF8,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,
|
||||
// 'U'
|
||||
0x55,0x03,0x11,0x12,0x01,0x12,
|
||||
0x60,0x03,0x30,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x33,0x00,0x19,0x80,0x0C,0xC0,0x06,0x60,0x03,0x30,0x01,0x98,0x01,0xCC,0x00,0xC7,0x00,0x61,0x80,0x70,0xE0,0x30,0x38,0x38,0x0F,0xF8,0x01,0xF0,0x00,
|
||||
// 'V'
|
||||
0x56,0x03,0x0E,0x13,0x02,0x10,
|
||||
0x80,0x0F,0x00,0x3C,0x01,0xB0,0x06,0x60,0x31,0x80,0xC6,0x03,0x0C,0x18,0x30,0x60,0xC1,0x81,0x8C,0x06,0x30,0x0D,0x80,0x36,0x00,0xF8,0x01,0xC0,0x07,0x00,0x08,0x00,0x00,0x00,
|
||||
// 'W'
|
||||
0x57,0x03,0x17,0x12,0x01,0x19,
|
||||
0xC0,0x20,0x0F,0xC0,0x60,0x19,0x81,0xC0,0x23,0x03,0x80,0xC6,0x07,0x01,0x86,0x1E,0x03,0x0C,0x36,0x0C,0x18,0x6C,0x18,0x11,0x98,0x60,0x33,0x30,0xC0,0x66,0x61,0x80,0xD8,0x66,0x01,0xB0,0xCC,0x01,0xC1,0xB0,0x03,0x83,0x60,0x07,0x07,0x80,0x0C,0x07,0x00,0x08,0x0E,0x00,
|
||||
// 'X'
|
||||
0x58,0x03,0x10,0x12,0x01,0x11,
|
||||
0x60,0x03,0x70,0x07,0x38,0x0E,0x1C,0x1C,0x0C,0x1C,0x0E,0x38,0x07,0x70,0x03,0xE0,0x01,0xC0,0x03,0xC0,0x07,0xE0,0x07,0x70,0x0E,0x38,0x1C,0x18,0x38,0x1C,0x70,0x0E,0xE0,0x07,0xC0,0x03,
|
||||
// 'Y'
|
||||
0x59,0x03,0x0F,0x13,0x00,0x10,
|
||||
0x60,0x06,0xE0,0x1D,0xC0,0x31,0xC0,0xE1,0xC1,0x83,0x83,0x03,0x8C,0x07,0x18,0x07,0x70,0x0F,0xC0,0x0F,0x80,0x0F,0x00,0x1C,0x00,0x38,0x00,0x60,0x01,0xC0,0x03,0x00,0x06,0x00,0x08,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x03,0x0F,0x12,0x01,0x11,
|
||||
0xFF,0xFF,0xFF,0xFC,0x00,0xF0,0x03,0x80,0x0E,0x00,0x3C,0x00,0xF0,0x03,0xC0,0x07,0x00,0x1E,0x00,0x38,0x00,0xE0,0x03,0xC0,0x07,0x00,0x1C,0x00,0x70,0x00,0xFF,0xFF,0xFF,0xFC,
|
||||
// '['
|
||||
0x5B,0x01,0x07,0x1A,0x01,0x09,
|
||||
0x00,0xFD,0xFB,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x3F,0x7E,0x00,
|
||||
// '\'
|
||||
0x5C,0x03,0x0B,0x14,0x02,0x0D,
|
||||
0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x20,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x60,
|
||||
// ']'
|
||||
0x5D,0x01,0x07,0x1A,0x02,0x09,
|
||||
0x01,0xFB,0xF0,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x06,0x0C,0x18,0x30,0x60,0xC1,0x83,0x7E,0xFC,0x00,
|
||||
// '^'
|
||||
0x5E,0x02,0x0A,0x06,0x02,0x0E,
|
||||
0x0C,0x07,0x83,0xF1,0xCE,0xE1,0xF0,0x30,
|
||||
// '_'
|
||||
0x5F,0x16,0x0F,0x04,0x00,0x0F,
|
||||
0x00,0x01,0xFF,0xFF,0xFF,0xF8,0x00,0x00,
|
||||
// '`'
|
||||
0x60,0x02,0x05,0x06,0x02,0x0D,
|
||||
0xC7,0x1C,0x63,0x8C,
|
||||
// 'a'
|
||||
0x61,0x09,0x0B,0x0C,0x01,0x0C,
|
||||
0x0F,0x87,0xF9,0xE3,0x30,0x6E,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xCC,0x39,0xFF,0x9F,0x30,
|
||||
// 'b'
|
||||
0x62,0x02,0x0C,0x13,0x01,0x0E,
|
||||
0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x78,0x7F,0xC7,0x8E,0x60,0x76,0x03,0x60,0x36,0x03,0x60,0x36,0x06,0x70,0xE7,0xFC,0x7F,0x00,
|
||||
// 'c'
|
||||
0x63,0x09,0x0A,0x0C,0x01,0x0C,
|
||||
0x0F,0x07,0xF3,0x0D,0x80,0x60,0x30,0x0C,0x03,0x00,0xC0,0x1C,0x33,0xFC,0x7C,
|
||||
// 'd'
|
||||
0x64,0x02,0x0C,0x13,0x01,0x0E,
|
||||
0x00,0x20,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x61,0xF6,0x3F,0xE7,0x0E,0x60,0x6C,0x06,0xC0,0x6C,0x06,0xC0,0x6E,0x06,0x70,0xE3,0xFE,0x1F,0x60,
|
||||
// 'e'
|
||||
0x65,0x09,0x0B,0x0C,0x01,0x0D,
|
||||
0x1F,0x07,0xF9,0xC7,0x30,0xEC,0x79,0xBE,0x3E,0x07,0x00,0xC0,0x6E,0x1D,0xFF,0x0F,0x80,
|
||||
// 'f'
|
||||
0x66,0x02,0x0A,0x14,0x01,0x0C,
|
||||
0x03,0x83,0xE0,0xE0,0x70,0x18,0x06,0x01,0x83,0xFF,0xFF,0xC6,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x80,0x60,
|
||||
// 'g'
|
||||
0x67,0x09,0x0A,0x13,0x02,0x0D,
|
||||
0x0F,0x0F,0xF7,0x0D,0x83,0xC0,0xF0,0x3C,0x1F,0x07,0xC1,0xD8,0xF7,0xEC,0xF3,0x00,0xC0,0x30,0x18,0x06,0x03,0xBF,0xC7,0xE0,
|
||||
// 'h'
|
||||
0x68,0x02,0x0B,0x13,0x01,0x0E,
|
||||
0x60,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x18,0x03,0x1E,0x6F,0xEF,0x8D,0xE1,0xB8,0x36,0x06,0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0x80,
|
||||
// 'i'
|
||||
0x69,0x04,0x02,0x11,0x03,0x07,
|
||||
0xF0,0x3F,0xFF,0xFF,0xC0,
|
||||
// 'j'
|
||||
0x6A,0x04,0x08,0x18,0x00,0x0A,
|
||||
0x03,0x03,0x00,0x00,0x00,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0x03,0xC3,0xE3,0x77,0x7E,0x1C,
|
||||
// 'k'
|
||||
0x6B,0x03,0x0B,0x13,0x02,0x0E,
|
||||
0xC0,0x18,0x03,0x00,0x60,0x0C,0x01,0x80,0x30,0x36,0x0E,0xC7,0x99,0xE3,0x70,0x7E,0x0F,0xE1,0xCE,0x30,0xE6,0x0E,0xC0,0xF8,0x08,0x00,0x00,
|
||||
// 'l'
|
||||
0x6C,0x02,0x02,0x13,0x03,0x07,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFC,
|
||||
// 'm'
|
||||
0x6D,0x09,0x10,0x0C,0x01,0x12,
|
||||
0x67,0x3C,0x6F,0xFE,0x7D,0xEE,0x79,0x86,0x71,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,0x61,0x86,
|
||||
// 'n'
|
||||
0x6E,0x09,0x0B,0x0C,0x01,0x0D,
|
||||
0x63,0x8D,0xF9,0xF1,0xBC,0x37,0x06,0xE0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x30,
|
||||
// 'o'
|
||||
0x6F,0x09,0x0C,0x0C,0x01,0x0D,
|
||||
0x0F,0x81,0xFC,0x38,0xC3,0x06,0x60,0x66,0x06,0x60,0x66,0x06,0x60,0xE3,0x1C,0x1F,0x80,0xF0,
|
||||
// 'p'
|
||||
0x70,0x08,0x0A,0x14,0x02,0x0D,
|
||||
0xC0,0x33,0xCF,0xFB,0xC6,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x7C,0x1B,0xFC,0xFE,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,
|
||||
// 'q'
|
||||
0x71,0x08,0x0A,0x14,0x01,0x0C,
|
||||
0x00,0x03,0xF3,0xFD,0xE3,0x60,0xF8,0x3C,0x0F,0x03,0xC0,0xF0,0x76,0x1D,0xFF,0x1F,0x80,0x60,0x18,0x06,0x01,0x80,0x60,0x18,0x06,
|
||||
// 'r'
|
||||
0x72,0x09,0x09,0x0C,0x01,0x0B,
|
||||
0xCF,0x6F,0xFE,0x7C,0x3C,0x1E,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x00,
|
||||
// 's'
|
||||
0x73,0x09,0x09,0x0C,0x02,0x0C,
|
||||
0x03,0x9F,0xDE,0x7C,0x3E,0x07,0xF0,0xFC,0x07,0x01,0xE0,0xFF,0xC7,0xC0,
|
||||
// 't'
|
||||
0x74,0x05,0x0A,0x10,0x00,0x0A,
|
||||
0x0C,0x03,0x00,0xC0,0x30,0xFF,0xFF,0xF0,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,
|
||||
// 'u'
|
||||
0x75,0x09,0x0B,0x0C,0x01,0x0C,
|
||||
0xC0,0xD8,0x1B,0x03,0x60,0x6C,0x0D,0x81,0xB0,0x36,0x06,0xC0,0xD8,0x19,0xFF,0x1F,0x60,
|
||||
// 'v'
|
||||
0x76,0x09,0x0B,0x0D,0x01,0x0C,
|
||||
0xC0,0x78,0x1F,0x83,0x30,0x67,0x1C,0x63,0x0C,0xE0,0xD8,0x1E,0x03,0xC0,0x30,0x06,0x00,0x00,
|
||||
// 'w'
|
||||
0x77,0x09,0x0F,0x0D,0x01,0x11,
|
||||
0xC1,0x87,0x83,0x0F,0x0E,0x1E,0x1C,0x66,0x7C,0xCC,0xD9,0x99,0x36,0x36,0x6C,0x7C,0xD8,0x70,0xE0,0xE1,0xC0,0x83,0x80,0x00,0x00,
|
||||
// 'x'
|
||||
0x78,0x09,0x0D,0x0D,0x01,0x0E,
|
||||
0x60,0x1B,0x81,0xCE,0x1C,0x39,0xC0,0xFC,0x03,0xC0,0x3C,0x03,0xF0,0x39,0xC3,0x87,0x38,0x1D,0x80,0x70,0x01,0x80,
|
||||
// 'y'
|
||||
0x79,0x09,0x0C,0x13,0x00,0x0D,
|
||||
0xC0,0x3E,0x07,0x60,0x67,0x0C,0x30,0xC3,0x98,0x19,0x81,0xD8,0x0F,0x00,0xF0,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x30,0x00,
|
||||
// 'z'
|
||||
0x7A,0x09,0x0B,0x0C,0x01,0x0D,
|
||||
0xFF,0xFF,0xFC,0x07,0x00,0xC0,0x30,0x0C,0x03,0x80,0xE0,0x38,0x0E,0x03,0xFF,0xFF,0xF0,
|
||||
// '{'
|
||||
0x7B,0x02,0x08,0x18,0x01,0x09,
|
||||
0x0F,0x1F,0x38,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x30,0x60,0xE0,0xE0,0x70,0x30,0x30,0x30,0x30,0x30,0x38,0x18,0x1F,0x07,
|
||||
// '|'
|
||||
0x7C,0x01,0x02,0x18,0x04,0x0A,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
// '}'
|
||||
0x7D,0x02,0x08,0x18,0x01,0x09,
|
||||
0x70,0xF8,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x06,0x07,0x07,0x0E,0x0C,0x0C,0x0C,0x0C,0x0C,0x1C,0x18,0xF8,0xE0,
|
||||
// '~'
|
||||
0x7E,0x0B,0x0C,0x05,0x01,0x0E,
|
||||
0x38,0x37,0xE3,0xE7,0x7C,0x3E,0x01,0xC0,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
7
components/epaper/component.mk
Normal file
7
components/epaper/component.mk
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
718
components/epaper/dejavuX.c
Normal file
718
components/epaper/dejavuX.c
Normal file
@ -0,0 +1,718 @@
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// on Arduinos. It can however handle any ttf font that has been converted
|
||||
// using the conversion program. These could be fixed width or proportional
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// dejavuX.c
|
||||
// Point Size : 18
|
||||
// Memory usage : 4676 bytes
|
||||
// # characters : 224
|
||||
|
||||
// Header Format (to make Arduino UTFT Compatible):
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
const unsigned char tft_Dejavu18[] =
|
||||
{
|
||||
0x00, 0x12, 0x00, 0x00,
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
|
||||
// ' '
|
||||
0x20,0x11,0x00,0x00,0x00,0x06,
|
||||
|
||||
// '!'
|
||||
0x21,0x04,0x02,0x0D,0x03,0x07,
|
||||
0xFF,0xFF,0xC3,0xC0,
|
||||
// '"'
|
||||
0x22,0x04,0x06,0x05,0x01,0x08,
|
||||
0xCF,0x3C,0xF3,0xCC,
|
||||
// '#'
|
||||
0x23,0x03,0x0C,0x0E,0x01,0x0F,
|
||||
0x04,0x40,0x44,0x0C,0xC0,0xC8,0x7F,0xF7,0xFF,0x09,0x81,0x90,0xFF,0xEF,0xFE,0x13,0x03,0x30,0x32,0x02,0x20,
|
||||
// '$'
|
||||
0x24,0x03,0x0A,0x11,0x01,0x0B,
|
||||
0x08,0x02,0x03,0xE1,0xFC,0xE9,0x32,0x0F,0x81,0xF8,0x0F,0x02,0x60,0x9A,0x2E,0xFF,0x1F,0x80,0x80,0x20,0x08,0x00,
|
||||
// '%'
|
||||
0x25,0x04,0x0F,0x0D,0x01,0x11,
|
||||
0x78,0x10,0x90,0x43,0x31,0x86,0x62,0x0C,0xC8,0x19,0x10,0x1E,0x4F,0x01,0x12,0x02,0x66,0x08,0xCC,0x31,0x98,0x41,0x21,0x03,0xC0,
|
||||
// '&'
|
||||
0x26,0x04,0x0C,0x0D,0x01,0x0D,
|
||||
0x0F,0x01,0xF8,0x30,0x83,0x00,0x38,0x03,0xC0,0x7E,0x6C,0x76,0xC3,0xCC,0x18,0xE1,0xC7,0xFE,0x3E,0x70,
|
||||
// '''
|
||||
0x27,0x04,0x02,0x05,0x01,0x04,
|
||||
0xFF,0xC0,
|
||||
// '('
|
||||
0x28,0x03,0x04,0x10,0x02,0x07,
|
||||
0x32,0x66,0x4C,0xCC,0xCC,0xC4,0x66,0x23,
|
||||
// ')'
|
||||
0x29,0x03,0x04,0x10,0x01,0x07,
|
||||
0xC4,0x66,0x23,0x33,0x33,0x32,0x66,0x4C,
|
||||
// '*'
|
||||
0x2A,0x04,0x07,0x08,0x01,0x09,
|
||||
0x11,0x25,0x51,0xC3,0x8A,0xA4,0x88,
|
||||
// '+'
|
||||
0x2B,0x05,0x0C,0x0C,0x02,0x0F,
|
||||
0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x06,0x00,0x60,
|
||||
// ','
|
||||
0x2C,0x0F,0x03,0x04,0x01,0x06,
|
||||
0x6D,0x40,
|
||||
// '-'
|
||||
0x2D,0x0B,0x05,0x02,0x01,0x07,
|
||||
0xFF,0xC0,
|
||||
// '.'
|
||||
0x2E,0x0F,0x02,0x02,0x02,0x06,
|
||||
0xF0,
|
||||
// '/'
|
||||
0x2F,0x04,0x06,0x0F,0x00,0x06,
|
||||
0x0C,0x31,0x86,0x18,0xE3,0x0C,0x31,0xC6,0x18,0x63,0x0C,0x00,
|
||||
// '0'
|
||||
0x30,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x3E,0x3F,0x98,0xD8,0x3C,0x1E,0x0F,0x07,0x83,0xC1,0xE0,0xD8,0xCF,0xE3,0xE0,
|
||||
// '1'
|
||||
0x31,0x04,0x08,0x0D,0x02,0x0B,
|
||||
0x38,0xF8,0xD8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0xFF,0xFF,
|
||||
// '2'
|
||||
0x32,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x7C,0x7F,0x21,0xC0,0x60,0x30,0x30,0x18,0x18,0x18,0x18,0x18,0x1F,0xEF,0xF0,
|
||||
// '3'
|
||||
0x33,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x7E,0x7F,0xA0,0xE0,0x30,0x39,0xF0,0xFC,0x07,0x01,0x80,0xE0,0xFF,0xE7,0xE0,
|
||||
// '4'
|
||||
0x34,0x04,0x0A,0x0D,0x01,0x0B,
|
||||
0x07,0x01,0xC0,0xB0,0x6C,0x13,0x08,0xC6,0x31,0x0C,0xFF,0xFF,0xF0,0x30,0x0C,0x03,0x00,
|
||||
// '5'
|
||||
0x35,0x04,0x08,0x0D,0x01,0x0B,
|
||||
0x7E,0x7E,0x60,0x60,0x7C,0x7E,0x47,0x03,0x03,0x03,0x87,0xFE,0x7C,
|
||||
// '6'
|
||||
0x36,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x1E,0x1F,0x9C,0x5C,0x0C,0x06,0xF3,0xFD,0xC7,0xC1,0xE0,0xD8,0xEF,0xE1,0xE0,
|
||||
// '7'
|
||||
0x37,0x04,0x08,0x0D,0x01,0x0B,
|
||||
0xFF,0xFF,0x06,0x06,0x06,0x0E,0x0C,0x0C,0x1C,0x18,0x18,0x38,0x30,
|
||||
// '8'
|
||||
0x38,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x3E,0x3F,0xB8,0xF8,0x3E,0x39,0xF1,0xFD,0xC7,0xC1,0xE0,0xF8,0xEF,0xE3,0xE0,
|
||||
// '9'
|
||||
0x39,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x3C,0x3F,0xB8,0xD8,0x3C,0x1F,0x1D,0xFE,0x7B,0x01,0x81,0xD1,0xCF,0xC3,0xC0,
|
||||
// ':'
|
||||
0x3A,0x08,0x02,0x09,0x02,0x06,
|
||||
0xF0,0x03,0xC0,
|
||||
// ';'
|
||||
0x3B,0x08,0x03,0x0B,0x01,0x06,
|
||||
0x6C,0x00,0x03,0x6A,0x00,
|
||||
// '<'
|
||||
0x3C,0x07,0x0B,0x0A,0x02,0x0F,
|
||||
0x00,0x20,0x3C,0x1F,0x1F,0x0F,0x81,0xF0,0x0F,0x80,0x3E,0x01,0xE0,0x04,
|
||||
// '='
|
||||
0x3D,0x08,0x0B,0x06,0x02,0x0F,
|
||||
0xFF,0xFF,0xFC,0x00,0x00,0x0F,0xFF,0xFF,0xC0,
|
||||
// '>'
|
||||
0x3E,0x07,0x0B,0x0A,0x02,0x0F,
|
||||
0x80,0x1E,0x01,0xF0,0x07,0xC0,0x3E,0x07,0xC3,0xE3,0xE0,0xF0,0x10,0x00,
|
||||
// '?'
|
||||
0x3F,0x04,0x07,0x0D,0x01,0x0A,
|
||||
0x79,0xFA,0x38,0x30,0x61,0x86,0x18,0x30,0x60,0x01,0x83,0x00,
|
||||
// '@'
|
||||
0x40,0x04,0x10,0x10,0x01,0x12,
|
||||
0x07,0xE0,0x1F,0xF8,0x3C,0x1C,0x70,0x06,0x60,0x07,0xE3,0x63,0xC7,0xE3,0xC6,0x63,0xC6,0x66,0xC7,0xFC,0xE3,0x70,0x60,0x00,0x70,0x00,0x3C,0x30,0x1F,0xF0,0x07,0xC0,
|
||||
// 'A'
|
||||
0x41,0x04,0x0C,0x0D,0x00,0x0C,
|
||||
0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30,
|
||||
// 'B'
|
||||
0x42,0x04,0x09,0x0D,0x02,0x0C,
|
||||
0xFC,0x7F,0xB0,0xD8,0x6C,0x37,0xF3,0xF9,0x86,0xC1,0xE0,0xF0,0xFF,0xEF,0xE0,
|
||||
// 'C'
|
||||
0x43,0x04,0x0B,0x0D,0x01,0x0D,
|
||||
0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC,
|
||||
// 'D'
|
||||
0x44,0x04,0x0B,0x0D,0x02,0x0E,
|
||||
0xFE,0x1F,0xF3,0x07,0x60,0x6C,0x07,0x80,0xF0,0x1E,0x03,0xC0,0x78,0x1B,0x07,0x7F,0xCF,0xE0,
|
||||
// 'E'
|
||||
0x45,0x04,0x08,0x0D,0x02,0x0B,
|
||||
0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'F'
|
||||
0x46,0x04,0x08,0x0D,0x02,0x0A,
|
||||
0xFF,0xFF,0xC0,0xC0,0xC0,0xFE,0xFE,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
// 'G'
|
||||
0x47,0x04,0x0B,0x0D,0x01,0x0E,
|
||||
0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x87,0xF0,0xFE,0x03,0xC0,0x6C,0x0D,0xC1,0x9F,0xE0,0xF8,
|
||||
// 'H'
|
||||
0x48,0x04,0x0A,0x0D,0x02,0x0E,
|
||||
0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xFF,0xFF,0xFF,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xC0,
|
||||
// 'I'
|
||||
0x49,0x04,0x02,0x0D,0x02,0x06,
|
||||
0xFF,0xFF,0xFF,0xC0,
|
||||
// 'J'
|
||||
0x4A,0x04,0x05,0x11,0xFF,0x06,
|
||||
0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,0x31,0x8C,0xFE,0xE0,
|
||||
// 'K'
|
||||
0x4B,0x04,0x0B,0x0D,0x02,0x0C,
|
||||
0xC1,0x98,0x63,0x18,0x66,0x0D,0x81,0xE0,0x3C,0x06,0xC0,0xCC,0x18,0xC3,0x0C,0x60,0xCC,0x0C,
|
||||
// 'L'
|
||||
0x4C,0x04,0x08,0x0D,0x02,0x0A,
|
||||
0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'M'
|
||||
0x4D,0x04,0x0C,0x0D,0x02,0x10,
|
||||
0xE0,0x7F,0x0F,0xF0,0xFD,0x8B,0xD9,0xBD,0x9B,0xCF,0x3C,0xF3,0xC6,0x3C,0x63,0xC0,0x3C,0x03,0xC0,0x30,
|
||||
// 'N'
|
||||
0x4E,0x04,0x0A,0x0D,0x02,0x0E,
|
||||
0xE0,0xF8,0x3F,0x0F,0xC3,0xD8,0xF6,0x3C,0xCF,0x1B,0xC6,0xF0,0xFC,0x3F,0x07,0xC1,0xC0,
|
||||
// 'O'
|
||||
0x4F,0x04,0x0C,0x0D,0x01,0x0E,
|
||||
0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,
|
||||
// 'P'
|
||||
0x50,0x04,0x08,0x0D,0x02,0x0B,
|
||||
0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,
|
||||
// 'Q'
|
||||
0x51,0x04,0x0C,0x0F,0x01,0x0E,
|
||||
0x1F,0x83,0xFC,0x70,0xE6,0x06,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0xC0,0x36,0x06,0x70,0xE3,0xFC,0x1F,0x80,0x18,0x00,0xC0,
|
||||
// 'R'
|
||||
0x52,0x04,0x0A,0x0D,0x02,0x0D,
|
||||
0xFC,0x3F,0x8C,0x73,0x0C,0xC3,0x31,0xCF,0xE3,0xF0,0xC6,0x30,0xCC,0x33,0x06,0xC1,0xC0,
|
||||
// 'S'
|
||||
0x53,0x04,0x0A,0x0D,0x01,0x0B,
|
||||
0x3E,0x1F,0xCE,0x13,0x00,0xC0,0x1F,0x03,0xF0,0x0E,0x01,0x80,0x68,0x3B,0xFC,0x7E,0x00,
|
||||
// 'T'
|
||||
0x54,0x04,0x0C,0x0D,0x00,0x0C,
|
||||
0xFF,0xFF,0xFF,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,
|
||||
// 'U'
|
||||
0x55,0x04,0x0A,0x0D,0x02,0x0E,
|
||||
0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x36,0x19,0xFE,0x1E,0x00,
|
||||
// 'V'
|
||||
0x56,0x04,0x0C,0x0D,0x00,0x0C,
|
||||
0xC0,0x36,0x06,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,0x06,0x00,
|
||||
// 'W'
|
||||
0x57,0x04,0x11,0x0D,0x01,0x13,
|
||||
0xC1,0xC1,0xE0,0xE0,0xD8,0xF8,0xCC,0x6C,0x66,0x36,0x33,0x1B,0x18,0xD8,0xD8,0x6C,0x6C,0x36,0x36,0x1F,0x1F,0x07,0x07,0x03,0x83,0x81,0xC1,0xC0,
|
||||
// 'X'
|
||||
0x58,0x04,0x0B,0x0D,0x01,0x0D,
|
||||
0x70,0xE6,0x18,0xE6,0x0D,0xC0,0xF0,0x1C,0x03,0x80,0x78,0x1B,0x07,0x30,0xC7,0x30,0x6E,0x0E,
|
||||
// 'Y'
|
||||
0x59,0x04,0x0C,0x0D,0x00,0x0C,
|
||||
0xE0,0x76,0x06,0x30,0xC1,0x98,0x19,0x80,0xF0,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x04,0x0B,0x0D,0x01,0x0D,
|
||||
0xFF,0xFF,0xFC,0x07,0x01,0xC0,0x30,0x0E,0x03,0x80,0xE0,0x18,0x06,0x01,0xC0,0x7F,0xFF,0xFE,
|
||||
// '['
|
||||
0x5B,0x03,0x04,0x10,0x01,0x07,
|
||||
0xFF,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xFF,
|
||||
// '\'
|
||||
0x5C,0x04,0x06,0x0F,0x00,0x06,
|
||||
0xC3,0x06,0x18,0x61,0xC3,0x0C,0x30,0xE1,0x86,0x18,0x30,0xC0,
|
||||
// ']'
|
||||
0x5D,0x03,0x04,0x10,0x02,0x07,
|
||||
0xFF,0x33,0x33,0x33,0x33,0x33,0x33,0xFF,
|
||||
// '^'
|
||||
0x5E,0x04,0x0B,0x05,0x02,0x0F,
|
||||
0x0E,0x03,0xE0,0xC6,0x30,0x6C,0x06,
|
||||
// '_'
|
||||
0x5F,0x13,0x09,0x02,0x00,0x09,
|
||||
0xFF,0xFF,0xC0,
|
||||
// '`'
|
||||
0x60,0x03,0x04,0x03,0x02,0x09,
|
||||
0xC6,0x30,
|
||||
// 'a'
|
||||
0x61,0x07,0x08,0x0A,0x01,0x0A,
|
||||
0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'b'
|
||||
0x62,0x03,0x09,0x0E,0x02,0x0B,
|
||||
0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF0,
|
||||
// 'c'
|
||||
0x63,0x07,0x08,0x0A,0x01,0x09,
|
||||
0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E,
|
||||
// 'd'
|
||||
0x64,0x03,0x09,0x0E,0x01,0x0B,
|
||||
0x01,0x80,0xC0,0x60,0x33,0xDB,0xFF,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x77,0xF9,0xEC,
|
||||
// 'e'
|
||||
0x65,0x07,0x0A,0x0A,0x01,0x0B,
|
||||
0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,
|
||||
// 'f'
|
||||
0x66,0x03,0x07,0x0E,0x00,0x06,
|
||||
0x1E,0x7C,0xC1,0x8F,0xFF,0xCC,0x18,0x30,0x60,0xC1,0x83,0x06,0x00,
|
||||
// 'g'
|
||||
0x67,0x07,0x09,0x0E,0x01,0x0B,
|
||||
0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x68,0x67,0xF1,0xF0,
|
||||
// 'h'
|
||||
0x68,0x03,0x08,0x0E,0x02,0x0B,
|
||||
0xC0,0xC0,0xC0,0xC0,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
|
||||
// 'i'
|
||||
0x69,0x03,0x02,0x0E,0x02,0x05,
|
||||
0xF0,0xFF,0xFF,0xF0,
|
||||
// 'j'
|
||||
0x6A,0x03,0x04,0x12,0x00,0x05,
|
||||
0x33,0x00,0x33,0x33,0x33,0x33,0x33,0x33,0xEC,
|
||||
// 'k'
|
||||
0x6B,0x03,0x09,0x0E,0x02,0x0A,
|
||||
0xC0,0x60,0x30,0x18,0x0C,0x36,0x33,0x31,0xB0,0xF0,0x78,0x36,0x19,0x8C,0x66,0x18,
|
||||
// 'l'
|
||||
0x6C,0x03,0x02,0x0E,0x02,0x05,
|
||||
0xFF,0xFF,0xFF,0xF0,
|
||||
// 'm'
|
||||
0x6D,0x07,0x0E,0x0A,0x02,0x11,
|
||||
0xDC,0x7B,0xFB,0xEE,0x79,0xF0,0xC3,0xC3,0x0F,0x0C,0x3C,0x30,0xF0,0xC3,0xC3,0x0F,0x0C,0x30,
|
||||
// 'n'
|
||||
0x6E,0x07,0x08,0x0A,0x02,0x0B,
|
||||
0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
|
||||
// 'o'
|
||||
0x6F,0x07,0x0A,0x0A,0x01,0x0B,
|
||||
0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'p'
|
||||
0x70,0x07,0x09,0x0E,0x02,0x0B,
|
||||
0xDE,0x7F,0xB8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0xFF,0x6F,0x30,0x18,0x0C,0x06,0x00,
|
||||
// 'q'
|
||||
0x71,0x07,0x09,0x0E,0x01,0x0B,
|
||||
0x3D,0xBF,0xF8,0xF8,0x3C,0x1E,0x0F,0x07,0xC7,0x7F,0x9E,0xC0,0x60,0x30,0x18,0x0C,
|
||||
// 'r'
|
||||
0x72,0x07,0x06,0x0A,0x02,0x08,
|
||||
0xDF,0xFE,0x30,0xC3,0x0C,0x30,0xC3,0x00,
|
||||
// 's'
|
||||
0x73,0x07,0x08,0x0A,0x01,0x08,
|
||||
0x7C,0xFE,0xC2,0xE0,0x7C,0x1E,0x06,0x86,0xFE,0x78,
|
||||
// 't'
|
||||
0x74,0x04,0x06,0x0D,0x01,0x07,
|
||||
0x61,0x86,0x3F,0xFD,0x86,0x18,0x61,0x86,0x1F,0x3C,
|
||||
// 'u'
|
||||
0x75,0x07,0x08,0x0A,0x02,0x0B,
|
||||
0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,
|
||||
// 'v'
|
||||
0x76,0x07,0x0C,0x0A,0x00,0x0B,
|
||||
0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x19,0x80,0xF0,0x0F,0x00,0x60,
|
||||
// 'w'
|
||||
0x77,0x07,0x0F,0x0A,0x01,0x10,
|
||||
0x63,0x8C,0xC7,0x19,0x8E,0x31,0xB6,0xC3,0x6D,0x86,0xDB,0x0F,0x1E,0x0E,0x38,0x1C,0x70,0x38,0xE0,
|
||||
// 'x'
|
||||
0x78,0x07,0x0A,0x0A,0x01,0x0B,
|
||||
0xE1,0xD8,0x63,0x30,0xCC,0x1E,0x07,0x83,0x30,0xCC,0x61,0xB8,0x70,
|
||||
// 'y'
|
||||
0x79,0x07,0x0C,0x0E,0x00,0x0B,
|
||||
0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,
|
||||
// 'z'
|
||||
0x7A,0x07,0x08,0x0A,0x01,0x09,
|
||||
0xFF,0xFF,0x06,0x0C,0x1C,0x38,0x30,0x70,0xFF,0xFF,
|
||||
// '{'
|
||||
0x7B,0x03,0x08,0x11,0x02,0x0B,
|
||||
0x0F,0x1F,0x18,0x18,0x18,0x18,0x38,0xF0,0xF0,0x38,0x18,0x18,0x18,0x18,0x18,0x1F,0x0F,
|
||||
// '|'
|
||||
0x7C,0x03,0x02,0x12,0x02,0x06,
|
||||
0xFF,0xFF,0xFF,0xFF,0xF0,
|
||||
// '}'
|
||||
0x7D,0x03,0x08,0x11,0x02,0x0B,
|
||||
0xF0,0xF8,0x18,0x18,0x18,0x18,0x1C,0x0F,0x0F,0x1C,0x18,0x18,0x18,0x18,0x18,0xF8,0xF0,
|
||||
// '~'
|
||||
0x7E,0x08,0x0B,0x05,0x02,0x0F,
|
||||
0x00,0x0F,0x87,0xFF,0xC3,0xE0,0x00,
|
||||
// ''
|
||||
0x7F,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '€'
|
||||
0x80,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '<27>'
|
||||
0x81,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '‚'
|
||||
0x82,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'ƒ'
|
||||
0x83,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '„'
|
||||
0x84,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '…'
|
||||
0x85,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '†'
|
||||
0x86,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '‡'
|
||||
0x87,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'ˆ'
|
||||
0x88,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '‰'
|
||||
0x89,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'Š'
|
||||
0x8A,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '‹'
|
||||
0x8B,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'Œ'
|
||||
0x8C,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '<27>'
|
||||
0x8D,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'Ž'
|
||||
0x8E,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '<27>'
|
||||
0x8F,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '<27>'
|
||||
0x90,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '‘'
|
||||
0x91,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '’'
|
||||
0x92,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '“'
|
||||
0x93,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '”'
|
||||
0x94,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '•'
|
||||
0x95,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '–'
|
||||
0x96,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '—'
|
||||
0x97,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '˜'
|
||||
0x98,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '™'
|
||||
0x99,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'š'
|
||||
0x9A,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '›'
|
||||
0x9B,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'œ'
|
||||
0x9C,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// '<27>'
|
||||
0x9D,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'ž'
|
||||
0x9E,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// 'Ÿ'
|
||||
0x9F,0x04,0x09,0x10,0x01,0x0B,
|
||||
0xFF,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0xFF,
|
||||
// ' '
|
||||
0xA0,0x11,0x00,0x00,0x00,0x06,
|
||||
|
||||
// '¡'
|
||||
0xA1,0x07,0x02,0x0D,0x03,0x07,
|
||||
0xF0,0xFF,0xFF,0xC0,
|
||||
// '¢'
|
||||
0xA2,0x04,0x08,0x10,0x02,0x0B,
|
||||
0x04,0x04,0x04,0x1E,0x7F,0x75,0xC4,0xC4,0xC4,0xC4,0x65,0x7F,0x1E,0x04,0x04,0x04,
|
||||
// '£'
|
||||
0xA3,0x04,0x09,0x0D,0x01,0x0B,
|
||||
0x0F,0x0F,0xCE,0x26,0x03,0x01,0x83,0xF9,0xFC,0x30,0x18,0x0C,0x1F,0xFF,0xF8,
|
||||
// '¤'
|
||||
0xA4,0x06,0x0A,0x0A,0x00,0x0B,
|
||||
0x00,0x10,0x13,0x58,0xFE,0x11,0x0C,0x61,0x10,0xFE,0x35,0x90,0x10,
|
||||
// '¥'
|
||||
0xA5,0x04,0x0A,0x0D,0x01,0x0B,
|
||||
0xC0,0xD8,0x66,0x18,0xCC,0x33,0x3F,0xF1,0xE0,0x30,0xFF,0xC3,0x00,0xC0,0x30,0x0C,0x00,
|
||||
// '¦'
|
||||
0xA6,0x04,0x02,0x10,0x02,0x06,
|
||||
0xFF,0xFC,0x3F,0xFF,
|
||||
// '§'
|
||||
0xA7,0x04,0x07,0x0F,0x01,0x09,
|
||||
0x3C,0xF9,0x83,0x03,0x0F,0x33,0x63,0x66,0x78,0x60,0x60,0xCF,0x9E,0x00,
|
||||
// '¨'
|
||||
0xA8,0x03,0x06,0x02,0x02,0x09,
|
||||
0xCF,0x30,
|
||||
// '©'
|
||||
0xA9,0x04,0x0D,0x0D,0x02,0x12,
|
||||
0x0F,0x81,0x83,0x18,0x0C,0x8F,0x28,0x80,0xC8,0x06,0x40,0x32,0x01,0x88,0x8A,0x38,0x98,0x0C,0x60,0xC0,0xF8,0x00,
|
||||
// 'ª'
|
||||
0xAA,0x04,0x08,0x09,0x01,0x08,
|
||||
0x7C,0x02,0x7E,0xC2,0x82,0xC6,0x7A,0x00,0xFE,
|
||||
// '«'
|
||||
0xAB,0x08,0x08,0x08,0x01,0x0B,
|
||||
0x11,0x33,0x66,0xCC,0xCC,0x66,0x33,0x11,
|
||||
// '¬'
|
||||
0xAC,0x09,0x0B,0x05,0x02,0x0F,
|
||||
0xFF,0xFF,0xFC,0x01,0x80,0x30,0x06,
|
||||
// ''
|
||||
0xAD,0x0B,0x05,0x02,0x01,0x07,
|
||||
0xFF,0xC0,
|
||||
// '®'
|
||||
0xAE,0x04,0x0D,0x0D,0x02,0x12,
|
||||
0x0F,0x81,0x83,0x18,0x0C,0x9E,0x28,0x88,0xC4,0x46,0x3C,0x31,0x21,0x88,0x8A,0x46,0x98,0x0C,0x60,0xC0,0xF8,0x00,
|
||||
// '¯'
|
||||
0xAF,0x04,0x05,0x02,0x02,0x09,
|
||||
0xFF,0xC0,
|
||||
// '°'
|
||||
0xB0,0x04,0x06,0x06,0x02,0x09,
|
||||
0x7B,0x38,0x61,0xCD,0xE0,
|
||||
// '±'
|
||||
0xB1,0x06,0x0C,0x0B,0x02,0x0F,
|
||||
0x06,0x00,0x60,0x06,0x0F,0xFF,0xFF,0xF0,0x60,0x06,0x00,0x60,0x00,0x0F,0xFF,0xFF,0xF0,
|
||||
// '²'
|
||||
0xB2,0x04,0x05,0x07,0x01,0x07,
|
||||
0x74,0x42,0x22,0x23,0xE0,
|
||||
// '³'
|
||||
0xB3,0x04,0x05,0x07,0x01,0x07,
|
||||
0xF0,0x5C,0x30,0x8F,0xC0,
|
||||
// '´'
|
||||
0xB4,0x03,0x04,0x03,0x03,0x09,
|
||||
0x36,0xC0,
|
||||
// 'µ'
|
||||
0xB5,0x07,0x09,0x0E,0x02,0x0B,
|
||||
0xC3,0x61,0xB0,0xD8,0x6C,0x36,0x1B,0x0D,0xCE,0xFF,0xEC,0xF0,0x18,0x0C,0x06,0x00,
|
||||
// '¶'
|
||||
0xB6,0x04,0x08,0x0F,0x01,0x0B,
|
||||
0x3F,0x79,0xF9,0xF9,0xF9,0xF9,0x79,0x09,0x09,0x09,0x09,0x09,0x09,0x09,0x09,
|
||||
// '·'
|
||||
0xB7,0x0A,0x02,0x02,0x02,0x06,
|
||||
0xF0,
|
||||
// '¸'
|
||||
0xB8,0x11,0x04,0x03,0x03,0x09,
|
||||
0x23,0xF0,
|
||||
// '¹'
|
||||
0xB9,0x04,0x05,0x07,0x01,0x07,
|
||||
0xE1,0x08,0x42,0x13,0xE0,
|
||||
// 'º'
|
||||
0xBA,0x04,0x07,0x09,0x01,0x08,
|
||||
0x38,0x8A,0x0C,0x18,0x28,0x8E,0x00,0xFE,
|
||||
// '»'
|
||||
0xBB,0x08,0x08,0x08,0x02,0x0B,
|
||||
0x88,0xCC,0x66,0x33,0x33,0x66,0xCC,0x88,
|
||||
// '¼'
|
||||
0xBC,0x04,0x10,0x0D,0x01,0x11,
|
||||
0xE0,0x18,0x20,0x10,0x20,0x20,0x20,0x60,0x20,0x40,0x20,0x80,0xF9,0x86,0x01,0x0A,0x02,0x12,0x06,0x22,0x04,0x3F,0x08,0x02,0x18,0x02,
|
||||
// '½'
|
||||
0xBD,0x04,0x0F,0x0D,0x01,0x11,
|
||||
0xE0,0x18,0x40,0x20,0x80,0x81,0x03,0x02,0x04,0x04,0x10,0x3E,0x67,0x00,0x91,0x02,0x02,0x0C,0x08,0x10,0x20,0x40,0x81,0x83,0xE0,
|
||||
// '¾'
|
||||
0xBE,0x04,0x10,0x0D,0x01,0x11,
|
||||
0xF0,0x18,0x08,0x10,0x70,0x20,0x18,0x60,0x08,0x40,0x18,0x80,0xF1,0x86,0x01,0x0A,0x02,0x12,0x06,0x22,0x04,0x3F,0x08,0x02,0x18,0x02,
|
||||
// '¿'
|
||||
0xBF,0x07,0x07,0x0E,0x02,0x0A,
|
||||
0x18,0x30,0x00,0xC1,0x83,0x0C,0x18,0x61,0x83,0x07,0x17,0xE7,0x80,
|
||||
// 'À'
|
||||
0xC0,0x01,0x0C,0x10,0x00,0x0C,
|
||||
0x06,0x00,0x30,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,
|
||||
// 'Á'
|
||||
0xC1,0x01,0x0C,0x10,0x00,0x0C,
|
||||
0x03,0x00,0x60,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,
|
||||
// 'Â'
|
||||
0xC2,0x01,0x0C,0x10,0x00,0x0C,
|
||||
0x06,0x00,0x90,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,
|
||||
// 'Ã'
|
||||
0xC3,0x01,0x0C,0x10,0x00,0x0C,
|
||||
0x0C,0x81,0x30,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,
|
||||
// 'Ä'
|
||||
0xC4,0x01,0x0C,0x10,0x00,0x0C,
|
||||
0x19,0x81,0x98,0x00,0x00,0x60,0x06,0x00,0xF0,0x0F,0x01,0x98,0x19,0x81,0x98,0x30,0xC3,0xFC,0x7F,0xE6,0x06,0x60,0x6C,0x03,
|
||||
// 'Å'
|
||||
0xC5,0x00,0x0C,0x11,0x00,0x0C,
|
||||
0x06,0x00,0x90,0x09,0x00,0x90,0x06,0x00,0x60,0x0F,0x00,0xF0,0x19,0x81,0x98,0x19,0x83,0x0C,0x3F,0xC7,0xFE,0x60,0x66,0x06,0xC0,0x30,
|
||||
// 'Æ'
|
||||
0xC6,0x04,0x10,0x0D,0x00,0x11,
|
||||
0x07,0xFF,0x07,0xFF,0x06,0xC0,0x0C,0xC0,0x0C,0xC0,0x18,0xFF,0x18,0xFF,0x30,0xC0,0x3F,0xC0,0x3F,0xC0,0x60,0xC0,0x60,0xFF,0xC0,0xFF,
|
||||
// 'Ç'
|
||||
0xC7,0x04,0x0B,0x10,0x01,0x0D,
|
||||
0x0F,0xC7,0xFD,0xC0,0xB0,0x0C,0x01,0x80,0x30,0x06,0x00,0xC0,0x0C,0x01,0xC0,0x9F,0xF0,0xFC,0x02,0x00,0x60,0x3C,
|
||||
// 'È'
|
||||
0xC8,0x01,0x08,0x10,0x02,0x0B,
|
||||
0x30,0x18,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'É'
|
||||
0xC9,0x01,0x08,0x10,0x02,0x0B,
|
||||
0x18,0x30,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'Ê'
|
||||
0xCA,0x01,0x08,0x10,0x02,0x0B,
|
||||
0x38,0x6C,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'Ë'
|
||||
0xCB,0x01,0x08,0x10,0x02,0x0B,
|
||||
0x66,0x66,0x00,0xFF,0xFF,0xC0,0xC0,0xC0,0xFF,0xFF,0xC0,0xC0,0xC0,0xC0,0xFF,0xFF,
|
||||
// 'Ì'
|
||||
0xCC,0x01,0x05,0x10,0x00,0x06,
|
||||
0x61,0x80,0x63,0x18,0xC6,0x31,0x8C,0x63,0x18,0xC6,
|
||||
// 'Í'
|
||||
0xCD,0x01,0x04,0x10,0x01,0x06,
|
||||
0x6C,0x06,0x66,0x66,0x66,0x66,0x66,0x66,
|
||||
// 'Î'
|
||||
0xCE,0x01,0x06,0x10,0x00,0x06,
|
||||
0x31,0x20,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,
|
||||
// 'Ï'
|
||||
0xCF,0x01,0x06,0x10,0x00,0x06,
|
||||
0xCF,0x30,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC3,0x0C,
|
||||
// 'Ð'
|
||||
0xD0,0x04,0x0D,0x0D,0x00,0x0E,
|
||||
0x3F,0x81,0xFF,0x0C,0x1C,0x60,0x73,0x01,0xFF,0x0F,0xF8,0x66,0x03,0x30,0x19,0x81,0xCC,0x1C,0x7F,0xC3,0xF8,0x00,
|
||||
// 'Ñ'
|
||||
0xD1,0x01,0x0A,0x10,0x02,0x0E,
|
||||
0x19,0x09,0x80,0x03,0x83,0xE0,0xFC,0x3F,0x0F,0x63,0xD8,0xF3,0x3C,0x6F,0x1B,0xC3,0xF0,0xFC,0x1F,0x07,
|
||||
// 'Ò'
|
||||
0xD2,0x01,0x0C,0x10,0x01,0x0E,
|
||||
0x06,0x00,0x30,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,
|
||||
// 'Ó'
|
||||
0xD3,0x01,0x0C,0x10,0x01,0x0E,
|
||||
0x03,0x00,0x60,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,
|
||||
// 'Ô'
|
||||
0xD4,0x01,0x0C,0x10,0x01,0x0E,
|
||||
0x06,0x00,0x90,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,
|
||||
// 'Õ'
|
||||
0xD5,0x01,0x0C,0x10,0x01,0x0E,
|
||||
0x0C,0x81,0x30,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,
|
||||
// 'Ö'
|
||||
0xD6,0x01,0x0C,0x10,0x01,0x0E,
|
||||
0x19,0x81,0x98,0x00,0x01,0xF8,0x3F,0xC7,0x0E,0x60,0x6C,0x03,0xC0,0x3C,0x03,0xC0,0x3C,0x03,0x60,0x67,0x0E,0x3F,0xC1,0xF8,
|
||||
// '×'
|
||||
0xD7,0x06,0x0A,0x0A,0x02,0x0F,
|
||||
0x40,0xB8,0x77,0x38,0xFC,0x1E,0x07,0x83,0xF1,0xCE,0xE1,0xD0,0x20,
|
||||
// 'Ø'
|
||||
0xD8,0x03,0x0E,0x0F,0x00,0x0E,
|
||||
0x00,0x00,0x3E,0x21,0xFD,0x0E,0x1C,0x70,0x71,0x83,0x66,0x19,0x98,0xC6,0x66,0x19,0xB0,0x63,0x83,0x8E,0x1C,0x2F,0xE1,0x1F,0x00,0x00,0x00,
|
||||
// 'Ù'
|
||||
0xD9,0x01,0x0A,0x10,0x02,0x0E,
|
||||
0x18,0x03,0x00,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,
|
||||
// 'Ú'
|
||||
0xDA,0x01,0x0A,0x10,0x02,0x0E,
|
||||
0x0C,0x06,0x00,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,
|
||||
// 'Û'
|
||||
0xDB,0x01,0x0A,0x10,0x02,0x0E,
|
||||
0x0C,0x04,0x80,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,
|
||||
// 'Ü'
|
||||
0xDC,0x01,0x0A,0x10,0x02,0x0E,
|
||||
0x33,0x0C,0xC0,0x03,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xF0,0x3C,0x0F,0x03,0xC0,0xD8,0x67,0xF8,0x78,
|
||||
// 'Ý'
|
||||
0xDD,0x01,0x0C,0x10,0x00,0x0C,
|
||||
0x06,0x00,0xC0,0x00,0x0E,0x07,0x60,0x63,0x0C,0x19,0x81,0x98,0x0F,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,0x06,0x00,0x60,
|
||||
// 'Þ'
|
||||
0xDE,0x04,0x08,0x0D,0x02,0x0B,
|
||||
0xC0,0xC0,0xFC,0xFE,0xC7,0xC3,0xC3,0xC7,0xFE,0xFC,0xC0,0xC0,0xC0,
|
||||
// 'ß'
|
||||
0xDF,0x03,0x09,0x0E,0x02,0x0B,
|
||||
0x3C,0x3F,0x39,0xD8,0x6C,0x66,0x63,0x31,0x8C,0xC3,0x60,0xF0,0x7A,0x7D,0xF6,0x70,
|
||||
// 'à'
|
||||
0xE0,0x03,0x08,0x0E,0x01,0x0A,
|
||||
0x30,0x18,0x0C,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'á'
|
||||
0xE1,0x03,0x08,0x0E,0x01,0x0A,
|
||||
0x06,0x0C,0x18,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'â'
|
||||
0xE2,0x03,0x08,0x0E,0x01,0x0A,
|
||||
0x18,0x3C,0x66,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'ã'
|
||||
0xE3,0x03,0x08,0x0E,0x01,0x0A,
|
||||
0x32,0x4C,0x00,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'ä'
|
||||
0xE4,0x03,0x08,0x0E,0x01,0x0A,
|
||||
0x66,0x66,0x00,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'å'
|
||||
0xE5,0x01,0x08,0x10,0x01,0x0A,
|
||||
0x1C,0x22,0x22,0x22,0x1C,0x00,0x3C,0x7E,0x47,0x03,0x3F,0xFF,0xC3,0xC7,0xFF,0x7B,
|
||||
// 'æ'
|
||||
0xE6,0x07,0x0F,0x0A,0x01,0x11,
|
||||
0x3C,0x78,0xFD,0xF9,0x1E,0x38,0x18,0x33,0xFF,0xFF,0xFF,0xF0,0xC0,0x63,0xC1,0xFD,0xFE,0xF0,0xF8,
|
||||
// 'ç'
|
||||
0xE7,0x07,0x08,0x0D,0x01,0x09,
|
||||
0x1E,0x7F,0x61,0xC0,0xC0,0xC0,0xC0,0x61,0x7F,0x1E,0x04,0x06,0x1E,
|
||||
// 'è'
|
||||
0xE8,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x30,0x06,0x00,0xC0,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,
|
||||
// 'é'
|
||||
0xE9,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x06,0x03,0x01,0x80,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,
|
||||
// 'ê'
|
||||
0xEA,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x0C,0x07,0x83,0x30,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,
|
||||
// 'ë'
|
||||
0xEB,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x33,0x0C,0xC0,0x00,0x00,0x1F,0x1F,0xE6,0x1F,0x03,0xFF,0xFF,0xFC,0x01,0x81,0x7F,0xC7,0xE0,
|
||||
// 'ì'
|
||||
0xEC,0x03,0x04,0x0E,0x00,0x05,
|
||||
0xC6,0x30,0x33,0x33,0x33,0x33,0x33,
|
||||
// 'í'
|
||||
0xED,0x03,0x04,0x0E,0x01,0x05,
|
||||
0x36,0xC0,0x66,0x66,0x66,0x66,0x66,
|
||||
// 'î'
|
||||
0xEE,0x03,0x06,0x0E,0x00,0x05,
|
||||
0x31,0xEC,0xC0,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC0,
|
||||
// 'ï'
|
||||
0xEF,0x03,0x06,0x0E,0x00,0x05,
|
||||
0xCF,0x30,0x00,0x30,0xC3,0x0C,0x30,0xC3,0x0C,0x30,0xC0,
|
||||
// 'ð'
|
||||
0xF0,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x10,0x07,0xC7,0xC0,0x18,0x1F,0x1F,0xE6,0x1F,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'ñ'
|
||||
0xF1,0x03,0x08,0x0E,0x02,0x0B,
|
||||
0x32,0x4C,0x00,0x00,0xDE,0xFE,0xE7,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,
|
||||
// 'ò'
|
||||
0xF2,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x30,0x06,0x00,0xC0,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'ó'
|
||||
0xF3,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x06,0x03,0x01,0x80,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'ô'
|
||||
0xF4,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x0C,0x07,0x83,0x30,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'õ'
|
||||
0xF5,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x19,0x09,0x80,0x00,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// 'ö'
|
||||
0xF6,0x03,0x0A,0x0E,0x01,0x0B,
|
||||
0x33,0x0C,0xC0,0x00,0x00,0x1E,0x1F,0xE6,0x1B,0x03,0xC0,0xF0,0x3C,0x0D,0x86,0x7F,0x87,0x80,
|
||||
// '÷'
|
||||
0xF7,0x07,0x0C,0x08,0x02,0x0F,
|
||||
0x06,0x00,0x60,0x00,0x0F,0xFF,0xFF,0xF0,0x00,0x06,0x00,0x60,
|
||||
// 'ø'
|
||||
0xF8,0x06,0x0C,0x0C,0x00,0x0B,
|
||||
0x00,0x00,0xF2,0x1F,0xC3,0x0C,0x61,0xE6,0x26,0x64,0x67,0x86,0x30,0xC3,0xFC,0x4F,0x00,0x00,
|
||||
// 'ù'
|
||||
0xF9,0x03,0x08,0x0E,0x02,0x0B,
|
||||
0x60,0x30,0x18,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,
|
||||
// 'ú'
|
||||
0xFA,0x03,0x08,0x0E,0x02,0x0B,
|
||||
0x0C,0x18,0x30,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,
|
||||
// 'û'
|
||||
0xFB,0x03,0x08,0x0E,0x02,0x0B,
|
||||
0x18,0x3C,0x66,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,
|
||||
// 'ü'
|
||||
0xFC,0x03,0x08,0x0E,0x02,0x0B,
|
||||
0x66,0x66,0x00,0x00,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xC3,0xE7,0x7F,0x7B,
|
||||
// 'ý'
|
||||
0xFD,0x03,0x0C,0x12,0x00,0x0B,
|
||||
0x03,0x00,0x60,0x0C,0x00,0x00,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,
|
||||
// 'þ'
|
||||
0xFE,0x03,0x09,0x12,0x02,0x0B,
|
||||
0xC0,0x60,0x30,0x18,0x0D,0xE7,0xFB,0x8F,0x83,0xC1,0xE0,0xF0,0x7C,0x7F,0xF6,0xF3,0x01,0x80,0xC0,0x60,0x00,
|
||||
// 'ÿ'
|
||||
0xFF,0x03,0x0C,0x12,0x00,0x0B,
|
||||
0x1B,0x01,0xB0,0x00,0x00,0x00,0x60,0x66,0x06,0x30,0xC3,0x0C,0x19,0x81,0x98,0x0F,0x00,0xF0,0x06,0x00,0x60,0x06,0x00,0xC0,0x3C,0x03,0x80,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
331
components/epaper/minya24.c
Normal file
331
components/epaper/minya24.c
Normal file
@ -0,0 +1,331 @@
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// on Arduinos. It can however handle any ttf font that has been converted
|
||||
// using the conversion program. These could be fixed width or proportional
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// minya24.c
|
||||
// Point Size : 24
|
||||
// Memory usage : 2807 bytes
|
||||
// # characters : 95
|
||||
|
||||
// Header Format (to make Arduino UTFT Compatible):
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
unsigned char tft_minya24[] =
|
||||
{
|
||||
0x00, 0x15, 0x00, 0x00,
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
|
||||
// ' '
|
||||
0x20,0x13,0x00,0x00,0x00,0x07,
|
||||
|
||||
// '!'
|
||||
0x21,0x02,0x05,0x12,0x00,0x05,
|
||||
0x11,0x8C,0x63,0x18,0xC6,0x31,0x8C,0x42,0x01,0xCE,0x73,0x80,
|
||||
// '"'
|
||||
0x22,0x01,0x06,0x08,0x00,0x06,
|
||||
0x01,0xA6,0xDB,0x6D,0xB6,0xC0,
|
||||
// '#'
|
||||
0x23,0x04,0x0C,0x0E,0x00,0x0B,
|
||||
0x04,0x80,0x6C,0x0C,0x80,0xD8,0x7F,0xE7,0xFE,0x1B,0x01,0xB0,0x7F,0xE7,0xFC,0x12,0x03,0x20,0x32,0x00,0x00,
|
||||
// '$'
|
||||
0x24,0x02,0x0A,0x11,0x00,0x0B,
|
||||
0x04,0x01,0x61,0xF8,0xFE,0x65,0x19,0x06,0x40,0xF0,0x1F,0x01,0xE0,0x4C,0x93,0x7C,0xCF,0xE0,0x60,0x10,0x04,0x00,
|
||||
// '%'
|
||||
0x25,0x01,0x0D,0x14,0x01,0x0F,
|
||||
0x00,0x01,0xC1,0x1F,0x19,0x8C,0xCC,0x6C,0x63,0x61,0x36,0x0F,0xB0,0x1B,0x00,0x18,0x01,0x80,0x0C,0x00,0xCE,0x06,0xF8,0x6C,0x66,0x63,0x33,0x13,0x0F,0x98,0x38,0x00,0x00,
|
||||
// '&'
|
||||
0x26,0x02,0x0E,0x11,0x00,0x0D,
|
||||
0x0E,0x00,0x7C,0x01,0xB0,0x06,0xC0,0x1E,0x00,0x38,0x00,0xC3,0x07,0x8C,0x37,0x60,0xCD,0x86,0x1E,0x18,0x70,0x41,0xE1,0x07,0xC6,0x33,0x9F,0x86,0x38,0x00,
|
||||
// '''
|
||||
0x27,0x02,0x03,0x08,0x00,0x03,
|
||||
0x6D,0xB6,0xD8,
|
||||
// '('
|
||||
0x28,0x01,0x05,0x14,0x02,0x07,
|
||||
0x00,0x8E,0x66,0x33,0x18,0xC6,0x31,0x8C,0x61,0x0C,0x63,0x8C,0x00,
|
||||
// ')'
|
||||
0x29,0x01,0x06,0x15,0x00,0x07,
|
||||
0x01,0x86,0x0C,0x18,0x61,0x82,0x08,0x30,0xC2,0x08,0x61,0x86,0x30,0xC6,0x10,0x00,
|
||||
// '*'
|
||||
0x2A,0x04,0x0A,0x0D,0x01,0x0B,
|
||||
0x08,0x03,0x04,0xC1,0xF6,0x7F,0x07,0x81,0xC0,0xF8,0x3F,0x1B,0xCC,0xD8,0x30,0x0C,0x00,
|
||||
// '+'
|
||||
0x2B,0x06,0x0A,0x0A,0x01,0x0B,
|
||||
0x00,0x03,0x00,0xC0,0x30,0x7F,0xBF,0xE0,0xC0,0x30,0x0C,0x00,0x00,
|
||||
// ','
|
||||
0x2C,0x10,0x05,0x07,0x00,0x05,
|
||||
0x33,0x9C,0x63,0x20,0x00,
|
||||
// '-'
|
||||
0x2D,0x09,0x07,0x02,0x00,0x07,
|
||||
0x7D,0xF8,
|
||||
// '.'
|
||||
0x2E,0x10,0x04,0x04,0x01,0x05,
|
||||
0x6E,0xE6,
|
||||
// '/'
|
||||
0x2F,0x01,0x0C,0x13,0x00,0x0B,
|
||||
0x00,0x00,0x06,0x00,0x60,0x0C,0x00,0xC0,0x18,0x01,0x80,0x30,0x03,0x00,0x60,0x06,0x00,0xC0,0x0C,0x01,0x80,0x18,0x03,0x00,0x30,0x06,0x00,0x40,0x00,
|
||||
// '0'
|
||||
0x30,0x08,0x0B,0x0B,0x00,0x0B,
|
||||
0x0E,0x03,0xE0,0xC6,0x30,0x66,0x0C,0xC0,0x98,0x33,0x06,0x61,0xC7,0xF0,0x7C,0x00,
|
||||
// '1'
|
||||
0x31,0x08,0x0A,0x0D,0x00,0x09,
|
||||
0x04,0x1F,0x03,0xC0,0x30,0x0C,0x03,0x00,0xC0,0x30,0x0C,0x03,0x07,0xF9,0xFE,0x00,0x00,
|
||||
// '2'
|
||||
0x32,0x06,0x0A,0x0E,0x00,0x0A,
|
||||
0x0E,0x07,0xC3,0x30,0xCC,0x03,0x01,0x80,0x60,0x30,0x18,0x0C,0x03,0x01,0xF8,0x7F,0xC0,0x20,
|
||||
// '3'
|
||||
0x33,0x08,0x09,0x10,0x00,0x08,
|
||||
0x78,0x3F,0x81,0x81,0x81,0xC0,0xC0,0xE0,0x78,0x06,0x01,0x01,0x80,0xC0,0xE1,0xE0,0xC0,0x00,
|
||||
// '4'
|
||||
0x34,0x03,0x0B,0x13,0x00,0x0A,
|
||||
0x00,0x00,0xC0,0x18,0x03,0x00,0x60,0x08,0x03,0x00,0x60,0x0D,0x83,0x20,0x64,0x18,0x83,0x10,0xC6,0x1F,0xF3,0xFE,0x03,0x00,0x60,0x0C,0x00,
|
||||
// '5'
|
||||
0x35,0x09,0x0A,0x0E,0x00,0x0A,
|
||||
0x3F,0x8F,0xE3,0x00,0x80,0x60,0x1F,0x87,0xF0,0x06,0x01,0x80,0x60,0x19,0x86,0x7F,0x07,0x80,
|
||||
// '6'
|
||||
0x36,0x03,0x0A,0x12,0x00,0x0A,
|
||||
0x00,0x01,0x80,0xE0,0x30,0x18,0x06,0x03,0x00,0xC0,0x60,0x1B,0x87,0xF1,0x86,0x61,0x90,0x66,0x19,0x86,0x3F,0x07,0x80,
|
||||
// '7'
|
||||
0x37,0x09,0x0A,0x0E,0x00,0x0A,
|
||||
0x7F,0x9F,0xF0,0x18,0x0C,0x06,0x01,0x80,0xC0,0x30,0x18,0x06,0x01,0x80,0x40,0x10,0x0C,0x00,
|
||||
// '8'
|
||||
0x38,0x03,0x0B,0x11,0x00,0x0B,
|
||||
0x0F,0x07,0xF0,0xC3,0x30,0x66,0x0C,0x63,0x87,0xE0,0xF8,0x39,0xCE,0x19,0x81,0x30,0x34,0x06,0xC1,0x98,0x71,0xFC,0x1F,0x00,
|
||||
// '9'
|
||||
0x39,0x07,0x0A,0x11,0x00,0x0A,
|
||||
0x1E,0x0F,0xC6,0x19,0x86,0x41,0x98,0x66,0x18,0xFE,0x1D,0x80,0x40,0x30,0x0C,0x06,0x03,0x01,0xC0,0x20,0x00,0x00,
|
||||
// ':'
|
||||
0x3A,0x0A,0x05,0x0A,0x00,0x05,
|
||||
0x33,0x9C,0x60,0x00,0xCE,0x71,0x80,
|
||||
// ';'
|
||||
0x3B,0x09,0x05,0x0D,0x00,0x06,
|
||||
0x33,0xDE,0x60,0x00,0x0E,0x73,0x8C,0xC0,0x00,
|
||||
// '<'
|
||||
0x3C,0x06,0x0A,0x0C,0x00,0x09,
|
||||
0x00,0x00,0xE0,0x70,0x38,0x1C,0x1C,0x03,0x00,0x70,0x0E,0x01,0xC0,0x10,0x00,
|
||||
// '='
|
||||
0x3D,0x09,0x08,0x06,0x01,0x0A,
|
||||
0xFF,0xFE,0x00,0x00,0x7F,0xFF,
|
||||
// '>'
|
||||
0x3E,0x06,0x0A,0x0C,0x00,0x09,
|
||||
0x00,0x18,0x03,0x80,0x70,0x0E,0x00,0xE0,0x30,0x38,0x1C,0x0E,0x02,0x00,0x00,
|
||||
// '?'
|
||||
0x3F,0x02,0x09,0x12,0x00,0x09,
|
||||
0x1E,0x1F,0x98,0x6C,0x30,0x18,0x18,0x38,0x30,0x30,0x18,0x0C,0x02,0x01,0x00,0x00,0x60,0x78,0x3C,0x0C,0x00,
|
||||
// '@'
|
||||
0x40,0x02,0x11,0x11,0x00,0x11,
|
||||
0x01,0xF0,0x03,0xFE,0x03,0x03,0x83,0x00,0xC3,0x04,0x31,0x1F,0x19,0x9F,0x0C,0xCC,0x86,0x4C,0x43,0x24,0x21,0x12,0x39,0x89,0xF7,0x84,0x71,0x83,0x00,0x00,0xC1,0x80,0x3F,0xC0,0x0F,0x80,0x00,
|
||||
// 'A'
|
||||
0x41,0x02,0x12,0x13,0x00,0x10,
|
||||
0x00,0x00,0x01,0xF0,0x00,0x7E,0x00,0x03,0x80,0x01,0xA0,0x00,0x6C,0x00,0x1B,0x00,0x0C,0x40,0x03,0x18,0x01,0x86,0x00,0x61,0x80,0x1F,0xE0,0x0F,0xFC,0x03,0x03,0x01,0x80,0xC0,0x60,0x10,0x18,0x1F,0x9F,0xC7,0xEF,0xF8,0x00,
|
||||
// 'B'
|
||||
0x42,0x02,0x0E,0x13,0x00,0x0E,
|
||||
0x7F,0x81,0xFF,0x81,0x86,0x06,0x18,0x18,0xC0,0x66,0x01,0xFC,0x07,0xFC,0x1C,0x30,0x60,0x61,0x81,0x86,0x06,0x18,0x18,0x60,0x61,0x81,0x06,0x0C,0x18,0xE0,0xFE,0x03,0xE0,0x00,
|
||||
// 'C'
|
||||
0x43,0x02,0x0F,0x12,0x00,0x0F,
|
||||
0x03,0xF0,0x1F,0xE0,0x70,0xC1,0x80,0x83,0x00,0x04,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x06,0x00,0x0E,0x01,0x0E,0x0E,0x0F,0xF8,0x07,0xE0,
|
||||
// 'D'
|
||||
0x44,0x02,0x0F,0x13,0x00,0x0F,
|
||||
0x3F,0xC0,0x7F,0xE0,0x60,0xE0,0xC0,0xC1,0x80,0xC3,0x01,0x86,0x03,0x0C,0x02,0x18,0x04,0x30,0x08,0x60,0x30,0xC0,0x61,0x80,0x83,0x03,0x06,0x0C,0x0C,0x38,0x18,0xE0,0xFF,0x81,0xF8,0x00,
|
||||
// 'E'
|
||||
0x45,0x02,0x0D,0x13,0x00,0x0D,
|
||||
0x3F,0xF1,0xFF,0x86,0x0C,0x30,0x61,0x80,0x0C,0x40,0x62,0x03,0xF0,0x1F,0x80,0xC4,0x06,0x20,0x30,0x01,0x80,0x0C,0x00,0x60,0xC3,0x06,0x7F,0xF3,0xFF,0x80,0x00,
|
||||
// 'F'
|
||||
0x46,0x01,0x0E,0x13,0x00,0x0E,
|
||||
0x00,0x01,0xFF,0xE7,0xFF,0x86,0x06,0x18,0x18,0x63,0x01,0x8C,0x03,0xF0,0x0F,0xC0,0x63,0x01,0x8C,0x06,0x30,0x18,0x00,0x60,0x01,0x80,0x06,0x00,0x3F,0x81,0xFE,0x00,0x00,0x00,
|
||||
// 'G'
|
||||
0x47,0x01,0x11,0x14,0x00,0x11,
|
||||
0x00,0x00,0x03,0xC8,0x03,0xFC,0x03,0x0E,0x03,0x03,0x01,0x00,0x01,0x80,0x00,0xC0,0x00,0x60,0x03,0x30,0x3F,0xD8,0x1F,0x0C,0x01,0x86,0x00,0xC3,0x80,0x60,0xC0,0x30,0x70,0x38,0x1C,0x3C,0x07,0xF6,0x01,0xF3,0x80,0x01,0xE0,
|
||||
// 'H'
|
||||
0x48,0x01,0x10,0x13,0x00,0x10,
|
||||
0x00,0x00,0x7C,0x0F,0x1C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x08,0x0C,0x08,0x0F,0xF8,0x0F,0xF8,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x1A,0x7C,0x1F,0x7C,0x10,
|
||||
// 'I'
|
||||
0x49,0x02,0x08,0x13,0x00,0x08,
|
||||
0x7E,0x7E,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,
|
||||
// 'J'
|
||||
0x4A,0x01,0x0C,0x14,0x00,0x0B,
|
||||
0x00,0x00,0x7E,0x07,0xE0,0x18,0x01,0x80,0x18,0x01,0x80,0x18,0x00,0x80,0x08,0x00,0x80,0x18,0x61,0x84,0x18,0x41,0x8C,0x18,0xC3,0x06,0x70,0x7E,0x01,0x80,
|
||||
// 'K'
|
||||
0x4B,0x02,0x11,0x13,0x00,0x10,
|
||||
0x7E,0x7E,0x3F,0x3E,0x06,0x06,0x03,0x06,0x01,0x86,0x00,0xC6,0x00,0x66,0x00,0x37,0x00,0x1F,0x80,0x0E,0x60,0x06,0x10,0x03,0x0C,0x01,0x06,0x00,0x81,0x00,0x60,0x80,0x30,0x66,0x7E,0x1B,0x3F,0x0F,0x80,0x01,0x80,
|
||||
// 'L'
|
||||
0x4C,0x02,0x0D,0x11,0x00,0x0D,
|
||||
0x7E,0x03,0xF0,0x06,0x00,0x30,0x01,0x80,0x0C,0x00,0x60,0x03,0x00,0x18,0x00,0xC0,0x06,0x00,0x30,0x01,0x81,0x0C,0x08,0x60,0x4F,0xFF,0x7F,0xF8,
|
||||
// 'M'
|
||||
0x4D,0x02,0x14,0x12,0x00,0x13,
|
||||
0x7C,0x07,0x87,0xC0,0x7C,0x0C,0x06,0x00,0xE0,0xE0,0x0E,0x0E,0x00,0xE0,0xE0,0x1B,0x1E,0x01,0xB1,0x60,0x0B,0x16,0x00,0x9B,0x60,0x09,0xA6,0x00,0x9E,0x60,0x08,0xE6,0x00,0x8C,0x60,0x08,0xC6,0x03,0x8C,0x7E,0x78,0x47,0xE0,0x00,0x00,
|
||||
// 'N'
|
||||
0x4E,0x01,0x12,0x13,0x00,0x12,
|
||||
0x00,0x00,0x1F,0x03,0xF3,0xC0,0x7C,0x38,0x10,0x0E,0x04,0x03,0xC1,0x00,0xB0,0x40,0x26,0x10,0x09,0x84,0x02,0x31,0x00,0x8C,0x40,0x21,0x90,0x08,0x74,0x06,0x0F,0x01,0x81,0xC0,0x60,0x70,0x78,0x0C,0x3E,0x03,0x00,0x00,0x40,
|
||||
// 'O'
|
||||
0x4F,0x02,0x11,0x12,0x00,0x11,
|
||||
0x03,0xE0,0x07,0xFC,0x07,0x07,0x06,0x01,0x82,0x00,0x63,0x00,0x11,0x80,0x0C,0x80,0x06,0x40,0x03,0x20,0x01,0x98,0x00,0xCC,0x00,0x66,0x00,0x31,0x80,0x30,0xE0,0x18,0x38,0x18,0x0F,0xF8,0x01,0xF0,0x00,
|
||||
// 'P'
|
||||
0x50,0x02,0x0C,0x12,0x00,0x0C,
|
||||
0x7F,0x07,0xFC,0x10,0x61,0x03,0x10,0x31,0x03,0x10,0x31,0x06,0x10,0xE1,0xFC,0x1E,0x01,0x00,0x18,0x01,0x80,0x18,0x01,0x80,0x7E,0x07,0xF0,
|
||||
// 'Q'
|
||||
0x51,0x02,0x13,0x15,0x00,0x11,
|
||||
0x07,0xE0,0x01,0xFE,0x00,0x60,0x70,0x18,0x06,0x06,0x00,0x60,0xC0,0x0C,0x18,0x00,0xC2,0x00,0x18,0x40,0x03,0x08,0x0C,0x61,0x83,0xCC,0x30,0xCD,0x83,0x09,0xE0,0x60,0x3C,0x06,0x07,0x00,0x7F,0xE3,0x07,0xEC,0x40,0x01,0x98,0x00,0x33,0x00,0x03,0xC0,0x00,0x30,
|
||||
// 'R'
|
||||
0x52,0x02,0x0F,0x13,0x00,0x0F,
|
||||
0x7F,0x80,0xFF,0xE0,0x60,0xE0,0xC0,0x61,0x80,0xC3,0x01,0x86,0x07,0x0C,0x1C,0x1F,0xF0,0x3F,0x80,0x66,0x00,0xC4,0x01,0x8C,0x63,0x18,0xC6,0x11,0x8C,0x33,0x7E,0x7C,0xFC,0x70,0x00,0x00,
|
||||
// 'S'
|
||||
0x53,0x01,0x0D,0x13,0x00,0x0D,
|
||||
0x00,0x60,0x7B,0x07,0xF8,0x71,0xC3,0x06,0x18,0x00,0xC0,0x03,0x80,0x0E,0x00,0x1C,0x00,0x78,0x00,0xC0,0x03,0x30,0x19,0x80,0xCC,0x06,0x30,0x70,0xFF,0x03,0xE0,
|
||||
// 'T'
|
||||
0x54,0x01,0x0F,0x12,0x00,0x0F,
|
||||
0x00,0x00,0xFF,0xF9,0xFF,0xF3,0x18,0x66,0x30,0xCC,0x61,0x90,0xC3,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x0F,0xE0,0x1F,0xC0,
|
||||
// 'U'
|
||||
0x55,0x02,0x10,0x11,0x00,0x0F,
|
||||
0x7C,0x7E,0x7C,0x7E,0x30,0x08,0x30,0x08,0x30,0x08,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x10,0x08,0x18,0x18,0x18,0x18,0x0C,0x30,0x0F,0xF0,0x03,0xC0,
|
||||
// 'V'
|
||||
0x56,0x01,0x10,0x12,0x00,0x10,
|
||||
0x00,0x7E,0xFE,0x7E,0x7E,0x18,0x18,0x30,0x18,0x30,0x18,0x20,0x08,0x60,0x0C,0x60,0x0C,0x60,0x0C,0x40,0x0C,0xC0,0x04,0xC0,0x04,0xC0,0x06,0x80,0x07,0x80,0x07,0x80,0x03,0x00,0x03,0x00,
|
||||
// 'W'
|
||||
0x57,0x01,0x14,0x13,0x00,0x14,
|
||||
0x00,0x00,0x0F,0xC4,0xFF,0xF0,0x4F,0xE3,0x06,0x10,0x30,0xE3,0x01,0x8E,0x30,0x18,0xE3,0x01,0x8E,0x30,0x19,0xA3,0x01,0x9A,0x20,0x09,0xA6,0x00,0xD2,0x60,0x0D,0x36,0x00,0xF3,0x40,0x0F,0x34,0x00,0x63,0xC0,0x06,0x1C,0x00,0x61,0x80,0x00,0x18,0x00,
|
||||
// 'X'
|
||||
0x58,0x01,0x10,0x13,0x00,0x10,
|
||||
0x00,0x00,0x7F,0x7F,0x7E,0x7E,0x0C,0x30,0x06,0x20,0x06,0x60,0x03,0xC0,0x01,0x80,0x01,0x80,0x03,0x80,0x02,0xC0,0x06,0x40,0x04,0x60,0x0C,0x60,0x18,0x30,0x18,0x30,0x7C,0x30,0xFC,0xFE,0x00,0xFF,
|
||||
// 'Y'
|
||||
0x59,0x01,0x11,0x13,0x00,0x10,
|
||||
0x00,0x00,0x7F,0x3F,0xBF,0x07,0x03,0x03,0x00,0xC1,0x00,0x31,0x80,0x18,0x80,0x06,0xC0,0x01,0xC0,0x00,0xE0,0x00,0x30,0x00,0x30,0x00,0x18,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x07,0x80,0x03,0xF8,0x00,0x7C,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x02,0x0E,0x12,0x00,0x0D,
|
||||
0x7F,0xF9,0xFF,0xE6,0x03,0x18,0x18,0x60,0xC1,0x07,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x00,0xC0,0x06,0x00,0x18,0x30,0xC0,0xC3,0x03,0x1F,0xFE,0x7F,0xF8,0x00,0x60,
|
||||
// '['
|
||||
0x5B,0x01,0x08,0x14,0x01,0x08,
|
||||
0x00,0x7C,0x7C,0x40,0x40,0x40,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x60,0x7E,0x7E,0x00,
|
||||
// '\'
|
||||
0x5C,0x01,0x0A,0x13,0x00,0x0A,
|
||||
0x00,0x10,0x06,0x01,0x80,0x30,0x0C,0x01,0x80,0x60,0x0C,0x03,0x00,0x60,0x18,0x06,0x00,0xC0,0x30,0x06,0x01,0x80,0x60,0x08,
|
||||
// ']'
|
||||
0x5D,0x01,0x08,0x14,0x00,0x08,
|
||||
0x00,0x7C,0x7E,0x04,0x04,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x0C,0x7C,0xFC,
|
||||
// '^'
|
||||
0x5E,0x03,0x0B,0x0B,0x00,0x0B,
|
||||
0x00,0x00,0x40,0x18,0x03,0x00,0xF0,0x32,0x0C,0x63,0x86,0x60,0xC0,0x0C,0x00,0x00,
|
||||
// '_'
|
||||
0x5F,0x15,0x11,0x02,0xFF,0x0F,
|
||||
0x7F,0xFF,0x3F,0xFF,0x80,
|
||||
// '`'
|
||||
0x60,0x00,0x06,0x07,0x00,0x06,
|
||||
0x01,0x87,0x0C,0x18,0x20,0x00,
|
||||
// 'a'
|
||||
0x61,0x06,0x0C,0x0D,0x00,0x0B,
|
||||
0x0E,0x03,0xF0,0x31,0x06,0x10,0x23,0x80,0xF8,0x3D,0x87,0x10,0x61,0x0C,0x18,0x63,0xA7,0xFE,0x1C,0xC0,
|
||||
// 'b'
|
||||
0x62,0x01,0x0C,0x14,0x00,0x0C,
|
||||
0x00,0x07,0xC0,0x3C,0x01,0x80,0x18,0x01,0x80,0x18,0x01,0x98,0x1F,0xC1,0xC6,0x18,0x21,0x83,0x10,0x31,0x03,0x18,0x31,0x83,0x18,0x6F,0xC6,0xF7,0xC0,0x30,
|
||||
// 'c'
|
||||
0x63,0x06,0x0B,0x0D,0x00,0x0B,
|
||||
0x06,0x03,0xF0,0xC7,0x31,0xE4,0x1C,0x80,0x30,0x06,0x00,0x60,0x0C,0x01,0xC3,0x1F,0xC0,0xF0,
|
||||
// 'd'
|
||||
0x64,0x01,0x0D,0x13,0x00,0x0D,
|
||||
0x00,0x00,0x1E,0x00,0xF0,0x01,0x80,0x0C,0x00,0x60,0x03,0x01,0x98,0x3E,0x81,0x9C,0x18,0x60,0xC3,0x04,0x08,0x60,0x41,0x02,0x0C,0x30,0x71,0x91,0xFF,0x87,0x1C,
|
||||
// 'e'
|
||||
0x65,0x07,0x0B,0x0C,0x00,0x0B,
|
||||
0x0F,0x03,0xF0,0xC3,0x30,0x66,0x1C,0xDE,0x1E,0x03,0x00,0x60,0x06,0x18,0x7E,0x07,0x80,
|
||||
// 'f'
|
||||
0x66,0x02,0x0A,0x12,0x00,0x08,
|
||||
0x07,0x07,0xE1,0xB8,0x4E,0x10,0x04,0x07,0xE1,0xF8,0x18,0x06,0x01,0x80,0x60,0x18,0x06,0x01,0x81,0xF8,0x7E,0x00,0x00,
|
||||
// 'g'
|
||||
0x67,0x05,0x0A,0x12,0x00,0x0A,
|
||||
0x00,0x00,0x20,0x18,0x7E,0x3F,0x18,0x64,0x09,0x02,0x61,0x9F,0xC1,0xE0,0x0C,0x01,0x84,0x67,0x19,0x8C,0x7E,0x0F,0x00,
|
||||
// 'h'
|
||||
0x68,0x02,0x0E,0x12,0x00,0x0D,
|
||||
0x78,0x01,0xE0,0x01,0x80,0x06,0x00,0x19,0xC0,0x2F,0x80,0xE6,0x07,0x08,0x18,0x20,0x60,0x81,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x9E,0x7E,0x78,0x00,0x00,
|
||||
// 'i'
|
||||
0x69,0x02,0x08,0x11,0x00,0x08,
|
||||
0x30,0x78,0x78,0x30,0x00,0x78,0x78,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7F,
|
||||
// 'j'
|
||||
0x6A,0x02,0x09,0x15,0xFE,0x07,
|
||||
0x06,0x07,0x03,0x81,0xC0,0x00,0xF8,0x7C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x18,0x0C,0x06,0x03,0x01,0x99,0x8F,0xC3,0xC0,
|
||||
// 'k'
|
||||
0x6B,0x02,0x0D,0x12,0x00,0x0D,
|
||||
0x78,0x03,0xC0,0x06,0x00,0x37,0xC1,0xBC,0x0C,0xC0,0x6C,0x03,0xC0,0x1C,0x00,0xC0,0x07,0x00,0x3E,0x01,0xB8,0x08,0x61,0xC1,0xCF,0x07,0x00,0x10,0x00,0x00,
|
||||
// 'l'
|
||||
0x6C,0x02,0x08,0x12,0x00,0x08,
|
||||
0x78,0x78,0x18,0x08,0x08,0x08,0x08,0x08,0x08,0x18,0x18,0x18,0x18,0x18,0x18,0x7E,0x7E,0x00,
|
||||
// 'm'
|
||||
0x6D,0x08,0x14,0x0D,0x00,0x14,
|
||||
0x40,0xC3,0x0F,0xBE,0xF8,0x1E,0x78,0xC1,0xC7,0x0C,0x18,0x20,0xC1,0x82,0x0C,0x10,0x20,0xC1,0x82,0x08,0x18,0x60,0x81,0x84,0x18,0x7E,0x71,0xE7,0xE7,0x9E,0x00,0x00,0x00,
|
||||
// 'n'
|
||||
0x6E,0x06,0x0E,0x0E,0x00,0x0D,
|
||||
0x79,0xC1,0xEF,0x81,0xE6,0x07,0x08,0x18,0x30,0x60,0xC1,0x82,0x06,0x08,0x18,0x20,0x60,0x81,0x82,0x1F,0x1E,0x7E,0x78,0x00,0x00,
|
||||
// 'o'
|
||||
0x6F,0x08,0x0B,0x0C,0x00,0x0C,
|
||||
0x0F,0x03,0xF8,0xC3,0x30,0x36,0x06,0x80,0xD0,0x1B,0x03,0x60,0x66,0x18,0xFE,0x07,0x80,
|
||||
// 'p'
|
||||
0x70,0x07,0x0B,0x10,0x00,0x0B,
|
||||
0x07,0x1F,0xF1,0xE3,0x18,0x23,0x06,0x60,0xCC,0x19,0x82,0x30,0xC6,0x18,0xFE,0x1B,0x83,0x00,0x60,0x1C,0x07,0x80,
|
||||
// 'q'
|
||||
0x71,0x06,0x0D,0x11,0x00,0x0B,
|
||||
0x0C,0x01,0xF7,0x0C,0xF8,0xC3,0x04,0x18,0x20,0x41,0x02,0x08,0x10,0x60,0x83,0x04,0x0C,0x60,0x7F,0x01,0xE8,0x00,0xC0,0x06,0xC0,0x1E,0x00,0xE0,
|
||||
// 'r'
|
||||
0x72,0x08,0x0A,0x0D,0x00,0x09,
|
||||
0x77,0x3F,0xE3,0xB8,0xCE,0x33,0x0C,0x03,0x00,0xC0,0x30,0x04,0x07,0xC1,0xF0,0x00,0x00,
|
||||
// 's'
|
||||
0x73,0x05,0x0A,0x0E,0x00,0x0A,
|
||||
0x03,0x00,0xC1,0xF0,0xFC,0x63,0x18,0x47,0x00,0xF8,0x07,0x80,0x64,0x19,0x86,0x7F,0x07,0x80,
|
||||
// 't'
|
||||
0x74,0x02,0x09,0x13,0x00,0x09,
|
||||
0x30,0x18,0x0C,0x06,0x02,0x07,0xE3,0xF8,0x40,0x20,0x10,0x08,0x04,0x02,0x11,0x18,0x84,0x62,0x33,0x0F,0x83,0x00,
|
||||
// 'u'
|
||||
0x75,0x06,0x0E,0x0E,0x00,0x0D,
|
||||
0x00,0x03,0xE7,0xC7,0x9F,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0C,0x30,0x30,0xC0,0xC3,0x03,0x0C,0x0E,0x7C,0x1F,0xF8,0x3C,0x00,
|
||||
// 'v'
|
||||
0x76,0x07,0x0E,0x0D,0x00,0x0D,
|
||||
0x01,0xFB,0xF3,0xEF,0xC6,0x06,0x18,0x18,0x60,0x31,0x00,0xCC,0x01,0x30,0x06,0x80,0x0A,0x00,0x38,0x00,0xE0,0x01,0x00,
|
||||
// 'w'
|
||||
0x77,0x08,0x11,0x0D,0x00,0x11,
|
||||
0x04,0x1F,0xFF,0x6F,0xBE,0x31,0x83,0x1C,0xC1,0x9E,0x40,0x4D,0x20,0x34,0xB0,0x1A,0x78,0x05,0x3C,0x03,0x8E,0x01,0x86,0x00,0x43,0x00,0x00,0x00,
|
||||
// 'x'
|
||||
0x78,0x08,0x0D,0x0D,0x00,0x0D,
|
||||
0x0C,0xFB,0xE7,0xDE,0x18,0x31,0x80,0xD8,0x03,0x80,0x18,0x01,0xE0,0x19,0x81,0x8C,0x0E,0x7D,0xF3,0xE4,0x00,0x00,
|
||||
// 'y'
|
||||
0x79,0x06,0x0F,0x11,0x00,0x0D,
|
||||
0x7C,0x01,0xF8,0x00,0xC3,0xF0,0xC7,0xE1,0x82,0x01,0x0C,0x03,0x18,0x06,0x20,0x06,0xC0,0x0D,0x00,0x0E,0x00,0x18,0x00,0x30,0x06,0xC0,0x1F,0x00,0x3E,0x00,0x30,0x00,
|
||||
// 'z'
|
||||
0x7A,0x08,0x0B,0x0B,0x00,0x0B,
|
||||
0x7F,0xCF,0xF9,0x86,0x31,0x86,0x60,0x1C,0x07,0x00,0xC6,0x30,0xCF,0xF9,0xFF,0x00,
|
||||
// '{'
|
||||
0x7B,0x02,0x09,0x12,0x00,0x08,
|
||||
0x07,0x07,0x83,0x01,0x01,0x80,0xC0,0x60,0xE0,0x70,0x0C,0x06,0x03,0x01,0x80,0xC0,0x60,0x30,0x1F,0x03,0x80,
|
||||
// '|'
|
||||
0x7C,0x02,0x03,0x12,0x01,0x05,
|
||||
0x49,0x24,0x92,0x6D,0xB6,0xDB,0x6C,
|
||||
// '}'
|
||||
0x7D,0x02,0x07,0x11,0x00,0x07,
|
||||
0x30,0xF0,0x20,0x41,0x83,0x02,0x06,0x0E,0x18,0x60,0xC0,0x81,0x83,0x3C,0x78,
|
||||
// '~'
|
||||
0x7E,0x09,0x0D,0x04,0x00,0x0D,
|
||||
0x18,0x03,0xF1,0x98,0xFC,0x83,0xC0,
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
331
components/epaper/tooney32.c
Normal file
331
components/epaper/tooney32.c
Normal file
@ -0,0 +1,331 @@
|
||||
// This comes with no warranty, implied or otherwise
|
||||
|
||||
// This data structure was designed to support Proportional fonts
|
||||
// on Arduinos. It can however handle any ttf font that has been converted
|
||||
// using the conversion program. These could be fixed width or proportional
|
||||
// fonts. Individual characters do not have to be multiples of 8 bits wide.
|
||||
// Any width is fine and does not need to be fixed.
|
||||
|
||||
// The data bits are packed to minimize data requirements, but the tradeoff
|
||||
// is that a header is required per character.
|
||||
|
||||
// tooney32.c
|
||||
// Point Size : 32
|
||||
// Memory usage : 5470 bytes
|
||||
// # characters : 95
|
||||
|
||||
// Header Format (to make Arduino UTFT Compatible):
|
||||
// ------------------------------------------------
|
||||
// Character Width (Used as a marker to indicate use this format. i.e.: = 0x00)
|
||||
// Character Height
|
||||
// First Character (Reserved. 0x00)
|
||||
// Number Of Characters (Reserved. 0x00)
|
||||
|
||||
unsigned char tft_tooney32[] =
|
||||
{
|
||||
0x00, 0x20, 0x00, 0x00,
|
||||
|
||||
// Individual Character Format:
|
||||
// ----------------------------
|
||||
// Character Code
|
||||
// Adjusted Y Offset
|
||||
// Width
|
||||
// Height
|
||||
// xOffset
|
||||
// xDelta (the distance to move the cursor. Effective width of the character.)
|
||||
// Data[n]
|
||||
|
||||
// NOTE: You can remove any of these characters if they are not needed in
|
||||
// your application. The first character number in each Glyph indicates
|
||||
// the ASCII character code. Therefore, these do not have to be sequential.
|
||||
// Just remove all the content for a particular character to save space.
|
||||
|
||||
// ' '
|
||||
0x20,0x1E,0x00,0x00,0x00,0x09,
|
||||
|
||||
// '!'
|
||||
0x21,0x09,0x0B,0x16,0x00,0x0B,
|
||||
0x3F,0xC8,0x07,0x81,0x70,0x27,0x00,0xE0,0x1C,0x21,0x84,0x30,0x86,0x10,0xC2,0x18,0x43,0xF0,0x61,0x0C,0x13,0x02,0x60,0x4E,0x09,0xE2,0x1F,0x81,0xE0,0x00,0x00,
|
||||
// '"'
|
||||
0x22,0x05,0x0E,0x0A,0xFF,0x0D,
|
||||
0x04,0x30,0x2D,0x61,0x8C,0x44,0x71,0x31,0x88,0xCE,0x42,0x72,0x18,0xC8,0x7B,0xC0,0xC6,0x00,
|
||||
// '#'
|
||||
0x23,0x07,0x18,0x16,0x00,0x18,
|
||||
0x00,0xFF,0xF8,0x01,0x83,0x08,0x01,0x82,0x08,0x01,0x82,0x08,0x0F,0x06,0x0F,0x10,0x00,0x01,0x30,0x00,0x01,0x30,0x00,0x00,0x20,0x00,0x02,0x7E,0x0C,0x1E,0x7E,0x0C,0x1E,0x60,0x00,0x02,0x60,0x00,0x00,0x40,0x00,0x04,0x40,0x00,0x04,0xC0,0x00,0x04,0xFC,0x10,0x78,0xFC,0x30,0x78,0x08,0x30,0x40,0x18,0x30,0x40,0x1F,0xFF,0x80,0x1F,0xFF,0x80,
|
||||
// '$'
|
||||
0x24,0x09,0x0F,0x14,0x00,0x0F,
|
||||
0x01,0x80,0x04,0xF8,0x18,0x08,0x20,0x10,0xC0,0x41,0x00,0x86,0x01,0x0C,0x12,0x18,0x38,0x30,0x60,0xA0,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x10,0x30,0x20,0x6E,0x40,0xFF,0x81,0x9E,0x00,0x18,0x00,
|
||||
// '%'
|
||||
0x25,0x07,0x17,0x16,0x00,0x17,
|
||||
0x0F,0x81,0xF8,0x20,0x84,0x10,0x80,0x98,0x42,0x00,0x21,0x0C,0x01,0x82,0x18,0x43,0x08,0x30,0x04,0x10,0x70,0x18,0x40,0xE0,0x21,0x00,0xF1,0x82,0x00,0xFF,0x0F,0xC0,0xFC,0x10,0x40,0x18,0x40,0x40,0x21,0x80,0x40,0x82,0x00,0x83,0x0C,0x21,0x04,0x18,0x02,0x18,0x78,0x04,0x21,0x30,0x10,0xC2,0x78,0xC3,0xF8,0x7F,0x07,0xE0,0x7C,0x00,
|
||||
// '&'
|
||||
0x26,0x08,0x17,0x17,0x00,0x17,
|
||||
0x01,0xF6,0x00,0x04,0x1A,0x00,0x10,0x04,0x00,0x40,0x10,0x01,0x00,0x40,0x06,0x00,0x80,0x0C,0x1A,0x00,0x18,0x1F,0xC0,0x30,0x18,0xF8,0x60,0x08,0x09,0x80,0x00,0x33,0x00,0x00,0xCC,0x0C,0x01,0x18,0x3C,0x04,0x30,0x30,0x07,0x60,0x00,0x01,0xE0,0x00,0x07,0xC0,0x00,0x09,0xC0,0x0C,0x23,0xC0,0x38,0x03,0xE1,0xF8,0x03,0xFF,0x70,0x01,0xF8,0x60,0x00,
|
||||
// '''
|
||||
0x27,0x05,0x09,0x0A,0xFF,0x08,
|
||||
0x06,0x05,0x86,0x23,0x13,0x11,0x90,0x90,0xC8,0x78,0x18,0x00,
|
||||
// '('
|
||||
0x28,0x05,0x0D,0x1D,0x00,0x0D,
|
||||
0x03,0x00,0x34,0x01,0x90,0x08,0x40,0x81,0x88,0x1C,0xC1,0xC4,0x08,0x60,0x83,0x04,0x10,0x41,0x82,0x0C,0x10,0x60,0x83,0x04,0x18,0x20,0xC0,0x06,0x04,0x38,0x20,0xC0,0x87,0x06,0x38,0x1C,0xE0,0x67,0x86,0x1C,0x60,0x76,0x01,0xE0,0x0E,0x00,0x60,0x00,
|
||||
// ')'
|
||||
0x29,0x05,0x0D,0x1D,0x00,0x0D,
|
||||
0x01,0x00,0x10,0x01,0x20,0x11,0x03,0x04,0x30,0x11,0xE0,0x8F,0x82,0x1C,0x10,0x70,0x81,0x82,0x0E,0x10,0x30,0x81,0x84,0x0C,0x20,0x61,0x02,0x08,0x10,0x01,0x84,0x08,0x20,0x81,0x18,0x11,0x80,0x8E,0x08,0x78,0x80,0xE4,0x03,0xE0,0x0E,0x00,0x30,0x00,
|
||||
// '*'
|
||||
0x2A,0x09,0x0C,0x0D,0x01,0x0D,
|
||||
0x07,0x00,0x88,0x18,0xE4,0x11,0xC0,0x1F,0x8E,0xC0,0x1C,0x11,0xC8,0xBF,0x8E,0x7D,0xC1,0xE0,0x0C,0x00,
|
||||
// '+'
|
||||
0x2B,0x09,0x15,0x14,0x00,0x15,
|
||||
0x00,0x7C,0x00,0x04,0x10,0x00,0x60,0x80,0x07,0x04,0x00,0x38,0x20,0x01,0xC1,0x00,0xFE,0x0F,0xCC,0x00,0x01,0xE0,0x00,0x0F,0x00,0x00,0x78,0x00,0x03,0xFF,0x07,0xFF,0xF8,0x3F,0x7F,0xC1,0xF0,0x0E,0x08,0x00,0x70,0x40,0x03,0x82,0x00,0x1F,0xF0,0x00,0xFE,0x00,0x03,0xE0,0x00,
|
||||
// ','
|
||||
0x2C,0x17,0x09,0x0B,0x00,0x09,
|
||||
0x1E,0x10,0x98,0x38,0x1C,0x0F,0x0B,0xC4,0xE4,0x32,0x1E,0x0E,0x00,
|
||||
// '-'
|
||||
0x2D,0x11,0x09,0x06,0x00,0x09,
|
||||
0x1B,0x90,0x50,0x39,0x2F,0xE7,0xF0,
|
||||
// '.'
|
||||
0x2E,0x16,0x09,0x09,0x00,0x09,
|
||||
0x1E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00,
|
||||
// '/'
|
||||
0x2F,0x09,0x11,0x19,0x00,0x11,
|
||||
0x00,0x3F,0x80,0x30,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xC1,0x00,0xC0,0x80,0x60,0x00,0x60,0x40,0x30,0x20,0x18,0x20,0x18,0x10,0x0C,0x08,0x06,0x08,0x06,0x04,0x03,0x04,0x03,0xFE,0x01,0xFE,0x00,0xFE,0x00,0x00,
|
||||
// '0'
|
||||
0x30,0x08,0x17,0x17,0x00,0x17,
|
||||
0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00,
|
||||
// '1'
|
||||
0x31,0x09,0x0D,0x16,0x00,0x0D,
|
||||
0x00,0x30,0x06,0x40,0xC4,0x18,0x43,0x02,0x20,0x13,0xC0,0x9E,0x04,0x30,0x21,0x81,0x0C,0x08,0x60,0x43,0x02,0x18,0x10,0xC0,0x86,0x04,0x30,0x21,0x81,0x98,0x03,0xFF,0xE7,0xFE,0x00,0x00,
|
||||
// '2'
|
||||
0x32,0x08,0x12,0x17,0x00,0x12,
|
||||
0x00,0xF0,0x00,0x81,0x00,0xC0,0x20,0xE0,0x04,0x40,0x01,0x38,0x00,0x2F,0x84,0x08,0xF9,0x82,0x1F,0xE0,0x81,0xF0,0x00,0x1C,0x10,0x06,0x04,0x01,0x03,0x80,0xC0,0xD0,0x20,0x04,0x18,0x01,0x0C,0x00,0x43,0x00,0x11,0x80,0x04,0x60,0x01,0x3F,0xFF,0x4F,0xFF,0xE0,0x00,0x30,
|
||||
// '3'
|
||||
0x33,0x08,0x12,0x17,0x00,0x12,
|
||||
0x0C,0x00,0x05,0xFF,0xE3,0x00,0x08,0xC0,0x02,0x30,0x01,0x0C,0x00,0x43,0x00,0x10,0xC0,0x0C,0x37,0x01,0x0F,0x80,0x23,0xE0,0x08,0x10,0x01,0x0F,0xE0,0x43,0xF8,0x10,0x4E,0x04,0x23,0x01,0x10,0x00,0x08,0x00,0x24,0x00,0x13,0x00,0x08,0xFC,0x0C,0x1F,0xFE,0x00,0xFE,0x00,
|
||||
// '4'
|
||||
0x34,0x09,0x12,0x16,0x00,0x12,
|
||||
0x00,0x0E,0x00,0x04,0x80,0x06,0x20,0x03,0x08,0x01,0x82,0x00,0xC0,0x80,0x40,0x20,0x20,0x08,0x10,0x03,0x88,0x20,0x94,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0xFE,0x09,0xFF,0x83,0x80,0x60,0xC0,0x30,0x10,0x0F,0xF8,0x03,0xFC,0x00,0x00,0x00,
|
||||
// '5'
|
||||
0x35,0x08,0x11,0x17,0x00,0x11,
|
||||
0x00,0x03,0x00,0xFF,0x40,0x80,0x20,0xC0,0x10,0x60,0x08,0x30,0x04,0x30,0x02,0x18,0x1D,0x0C,0x07,0x06,0x01,0x82,0x00,0x43,0x00,0x11,0xFC,0x08,0xFF,0x04,0x17,0x82,0x18,0x01,0x18,0x00,0x08,0x00,0x8C,0x00,0x8C,0x00,0xC7,0xC1,0xC3,0xFF,0x80,0xBF,0x00,
|
||||
// '6'
|
||||
0x36,0x08,0x13,0x17,0x00,0x13,
|
||||
0x00,0x7F,0xC0,0x30,0x08,0x18,0x01,0x06,0x00,0x41,0x80,0x10,0x60,0x02,0x08,0x0C,0x83,0x00,0x30,0x60,0x01,0x18,0x00,0x13,0x00,0x01,0x60,0x00,0x0C,0x00,0x03,0x80,0xC0,0x78,0x3C,0x0F,0x03,0x01,0x60,0x00,0x0E,0x00,0x08,0xE0,0x02,0x1E,0x00,0x81,0xF0,0x60,0x1F,0xF8,0x00,0xFC,0x00,
|
||||
// '7'
|
||||
0x37,0x08,0x12,0x17,0x00,0x12,
|
||||
0x0C,0x00,0x0D,0xFF,0xF3,0x00,0x04,0xC0,0x02,0x30,0x00,0x8C,0x00,0x43,0x00,0x10,0xDC,0x08,0x3F,0x02,0x0E,0x81,0x00,0x60,0x40,0x10,0x20,0x0C,0x08,0x02,0x04,0x01,0x81,0x00,0x40,0x80,0x30,0x20,0x10,0x10,0x0F,0x04,0x03,0xF1,0x00,0x3F,0x40,0x03,0xE0,0x00,0x30,0x00,
|
||||
// '8'
|
||||
0x38,0x08,0x12,0x17,0x00,0x12,
|
||||
0x01,0xF0,0x00,0x83,0x00,0xC0,0x20,0x20,0x08,0x10,0x01,0x0C,0x18,0x43,0x06,0x10,0xC0,0x04,0x38,0x01,0x0C,0x00,0x42,0x00,0x09,0x80,0x01,0xC0,0x00,0x70,0x3C,0x1C,0x0F,0x07,0x00,0x01,0xE0,0x00,0x9C,0x00,0x27,0x80,0x30,0xF8,0x38,0x1F,0xFC,0x01,0xFC,0x00,0x00,0x00,
|
||||
// '9'
|
||||
0x39,0x08,0x13,0x17,0x00,0x13,
|
||||
0x01,0xF8,0x00,0xC0,0xC0,0x20,0x04,0x08,0x00,0x42,0x00,0x08,0xC0,0x00,0x90,0x18,0x16,0x07,0x81,0xC0,0x60,0x38,0x00,0x07,0x80,0x00,0xF0,0x00,0x17,0x00,0x02,0xF0,0x00,0x0F,0x80,0x10,0xE6,0x02,0x08,0x00,0x83,0x00,0x20,0x40,0x0C,0x10,0x03,0x06,0xC1,0xC0,0xFF,0xE0,0x1F,0xF0,0x00,
|
||||
// ':'
|
||||
0x3A,0x0E,0x09,0x11,0x00,0x09,
|
||||
0x0E,0x10,0x90,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3C,0x19,0x98,0x38,0x1C,0x0F,0x07,0xCC,0xFC,0x3C,0x00,
|
||||
// ';'
|
||||
0x3B,0x0F,0x09,0x13,0x00,0x09,
|
||||
0x0E,0x10,0x98,0x38,0x1C,0x0F,0x07,0xC4,0xFC,0x3E,0x19,0x98,0x38,0x1C,0x0F,0x03,0xC4,0xE4,0x32,0x1E,0x0E,0x00,
|
||||
// '<'
|
||||
0x3C,0x0A,0x13,0x13,0x00,0x13,
|
||||
0x00,0x00,0xC0,0x00,0x64,0x00,0x60,0x80,0x30,0x10,0x38,0x02,0x18,0x03,0x8C,0x01,0xE3,0x01,0xF0,0xE0,0xF8,0x1C,0x06,0x03,0x80,0x18,0x7E,0x00,0xCF,0xF0,0x06,0x7F,0xC0,0x43,0xFE,0x08,0x0F,0xF9,0x00,0x7F,0xE0,0x01,0xF8,0x00,0x0C,0x00,
|
||||
// '='
|
||||
0x3D,0x0D,0x14,0x0E,0x00,0x14,
|
||||
0x3F,0xFF,0xE6,0x00,0x01,0xE0,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xE6,0x00,0x01,0x60,0x00,0x1E,0x00,0x01,0xE0,0x00,0x1F,0xFF,0xFE,0xFF,0xFF,0xEF,0xFF,0xF8,
|
||||
// '>'
|
||||
0x3E,0x0A,0x13,0x13,0x00,0x13,
|
||||
0x38,0x00,0x0C,0xC0,0x03,0x87,0x00,0x70,0x18,0x0E,0x00,0xE1,0xF8,0x03,0x3F,0xC0,0x19,0xFF,0x01,0x0F,0xF8,0x20,0x3C,0x04,0x0C,0x00,0x86,0x00,0xE3,0x00,0x78,0xC0,0x7C,0x38,0x3E,0x07,0x3E,0x00,0xFF,0x00,0x1F,0x00,0x03,0x80,0x00,0x00,
|
||||
// '?'
|
||||
0x3F,0x08,0x11,0x16,0x00,0x11,
|
||||
0x00,0xF0,0x01,0x82,0x01,0x00,0x81,0x00,0x23,0x00,0x0B,0x00,0x05,0xC0,0x02,0xF8,0xC1,0x3F,0x40,0x87,0xE0,0x80,0xE0,0x40,0x30,0x40,0x18,0x20,0x0F,0xE0,0x07,0x30,0x03,0x04,0x03,0x02,0x01,0x81,0x00,0xE0,0x80,0x78,0x80,0x1F,0x80,0x07,0x80,
|
||||
// '@'
|
||||
0x40,0x09,0x16,0x16,0x00,0x16,
|
||||
0x00,0x3F,0x00,0x06,0x03,0x00,0x23,0xFB,0x01,0x3F,0xFC,0x09,0x81,0xF8,0x48,0x7F,0xE2,0x44,0x13,0xD9,0x23,0x8F,0x41,0x1E,0x1F,0x2C,0x51,0x7C,0xE0,0xC5,0xF3,0x8B,0x06,0xCE,0x28,0x3B,0x38,0xE2,0xEE,0x71,0x4D,0x19,0xE3,0x88,0x73,0xFF,0xD1,0xE7,0x9F,0xA3,0xC7,0xF1,0x07,0xE0,0x38,0x07,0xFF,0x80,0x07,0xF8,0x00,
|
||||
// 'A'
|
||||
0x41,0x08,0x19,0x17,0x00,0x19,
|
||||
0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00,
|
||||
// 'B'
|
||||
0x42,0x09,0x13,0x15,0x00,0x13,
|
||||
0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80,
|
||||
// 'C'
|
||||
0x43,0x08,0x16,0x17,0x00,0x16,
|
||||
0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00,
|
||||
// 'D'
|
||||
0x44,0x09,0x16,0x15,0xFF,0x15,
|
||||
0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00,
|
||||
// 'E'
|
||||
0x45,0x08,0x11,0x17,0x00,0x11,
|
||||
0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08,
|
||||
// 'F'
|
||||
0x46,0x08,0x11,0x16,0xFF,0x10,
|
||||
0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00,
|
||||
// 'G'
|
||||
0x47,0x08,0x16,0x17,0x00,0x16,
|
||||
0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00,
|
||||
// 'H'
|
||||
0x48,0x09,0x16,0x15,0x00,0x16,
|
||||
0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00,
|
||||
// 'I'
|
||||
0x49,0x09,0x0B,0x15,0x00,0x0B,
|
||||
0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8,
|
||||
// 'J'
|
||||
0x4A,0x09,0x0F,0x16,0x00,0x0F,
|
||||
0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00,
|
||||
// 'K'
|
||||
0x4B,0x08,0x17,0x18,0x00,0x17,
|
||||
0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00,
|
||||
// 'L'
|
||||
0x4C,0x09,0x11,0x16,0x00,0x11,
|
||||
0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30,
|
||||
// 'M'
|
||||
0x4D,0x09,0x20,0x16,0x00,0x1F,
|
||||
0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00,
|
||||
// 'N'
|
||||
0x4E,0x09,0x17,0x15,0x00,0x17,
|
||||
0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80,
|
||||
// 'O'
|
||||
0x4F,0x08,0x17,0x17,0x00,0x17,
|
||||
0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00,
|
||||
// 'P'
|
||||
0x50,0x09,0x13,0x15,0x00,0x13,
|
||||
0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00,
|
||||
// 'Q'
|
||||
0x51,0x09,0x17,0x1C,0x00,0x17,
|
||||
0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,
|
||||
// 'R'
|
||||
0x52,0x09,0x18,0x17,0x00,0x18,
|
||||
0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00,
|
||||
// 'S'
|
||||
0x53,0x07,0x11,0x19,0x00,0x11,
|
||||
0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00,
|
||||
// 'T'
|
||||
0x54,0x08,0x12,0x16,0x01,0x13,
|
||||
0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00,
|
||||
// 'U'
|
||||
0x55,0x09,0x19,0x16,0xFF,0x18,
|
||||
0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00,
|
||||
// 'V'
|
||||
0x56,0x07,0x19,0x18,0x00,0x19,
|
||||
0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00,
|
||||
// 'W'
|
||||
0x57,0x07,0x20,0x18,0x00,0x20,
|
||||
0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00,
|
||||
// 'X'
|
||||
0x58,0x05,0x19,0x1D,0x00,0x18,
|
||||
0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00,
|
||||
// 'Y'
|
||||
0x59,0x06,0x19,0x1B,0x00,0x19,
|
||||
0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00,
|
||||
// 'Z'
|
||||
0x5A,0x08,0x13,0x17,0xFF,0x12,
|
||||
0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80,
|
||||
// '['
|
||||
0x5B,0x04,0x0B,0x20,0x00,0x0B,
|
||||
0x00,0x40,0x19,0xFD,0x60,0x2C,0x05,0x80,0xB0,0x16,0x0E,0xC1,0xD8,0x33,0x04,0x60,0x8C,0x11,0x82,0x30,0x46,0x08,0xC1,0x18,0x23,0x04,0x60,0x8C,0x11,0x82,0xB0,0x76,0x02,0xC0,0x58,0x0B,0x01,0x60,0x2F,0xFD,0xFF,0x80,0x60,0x00,
|
||||
// '\'
|
||||
0x5C,0x09,0x11,0x18,0x00,0x11,
|
||||
0x3F,0x00,0x30,0x40,0x38,0x10,0x1E,0x08,0x0F,0x04,0x03,0x81,0x01,0xE0,0x80,0x70,0x20,0x3C,0x10,0x1E,0x08,0x07,0x02,0x03,0xC1,0x00,0xE0,0x40,0x78,0x20,0x3C,0x08,0x0F,0x04,0x07,0x82,0x01,0xC0,0x80,0xF0,0x40,0x38,0x10,0x1E,0x08,0x0F,0xFC,0x03,0xFC,0x01,0xFC,
|
||||
// ']'
|
||||
0x5D,0x04,0x0C,0x1F,0xFF,0x0B,
|
||||
0x30,0x02,0xFF,0x60,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0xC1,0x7C,0x16,0xC1,0x6C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x10,0xC1,0x0C,0x13,0xC1,0x6C,0x16,0x01,0x60,0x16,0x01,0x60,0x16,0x01,0x7F,0xE7,0xFE,0x60,0x00,
|
||||
// '^'
|
||||
0x5E,0x1E,0x00,0x00,0x00,0x09,
|
||||
|
||||
// '_'
|
||||
0x5F,0x20,0x10,0x04,0x00,0x10,
|
||||
0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,0xFF,
|
||||
// '`'
|
||||
0x60,0x00,0x0A,0x09,0x00,0x0B,
|
||||
0x00,0x06,0x02,0x61,0x8C,0x60,0xBF,0x17,0xFC,0x3E,0x03,0x00,
|
||||
// 'a'
|
||||
0x61,0x08,0x19,0x17,0x00,0x19,
|
||||
0x00,0x0C,0x00,0x00,0x09,0x00,0x00,0x08,0x80,0x00,0x0C,0x20,0x00,0x04,0x08,0x00,0x06,0x04,0x00,0x02,0x01,0x00,0x03,0x00,0xC0,0x03,0x00,0x20,0x01,0x00,0x08,0x01,0x80,0x04,0x00,0x80,0x01,0x00,0xC0,0xC0,0x40,0xC0,0x60,0x20,0x40,0x00,0x08,0x60,0x00,0x06,0x40,0x00,0x00,0xF0,0x00,0x00,0xFE,0x1F,0xE1,0xCF,0xCF,0xF1,0x81,0xF4,0x1B,0x80,0x3E,0x0F,0x00,0x0E,0x06,0x00,
|
||||
// 'b'
|
||||
0x62,0x09,0x13,0x15,0x00,0x13,
|
||||
0x3F,0xFC,0x0C,0x00,0x61,0xC0,0x06,0x38,0x00,0x43,0x00,0x04,0x60,0x60,0x8C,0x0C,0x11,0x81,0x02,0x30,0x00,0x46,0x00,0x08,0xC0,0x00,0x98,0x18,0x13,0x03,0x02,0x60,0x60,0x4C,0x00,0x09,0x80,0x01,0x30,0x00,0x44,0x00,0x11,0x80,0x0E,0x3F,0xFF,0x07,0xFF,0x80,
|
||||
// 'c'
|
||||
0x63,0x08,0x16,0x17,0x00,0x16,
|
||||
0x00,0x7E,0x00,0x06,0x02,0x00,0x60,0x06,0x02,0x00,0x06,0x10,0x00,0x00,0xC0,0x00,0x22,0x00,0x01,0x18,0x0F,0x18,0x40,0x7E,0xC3,0x02,0x3E,0x0C,0x08,0xF0,0x30,0x21,0x80,0xC0,0x83,0x03,0x81,0x1A,0x0E,0x03,0xC4,0x18,0x00,0x08,0x70,0x00,0x19,0xE0,0x00,0x23,0xC0,0x01,0x87,0x80,0x1E,0x0F,0xC1,0xE0,0x0F,0xFE,0x00,0x0F,0xC0,0x00,
|
||||
// 'd'
|
||||
0x64,0x09,0x16,0x15,0xFF,0x15,
|
||||
0x1F,0xFE,0x00,0x80,0x06,0x07,0x00,0x06,0x1C,0x00,0x0C,0x30,0x00,0x10,0xC0,0x00,0x23,0x00,0x00,0x8C,0x0F,0x01,0x30,0x3E,0x04,0xC0,0xF8,0x13,0x03,0xE0,0x4C,0x0F,0x01,0x30,0x00,0x04,0xC0,0x00,0x23,0x00,0x00,0x8C,0x00,0x04,0x30,0x00,0x20,0x80,0x01,0x06,0x00,0x18,0x1F,0xFF,0x80,0x3F,0xF0,0x00,
|
||||
// 'e'
|
||||
0x65,0x08,0x11,0x17,0x00,0x11,
|
||||
0x00,0x01,0x0F,0xFF,0x48,0x00,0x2C,0x00,0x17,0x00,0x0B,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x1A,0x98,0x01,0x8C,0x00,0x86,0x00,0x43,0x00,0x31,0x80,0xD4,0xC0,0x02,0x60,0x01,0x30,0x00,0x98,0x00,0x4C,0x00,0x24,0x00,0x17,0xFF,0xEB,0xFF,0xF8,0x00,0x08,
|
||||
// 'f'
|
||||
0x66,0x08,0x11,0x16,0xFF,0x10,
|
||||
0x00,0x01,0x0F,0xFF,0x48,0x00,0x2E,0x00,0x17,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x3A,0x98,0x01,0x8C,0x00,0xC6,0x00,0x43,0x00,0x21,0x81,0xD0,0xC0,0xF0,0x60,0x70,0x30,0x20,0x18,0x10,0x08,0x02,0x0C,0x01,0x07,0xFF,0x03,0xFF,0x00,
|
||||
// 'g'
|
||||
0x67,0x08,0x16,0x17,0x00,0x16,
|
||||
0x00,0x7F,0x00,0x06,0x03,0x00,0x60,0x03,0x82,0x00,0x02,0x10,0x00,0x08,0xC0,0x00,0xC2,0x00,0x06,0x18,0x07,0x30,0x40,0x3C,0x83,0x01,0x3C,0x0C,0x04,0xFF,0xB0,0x14,0x02,0xC0,0x78,0x1B,0x80,0xE0,0x4E,0x01,0x81,0x18,0x00,0x04,0x70,0x00,0x11,0xE0,0x00,0x43,0xC0,0x01,0x07,0x80,0x18,0x0F,0x81,0xC0,0x1F,0xFC,0x00,0x0F,0xC0,0x00,
|
||||
// 'h'
|
||||
0x68,0x09,0x16,0x15,0x00,0x16,
|
||||
0x3F,0xC7,0xF9,0x00,0xE0,0x1E,0x03,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x80,0xF0,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x00,0x09,0x80,0x00,0x26,0x00,0x00,0x98,0x00,0x02,0x60,0x3C,0x09,0x80,0xF0,0x26,0x02,0xC0,0x98,0x0B,0x02,0x60,0x2C,0x09,0x00,0x20,0x1F,0xFF,0xFF,0xFF,0xF7,0xFC,0x00,0x00,0x00,
|
||||
// 'i'
|
||||
0x69,0x09,0x0B,0x15,0x00,0x0B,
|
||||
0x3F,0xC8,0x07,0x81,0x70,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x4C,0x09,0x81,0x30,0x26,0x04,0xC0,0x98,0x13,0x02,0x60,0x48,0x07,0x00,0xFF,0xEF,0xF8,
|
||||
// 'j'
|
||||
0x6A,0x09,0x0F,0x16,0x00,0x0F,
|
||||
0x03,0xFC,0x08,0x04,0x38,0x08,0x70,0x10,0x60,0x20,0xC0,0x41,0x80,0x83,0x01,0x06,0x02,0x0C,0x04,0x18,0x08,0x30,0x10,0xA0,0x23,0x00,0x44,0x00,0x98,0x01,0x20,0x00,0xC0,0x09,0x00,0x27,0xC1,0x8F,0xFE,0x0F,0xF0,0x00,
|
||||
// 'k'
|
||||
0x6B,0x08,0x17,0x18,0x00,0x17,
|
||||
0x00,0x01,0x80,0x7F,0xEE,0x81,0x80,0x38,0x87,0x81,0xE0,0x8F,0x03,0x80,0x86,0x06,0x00,0x8C,0x08,0x07,0x18,0x00,0x1C,0x30,0x00,0x70,0x60,0x01,0x00,0xC0,0x02,0x01,0x80,0x02,0x03,0x00,0x04,0x06,0x04,0x04,0x0C,0x0C,0x04,0x18,0x18,0x06,0x30,0x38,0x00,0x60,0x78,0x09,0x00,0x30,0x26,0x00,0x71,0x8F,0xFF,0xE4,0x0F,0xFC,0xD0,0x00,0x01,0xC0,0x00,0x00,0x00,
|
||||
// 'l'
|
||||
0x6C,0x09,0x11,0x16,0x00,0x11,
|
||||
0x3F,0xF0,0x30,0x04,0x1C,0x06,0x0E,0x02,0x03,0x01,0x01,0x80,0x80,0xC0,0x40,0x60,0x20,0x30,0x10,0x18,0x08,0x0C,0x04,0xC6,0x03,0xD3,0x00,0x09,0x80,0x04,0xC0,0x02,0x60,0x01,0x30,0x00,0xB0,0x00,0x58,0x00,0x2F,0xFF,0xD7,0xFF,0xF0,0x00,0x30,
|
||||
// 'm'
|
||||
0x6D,0x09,0x20,0x16,0x00,0x1F,
|
||||
0x00,0xF8,0x1F,0x00,0x01,0x84,0x30,0x80,0x01,0x82,0x61,0x00,0x01,0x82,0x40,0x00,0x01,0x81,0xC0,0x80,0x01,0x01,0x80,0x80,0x03,0x00,0x80,0x40,0x02,0x00,0x00,0x40,0x06,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x04,0x00,0x00,0x10,0x0C,0x00,0x00,0x10,0x08,0x00,0x00,0x10,0x18,0x08,0x08,0x08,0x10,0x18,0x18,0x08,0x30,0x1C,0x1C,0x04,0x60,0x3C,0x3C,0x02,0x70,0x2E,0x2E,0x06,0x7C,0x27,0x4E,0x3C,0x3F,0x27,0xC6,0xF0,0x07,0xC3,0x8F,0x80,0x01,0x83,0x06,0x00,
|
||||
// 'n'
|
||||
0x6E,0x09,0x17,0x15,0x00,0x17,
|
||||
0x3F,0x07,0xFC,0xC1,0x10,0x07,0xC1,0x78,0x1F,0x81,0xF0,0x23,0x01,0xE0,0x46,0x01,0xC0,0x8C,0x01,0x81,0x18,0x01,0x02,0x30,0x00,0x04,0x60,0x00,0x08,0xC0,0x00,0x11,0x80,0x00,0x23,0x02,0x00,0x46,0x06,0x00,0x8C,0x0E,0x01,0x18,0x1E,0x02,0x30,0x3F,0x04,0x60,0x3F,0x0B,0x00,0x2F,0x17,0xFF,0x8F,0xEF,0xFE,0x0F,0x80,
|
||||
// 'o'
|
||||
0x6F,0x08,0x17,0x17,0x00,0x17,
|
||||
0x00,0x7E,0x00,0x03,0x01,0x80,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x00,0x08,0x00,0x01,0x30,0x00,0x02,0x40,0x3C,0x03,0x80,0xFC,0x07,0x02,0x3C,0x0E,0x04,0x38,0x1C,0x08,0x30,0x3C,0x08,0x40,0x78,0x0F,0x01,0x30,0x00,0x02,0x70,0x00,0x08,0xF0,0x00,0x10,0xF0,0x00,0xC0,0xF0,0x03,0x00,0xFC,0x1C,0x00,0xFF,0xE0,0x00,0x3F,0x00,0x00,
|
||||
// 'p'
|
||||
0x70,0x09,0x13,0x15,0x00,0x13,
|
||||
0x3F,0xFC,0x08,0x00,0x43,0x80,0x06,0x70,0x00,0x46,0x00,0x04,0xC0,0x00,0x18,0x00,0x0B,0x01,0x81,0x60,0x30,0x2C,0x04,0x05,0x80,0x00,0x30,0x00,0x26,0x00,0x08,0xC0,0x02,0x18,0x01,0x83,0x01,0xE0,0x60,0x30,0x08,0x04,0x03,0x00,0x80,0x7F,0xE0,0x07,0xF8,0x00,
|
||||
// 'q'
|
||||
0x71,0x09,0x17,0x1C,0x00,0x17,
|
||||
0x00,0x7E,0x00,0x03,0x01,0x00,0x18,0x00,0x80,0x40,0x00,0x81,0x00,0x00,0x86,0x00,0x01,0x08,0x00,0x01,0x30,0x1E,0x02,0x40,0x7E,0x03,0x81,0x1E,0x07,0x02,0x1C,0x0E,0x04,0x18,0x1C,0x04,0x20,0x3C,0x07,0x80,0x78,0x00,0x01,0x30,0x00,0x02,0x70,0x00,0x04,0xF0,0x00,0x10,0xF0,0x00,0x70,0xF0,0x00,0x00,0xFC,0x00,0x40,0xFF,0x81,0x00,0x3F,0x84,0x00,0x0F,0x10,0x00,0x06,0x40,0x00,0x0F,0x00,0x00,0x1C,0x00,0x00,0x00,0x00,
|
||||
// 'r'
|
||||
0x72,0x09,0x18,0x17,0x00,0x18,
|
||||
0x3F,0xFE,0x00,0x60,0x01,0x80,0x70,0x00,0x40,0x70,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x10,0x10,0x30,0x18,0x10,0x30,0x10,0x10,0x30,0x00,0x10,0x30,0x00,0x20,0x30,0x00,0x20,0x30,0x00,0x10,0x30,0x00,0x1E,0x30,0x00,0x0A,0x30,0x18,0x06,0x30,0x1C,0x0C,0x20,0x0E,0x18,0x7F,0xFF,0x30,0x7F,0xE7,0x20,0x00,0x03,0xC0,0x00,0x03,0x80,0x00,0x03,0x00,
|
||||
// 's'
|
||||
0x73,0x07,0x11,0x19,0x00,0x11,
|
||||
0x00,0x06,0x00,0x02,0x80,0x1E,0x40,0x10,0x20,0x30,0x10,0x30,0x08,0x10,0x04,0x18,0x01,0x08,0x00,0x8C,0x0F,0x46,0x07,0xA3,0x01,0xE1,0xC0,0xE1,0xE0,0x41,0x70,0x21,0x80,0x10,0xC0,0x08,0x70,0x08,0x38,0x04,0x0C,0x04,0x06,0x04,0x03,0x3C,0x01,0xFC,0x00,0xF0,0x00,0x30,0x00,0x00,
|
||||
// 't'
|
||||
0x74,0x08,0x12,0x16,0x01,0x13,
|
||||
0x30,0x01,0x93,0xFF,0xDC,0x00,0x07,0x00,0x01,0xC0,0x00,0x70,0x00,0x1C,0x00,0x07,0x00,0x01,0xCC,0x07,0x7F,0x01,0xFF,0xC0,0x79,0xB0,0x1C,0x0C,0x04,0x03,0x01,0x00,0xC0,0x40,0x30,0x10,0x0C,0x04,0x03,0x01,0x00,0xC0,0x60,0x60,0x08,0x1F,0xFC,0x07,0xFE,0x00,
|
||||
// 'u'
|
||||
0x75,0x09,0x19,0x16,0xFF,0x18,
|
||||
0x1F,0xF1,0xFF,0x10,0x05,0x00,0x9C,0x07,0xC0,0xCE,0x02,0xE0,0x43,0x01,0x30,0x21,0x80,0x98,0x10,0xC0,0x4C,0x08,0x60,0x26,0x04,0x30,0x13,0x02,0x18,0x09,0x81,0x0C,0x04,0xC0,0x86,0x02,0x60,0x43,0x01,0x30,0x21,0xC0,0x70,0x10,0xE0,0x00,0x10,0x30,0x00,0x08,0x1C,0x00,0x08,0x0F,0x00,0x08,0x03,0xC0,0x08,0x00,0xFC,0x18,0x00,0x1F,0xF8,0x00,0x03,0xF0,0x00,
|
||||
// 'v'
|
||||
0x76,0x07,0x19,0x18,0x00,0x19,
|
||||
0x00,0xC1,0xC0,0x01,0x91,0x98,0x03,0x18,0xC3,0x06,0x04,0x60,0x64,0x02,0x20,0x1F,0x00,0xB0,0x1B,0xC0,0x70,0x0C,0xF0,0x10,0x08,0x38,0x00,0x08,0x0E,0x00,0x04,0x07,0x00,0x04,0x01,0xC0,0x06,0x00,0xE0,0x02,0x00,0x38,0x02,0x00,0x1C,0x01,0x00,0x07,0x01,0x00,0x03,0x81,0x80,0x00,0xE0,0x80,0x00,0x30,0x80,0x00,0x1C,0x40,0x00,0x06,0x40,0x00,0x03,0xE0,0x00,0x00,0xE0,0x00,0x00,0x60,0x00,
|
||||
// 'w'
|
||||
0x77,0x07,0x20,0x18,0x00,0x20,
|
||||
0x00,0x60,0x03,0x80,0x01,0x90,0x06,0x60,0x0E,0x10,0xC6,0x1C,0x38,0x11,0xA6,0x07,0x60,0x11,0x26,0x01,0x78,0x12,0x1C,0x06,0x78,0x0E,0x1C,0x04,0x3C,0x0C,0x08,0x08,0x1C,0x00,0x08,0x10,0x0C,0x00,0x00,0x10,0x0E,0x00,0x00,0x20,0x06,0x00,0x00,0x20,0x07,0x00,0x00,0x40,0x03,0x00,0x00,0x40,0x03,0x80,0x00,0x80,0x03,0x80,0x00,0x80,0x01,0xC0,0x81,0x00,0x01,0xC1,0xC0,0x00,0x00,0xE1,0xC2,0x00,0x00,0xE2,0xE4,0x00,0x00,0x74,0xE4,0x00,0x00,0x7C,0x78,0x00,0x00,0x38,0x78,0x00,0x00,0x30,0x30,0x00,
|
||||
// 'x'
|
||||
0x78,0x05,0x19,0x1D,0x00,0x18,
|
||||
0x00,0x01,0x80,0x00,0x01,0x20,0x00,0x61,0x8C,0x00,0x48,0xC3,0x00,0x44,0x40,0x60,0x43,0x60,0x10,0xC0,0xE0,0x18,0xC0,0x30,0x1C,0xC0,0x00,0x18,0x7C,0x00,0x08,0x1F,0x00,0x08,0x03,0x80,0x08,0x00,0xE0,0x04,0x00,0x38,0x02,0x00,0x0C,0x01,0x80,0x04,0x00,0x60,0x06,0x00,0x10,0x02,0x00,0x07,0x03,0x00,0x00,0x41,0x01,0x00,0x63,0x00,0xC0,0x62,0x00,0xF0,0x63,0x80,0x7C,0x61,0xF0,0x4E,0x60,0x7C,0x63,0xE0,0x0F,0x91,0xE0,0x01,0xF0,0x40,0x00,0x70,0x00,0x00,0x00,0x00,0x00,
|
||||
// 'y'
|
||||
0x79,0x06,0x19,0x1B,0x00,0x19,
|
||||
0x00,0x00,0x60,0x00,0xC0,0x48,0x00,0x80,0x62,0x00,0x88,0x20,0xC0,0x82,0x30,0x11,0x80,0xB0,0x01,0x80,0x30,0x0D,0x80,0x00,0x0C,0xF8,0x00,0x08,0x3E,0x00,0x04,0x07,0x80,0x04,0x01,0xE0,0x04,0x00,0x78,0x04,0x00,0x1C,0x02,0x00,0x0C,0x02,0x00,0x04,0x02,0x00,0x04,0x02,0x00,0x06,0x01,0x00,0x0E,0x01,0x00,0x0C,0x01,0x00,0x07,0x01,0x00,0x03,0xC0,0x80,0x01,0xF0,0x80,0x00,0x3E,0x00,0x00,0x0F,0xC0,0x00,0x03,0xE0,0x00,0x00,0x40,0x00,0x00,
|
||||
// 'z'
|
||||
0x7A,0x08,0x13,0x17,0xFF,0x12,
|
||||
0x0C,0x00,0x02,0xFF,0xFC,0xC0,0x01,0x98,0x00,0x23,0x00,0x04,0x60,0x01,0x0C,0x00,0x21,0x80,0x08,0x37,0x01,0x07,0xE0,0x60,0xF8,0x08,0x03,0x01,0x00,0x40,0x70,0x18,0x0D,0x02,0x00,0x20,0xC0,0x04,0x18,0x00,0x86,0x00,0x10,0xC0,0x02,0x10,0x00,0x47,0xFF,0xE8,0xFF,0xFE,0x00,0x01,0x80,
|
||||
// '{'
|
||||
0x7B,0x05,0x0D,0x1F,0x01,0x0E,
|
||||
0x00,0x10,0x0E,0x81,0x04,0x10,0x21,0x81,0x08,0x08,0xC0,0x46,0x0E,0x30,0x71,0x83,0x0C,0x10,0x60,0x84,0x04,0x60,0x23,0x02,0x18,0x08,0xC0,0x47,0x82,0x3C,0x10,0x60,0x83,0x05,0x18,0x38,0xC0,0x46,0x02,0x38,0x11,0xC0,0x87,0x84,0x1F,0xE0,0x7F,0x00,0x30,0x00,0x00,
|
||||
// '|'
|
||||
0x7C,0x1E,0x00,0x00,0x00,0x09,
|
||||
|
||||
// '}'
|
||||
0x7D,0x04,0x0E,0x1F,0x00,0x0F,
|
||||
0x30,0x00,0xBC,0x06,0x0C,0x18,0x08,0x60,0x21,0x80,0x46,0x01,0x1F,0x04,0x7C,0x11,0xB0,0x44,0xC1,0x03,0x04,0x0C,0x0C,0x30,0x10,0xE0,0x43,0x81,0x04,0x04,0x30,0x70,0xC1,0x03,0x04,0x0C,0x10,0xF0,0x46,0xC1,0x18,0x04,0x60,0x11,0x80,0x86,0x04,0x18,0x60,0x7F,0x81,0xF8,0x06,0x00,0x00,
|
||||
// '~'
|
||||
0x7E,0x1E,0x00,0x00,0x00,0x09,
|
||||
|
||||
|
||||
// Terminator
|
||||
0xFF
|
||||
};
|
24
components/mkspiffs/.travis.yml
Normal file
24
components/mkspiffs/.travis.yml
Normal file
@ -0,0 +1,24 @@
|
||||
language: cpp
|
||||
addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
packages:
|
||||
- g++-4.8
|
||||
script:
|
||||
- export CXX="g++-4.8" CC="gcc-4.8"
|
||||
- make dist
|
||||
notifications:
|
||||
email:
|
||||
recipients:
|
||||
- ivan@esp8266.com
|
||||
on_success: change
|
||||
on_failure: always
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: k/DDoCfLXIct8TcGjekKm5CAoTL6Wy6LXhI74Ssgc8VSbjJQ1crO2J4V5HnQw7QplgAXwqjkoAUkzEJiz34wqBaAv0w9o8+5jPwCP6rMQ/VEvbn1MPI52KIFbYqKxmXe5J24B00BttbGc773ldXPnvmv+qPWWcXDTpcosni2laBt3z8bxCGVwkQ7nuQUaAelzs21wQuhjmKQ6F1dgNN5XhdJ5qgFYYM8cwiigvcqIaCwLMcrOs7gj22TS242pzp38etWhfxUbqUKejWgOH4qYeU3Tf5gsu4WV0otbqXYMvV18gVSoAiMnodDfYJUNHlfelCAEqebvECrIvvE8D0syuVYz6fh2/BrxZ6HeiYj1CXILghOjPUZZZ7/chKglWnA1vL+6Uxn5LtyTJ5gbgMYXvKQUXrRVZ3Zd9xrmv/YaMnGq+6BDBkS30aXpSK2X0HvW9/6JyQ9L1sjnKdOzDmagvikHm2rrPXBRMMfYTt4nucgUBWqJqyFe0uGva/n8TG5RzOzdOgRxFx/lF8XudtR4Z4gUBUFpve/meVHVVK82+cxzfN97aFdxvBzyGq18EDjOEpDi7k7mZjXUycvD8UZ7o12sxJ0Zr6/9esiFUsaqyE+2Vi6bMbgEHGx7hfWbdfREnpOtjFLH+u5mAPIqOh89a/UJ6SbYm0cON+ewTMUkJ8=
|
||||
file: mkspiffs-$TRAVIS_TAG-linux64.tar.gz
|
||||
on:
|
||||
repo: igrr/mkspiffs
|
||||
tags: true
|
14
components/mkspiffs/Makefile.projbuild
Normal file
14
components/mkspiffs/Makefile.projbuild
Normal file
@ -0,0 +1,14 @@
|
||||
MKSPIFFS_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
MKSPIFFS_BUILD_DIR=$(abspath $(MKSPIFFS_COMPONENT_PATH)/mkspiffs)
|
||||
|
||||
# Custom recursive make for mkspiffs sub-project
|
||||
MKSPIFFS_MAKE=+$(MAKE) -C $(MKSPIFFS_COMPONENT_PATH)/src
|
||||
|
||||
.PHONY: mkspiffs clean
|
||||
|
||||
mkspiffs: $(SDKCONFIG_MAKEFILE)
|
||||
$(MKSPIFFS_MAKE) all
|
||||
|
||||
clean: $(SDKCONFIG_MAKEFILE)
|
||||
$(MKSPIFFS_MAKE) clean
|
||||
|
6
components/mkspiffs/component.mk
Normal file
6
components/mkspiffs/component.mk
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS :=
|
||||
COMPONENT_ADD_INCLUDEDIRS :=
|
93
components/mkspiffs/src/Makefile.original
Normal file
93
components/mkspiffs/src/Makefile.original
Normal file
@ -0,0 +1,93 @@
|
||||
CFLAGS ?= -std=gnu99 -Os -Wall
|
||||
CXXFLAGS ?= -std=gnu++11 -Os -Wall
|
||||
|
||||
ifeq ($(OS),Windows_NT)
|
||||
TARGET_OS := WINDOWS
|
||||
DIST_SUFFIX := windows
|
||||
ARCHIVE_CMD := 7z a
|
||||
ARCHIVE_EXTENSION := zip
|
||||
TARGET := mkspiffs.exe
|
||||
TARGET_CFLAGS := -mno-ms-bitfields
|
||||
TARGET_LDFLAGS := -Wl,-static -static-libgcc
|
||||
|
||||
else
|
||||
UNAME_S := $(shell uname -s)
|
||||
ifeq ($(UNAME_S),Linux)
|
||||
TARGET_OS := LINUX
|
||||
UNAME_P := $(shell uname -p)
|
||||
ifeq ($(UNAME_P),x86_64)
|
||||
DIST_SUFFIX := linux64
|
||||
endif
|
||||
ifneq ($(filter %86,$(UNAME_P)),)
|
||||
DIST_SUFFIX := linux32
|
||||
endif
|
||||
endif
|
||||
ifeq ($(UNAME_S),Darwin)
|
||||
TARGET_OS := OSX
|
||||
DIST_SUFFIX := osx
|
||||
CC=clang
|
||||
CXX=clang++
|
||||
TARGET_CFLAGS = -mmacosx-version-min=10.7 -arch i386 -arch x86_64
|
||||
TARGET_CXXFLAGS = -mmacosx-version-min=10.7 -arch i386 -arch x86_64 -stdlib=libc++
|
||||
TARGET_LDFLAGS = -arch i386 -arch x86_64 -stdlib=libc++
|
||||
endif
|
||||
ARCHIVE_CMD := tar czf
|
||||
ARCHIVE_EXTENSION := tar.gz
|
||||
TARGET := mkspiffs
|
||||
endif
|
||||
|
||||
VERSION ?= $(shell git describe --always)
|
||||
|
||||
OBJ := main.o \
|
||||
spiffs/spiffs_cache.o \
|
||||
spiffs/spiffs_check.o \
|
||||
spiffs/spiffs_gc.o \
|
||||
spiffs/spiffs_hydrogen.o \
|
||||
spiffs/spiffs_nucleus.o \
|
||||
|
||||
INCLUDES := -Itclap -Ispiffs -I.
|
||||
|
||||
CFLAGS += $(TARGET_CFLAGS)
|
||||
CXXFLAGS += $(TARGET_CXXFLAGS)
|
||||
LDFLAGS += $(TARGET_LDFLAGS)
|
||||
|
||||
CPPFLAGS += $(INCLUDES) -D$(TARGET_OS) -DVERSION=\"$(VERSION)\" -D__NO_INLINE__
|
||||
|
||||
DIST_NAME := mkspiffs-$(VERSION)-$(DIST_SUFFIX)
|
||||
DIST_DIR := $(DIST_NAME)
|
||||
DIST_ARCHIVE := $(DIST_NAME).$(ARCHIVE_EXTENSION)
|
||||
|
||||
.PHONY: all clean dist
|
||||
|
||||
all: $(TARGET)
|
||||
|
||||
dist: test $(DIST_ARCHIVE)
|
||||
|
||||
$(DIST_ARCHIVE): $(TARGET) $(DIST_DIR)
|
||||
cp $(TARGET) $(DIST_DIR)/
|
||||
$(ARCHIVE_CMD) $(DIST_ARCHIVE) $(DIST_DIR)
|
||||
|
||||
$(TARGET): $(OBJ)
|
||||
$(CXX) $^ -o $@ $(LDFLAGS)
|
||||
strip $(TARGET)
|
||||
|
||||
$(DIST_DIR):
|
||||
@mkdir -p $@
|
||||
|
||||
clean:
|
||||
@rm -f *.o
|
||||
@rm -f spiffs/*.o
|
||||
@rm -f $(TARGET)
|
||||
|
||||
SPIFFS_TEST_FS_CONFIG := -s 0x100000 -p 512 -b 0x2000
|
||||
|
||||
test: $(TARGET)
|
||||
ls -1 spiffs > out.list0
|
||||
./mkspiffs -c spiffs $(SPIFFS_TEST_FS_CONFIG) out.spiffs | sort | sed s/^\\/// > out.list1
|
||||
./mkspiffs -u spiffs_u $(SPIFFS_TEST_FS_CONFIG) out.spiffs | sort | sed s/^\\/// > out.list_u
|
||||
./mkspiffs -l $(SPIFFS_TEST_FS_CONFIG) out.spiffs | cut -f 2 | sort | sed s/^\\/// > out.list2
|
||||
diff --strip-trailing-cr out.list0 out.list1
|
||||
diff --strip-trailing-cr out.list0 out.list2
|
||||
diff spiffs spiffs_u
|
||||
rm -f out.{list0,list1,list2,list_u,spiffs}
|
||||
rm -R spiffs_u
|
80
components/mkspiffs/src/README.md
Normal file
80
components/mkspiffs/src/README.md
Normal file
@ -0,0 +1,80 @@
|
||||
# mkspiffs
|
||||
Tool to build and unpack [SPIFFS](https://github.com/pellepl/spiffs) images.
|
||||
|
||||
|
||||
## Usage
|
||||
|
||||
```
|
||||
|
||||
mkspiffs {-c <pack_dir>|-u <dest_dir>|-l|-i} [-d <0-5>] [-b <number>]
|
||||
[-p <number>] [-s <number>] [--] [--version] [-h]
|
||||
<image_file>
|
||||
|
||||
|
||||
Where:
|
||||
|
||||
-c <pack_dir>, --create <pack_dir>
|
||||
(OR required) create spiffs image from a directory
|
||||
-- OR --
|
||||
-u <dest_dir>, --unpack <dest_dir>
|
||||
(OR required) unpack spiffs image to a directory
|
||||
-- OR --
|
||||
-l, --list
|
||||
(OR required) list files in spiffs image
|
||||
-- OR --
|
||||
-i, --visualize
|
||||
(OR required) visualize spiffs image
|
||||
|
||||
|
||||
-d <0-5>, --debug <0-5>
|
||||
Debug level. 0 means no debug output.
|
||||
|
||||
-b <number>, --block <number>
|
||||
fs block size, in bytes
|
||||
|
||||
-p <number>, --page <number>
|
||||
fs page size, in bytes
|
||||
|
||||
-s <number>, --size <number>
|
||||
fs image size, in bytes
|
||||
|
||||
--, --ignore_rest
|
||||
Ignores the rest of the labeled arguments following this flag.
|
||||
|
||||
--version
|
||||
Displays version information and exits.
|
||||
|
||||
-h, --help
|
||||
Displays usage information and exits.
|
||||
|
||||
<image_file>
|
||||
(required) spiffs image file
|
||||
|
||||
|
||||
```
|
||||
## Build
|
||||
|
||||
You need gcc (≥4.8) or clang(≥600.0.57), and make. On Windows, use MinGW.
|
||||
|
||||
Run:
|
||||
```bash
|
||||
$ make dist
|
||||
```
|
||||
|
||||
### Build status
|
||||
|
||||
Linux | Windows
|
||||
------|-------
|
||||
[![Linux build status](http://img.shields.io/travis/igrr/mkspiffs.svg)](https://travis-ci.org/igrr/mkspiffs) | [![Windows build status](http://img.shields.io/appveyor/ci/igrr/mkspiffs.svg)](https://ci.appveyor.com/project/igrr/mkspiffs)
|
||||
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
|
||||
## To do
|
||||
|
||||
- [ ] Add more debug output and print SPIFFS debug output
|
||||
- [ ] Error handling
|
||||
- [ ] Determine the image size automatically when opening a file
|
||||
- [ ] Code cleanup
|
28
components/mkspiffs/src/appveyor.yml
Normal file
28
components/mkspiffs/src/appveyor.yml
Normal file
@ -0,0 +1,28 @@
|
||||
version: 0.0.{build}
|
||||
|
||||
platform:
|
||||
- x86
|
||||
|
||||
skip_commits:
|
||||
message: /\[ci skip\]/
|
||||
|
||||
matrix:
|
||||
fast_finish: true
|
||||
|
||||
build_script:
|
||||
- SET PATH=C:\MinGW\bin;C:\MinGW\msys\1.0\bin;%PATH%
|
||||
- make dist
|
||||
|
||||
artifacts:
|
||||
- path: '*.zip'
|
||||
|
||||
deploy:
|
||||
release: $(PRODUCT_VERSION)
|
||||
provider: GitHub
|
||||
auth_token:
|
||||
secure: 'PGg5fnoBpP1Omzr6f3KIYDiD8J30rretQjSl/MITRpzvSCmN88kM6VDMz1TBGZTA'
|
||||
artifact: /.*\.zip/
|
||||
draft: true
|
||||
prerelease: false
|
||||
on:
|
||||
appveyor_repo_tag: true
|
646
components/mkspiffs/src/main.cpp
Normal file
646
components/mkspiffs/src/main.cpp
Normal file
@ -0,0 +1,646 @@
|
||||
//
|
||||
// main.cpp
|
||||
// make_spiffs
|
||||
//
|
||||
// Created by Ivan Grokhotkov on 13/05/15.
|
||||
// Copyright (c) 2015 Ivan Grokhotkov. All rights reserved.
|
||||
//
|
||||
#define TCLAP_SETBASE_ZERO 1
|
||||
#define VERSION "0.3.6"
|
||||
|
||||
#include <iostream>
|
||||
#include "spiffs/spiffs.h"
|
||||
#include <vector>
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <time.h>
|
||||
#include <memory>
|
||||
#include <cstdlib>
|
||||
#include "tclap/CmdLine.h"
|
||||
#include "tclap/UnlabeledValueArg.h"
|
||||
|
||||
static std::vector<uint8_t> s_flashmem;
|
||||
|
||||
static std::string s_dirName;
|
||||
static std::string s_imageName;
|
||||
static int s_imageSize;
|
||||
static int s_pageSize;
|
||||
static int s_blockSize;
|
||||
|
||||
typedef struct {
|
||||
time_t mtime;
|
||||
time_t ctime;
|
||||
time_t atime;
|
||||
uint8_t spare[SPIFFS_OBJ_META_LEN - (sizeof(time_t)*3)];
|
||||
} spiffs_metadata_t;
|
||||
|
||||
enum Action { ACTION_NONE, ACTION_PACK, ACTION_UNPACK, ACTION_LIST, ACTION_VISUALIZE };
|
||||
static Action s_action = ACTION_NONE;
|
||||
|
||||
static spiffs s_fs;
|
||||
|
||||
static std::vector<uint8_t> s_spiffsWorkBuf;
|
||||
static std::vector<uint8_t> s_spiffsFds;
|
||||
static std::vector<uint8_t> s_spiffsCache;
|
||||
|
||||
|
||||
static s32_t api_spiffs_read(u32_t addr, u32_t size, u8_t *dst){
|
||||
memcpy(dst, &s_flashmem[0] + addr, size);
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
static s32_t api_spiffs_write(u32_t addr, u32_t size, u8_t *src){
|
||||
memcpy(&s_flashmem[0] + addr, src, size);
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
static s32_t api_spiffs_erase(u32_t addr, u32_t size){
|
||||
memset(&s_flashmem[0] + addr, 0xff, size);
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
|
||||
int g_debugLevel = 0;
|
||||
|
||||
|
||||
//implementation
|
||||
|
||||
int spiffsTryMount(){
|
||||
spiffs_config cfg = {0};
|
||||
|
||||
cfg.phys_addr = 0x0000;
|
||||
cfg.phys_size = (u32_t) s_flashmem.size();
|
||||
|
||||
cfg.phys_erase_block = s_blockSize;
|
||||
cfg.log_block_size = s_blockSize;
|
||||
cfg.log_page_size = s_pageSize;
|
||||
|
||||
cfg.hal_read_f = api_spiffs_read;
|
||||
cfg.hal_write_f = api_spiffs_write;
|
||||
cfg.hal_erase_f = api_spiffs_erase;
|
||||
|
||||
const int maxOpenFiles = 4;
|
||||
s_spiffsWorkBuf.resize(s_pageSize * 2);
|
||||
s_spiffsFds.resize(32 * maxOpenFiles);
|
||||
s_spiffsCache.resize((32 + s_pageSize) * maxOpenFiles);
|
||||
|
||||
return SPIFFS_mount(&s_fs, &cfg,
|
||||
&s_spiffsWorkBuf[0],
|
||||
&s_spiffsFds[0], s_spiffsFds.size(),
|
||||
&s_spiffsCache[0], s_spiffsCache.size(),
|
||||
NULL);
|
||||
}
|
||||
|
||||
bool spiffsMount(){
|
||||
if(SPIFFS_mounted(&s_fs))
|
||||
return true;
|
||||
int res = spiffsTryMount();
|
||||
return (res == SPIFFS_OK);
|
||||
}
|
||||
|
||||
bool spiffsFormat(){
|
||||
spiffsMount();
|
||||
SPIFFS_unmount(&s_fs);
|
||||
int formated = SPIFFS_format(&s_fs);
|
||||
if(formated != SPIFFS_OK)
|
||||
return false;
|
||||
return (spiffsTryMount() == SPIFFS_OK);
|
||||
}
|
||||
|
||||
void spiffsUnmount(){
|
||||
if(SPIFFS_mounted(&s_fs))
|
||||
SPIFFS_unmount(&s_fs);
|
||||
}
|
||||
|
||||
// WHITECAT BEGIN
|
||||
int addDir(const char* name) {
|
||||
spiffs_metadata_t meta;
|
||||
|
||||
std::string fileName = name;
|
||||
fileName += "/.";
|
||||
|
||||
std::cout << fileName << std::endl;
|
||||
|
||||
spiffs_file dst = SPIFFS_open(&s_fs, fileName.c_str(), SPIFFS_CREAT, 0);
|
||||
if (dst < 0) {
|
||||
std::cerr << "SPIFFS_write error(" << s_fs.err_code << "): ";
|
||||
|
||||
if (s_fs.err_code == SPIFFS_ERR_FULL) {
|
||||
std::cerr << "File system is full." << std::endl;
|
||||
} else {
|
||||
std::cerr << "unknown";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
SPIFFS_close(&s_fs, dst);
|
||||
return 1;
|
||||
}
|
||||
|
||||
SPIFFS_close(&s_fs, dst);
|
||||
if (strlen(name) > 0) {
|
||||
// Get the system time to file timestamps
|
||||
meta.atime = time(NULL);
|
||||
meta.ctime = meta.atime;
|
||||
meta.mtime = meta.atime;
|
||||
SPIFFS_update_meta(&s_fs, fileName.c_str(), &meta);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
// WHITECAT END
|
||||
|
||||
int addFile(char* name, const char* path) {
|
||||
spiffs_metadata_t meta;
|
||||
|
||||
FILE* src = fopen(path, "rb");
|
||||
if (!src) {
|
||||
std::cerr << "error: failed to open " << path << " for reading" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
spiffs_file dst = SPIFFS_open(&s_fs, name, SPIFFS_CREAT | SPIFFS_TRUNC | SPIFFS_RDWR, 0);
|
||||
|
||||
// read file size
|
||||
fseek(src, 0, SEEK_END);
|
||||
size_t size = ftell(src);
|
||||
fseek(src, 0, SEEK_SET);
|
||||
|
||||
if (g_debugLevel > 0) {
|
||||
std::cout << "file size: " << size << std::endl;
|
||||
}
|
||||
|
||||
size_t left = size;
|
||||
uint8_t data_byte;
|
||||
while (left > 0){
|
||||
if (1 != fread(&data_byte, 1, 1, src)) {
|
||||
std::cerr << "fread error!" << std::endl;
|
||||
|
||||
fclose(src);
|
||||
SPIFFS_close(&s_fs, dst);
|
||||
return 1;
|
||||
}
|
||||
int res = SPIFFS_write(&s_fs, dst, &data_byte, 1);
|
||||
if (res < 0) {
|
||||
std::cerr << "SPIFFS_write error(" << s_fs.err_code << "): ";
|
||||
|
||||
if (s_fs.err_code == SPIFFS_ERR_FULL) {
|
||||
std::cerr << "File system is full." << std::endl;
|
||||
} else {
|
||||
std::cerr << "unknown";
|
||||
}
|
||||
std::cerr << std::endl;
|
||||
|
||||
if (g_debugLevel > 0) {
|
||||
std::cout << "data left: " << left << std::endl;
|
||||
}
|
||||
|
||||
fclose(src);
|
||||
SPIFFS_close(&s_fs, dst);
|
||||
return 1;
|
||||
}
|
||||
left -= 1;
|
||||
}
|
||||
|
||||
SPIFFS_close(&s_fs, dst);
|
||||
|
||||
// Get the system time to file timestamps
|
||||
meta.atime = time(NULL);
|
||||
meta.ctime = meta.atime;
|
||||
meta.mtime = meta.atime;
|
||||
SPIFFS_update_meta(&s_fs, name, &meta);
|
||||
|
||||
fclose(src);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int addFiles(const char* dirname, const char* subPath) {
|
||||
DIR *dir;
|
||||
struct dirent *ent;
|
||||
bool error = false;
|
||||
std::string dirPath = dirname;
|
||||
dirPath += subPath;
|
||||
|
||||
// Open directory
|
||||
if ((dir = opendir (dirPath.c_str())) != NULL) {
|
||||
|
||||
// Read files from directory.
|
||||
while ((ent = readdir (dir)) != NULL) {
|
||||
// Ignore dir itself.
|
||||
if (ent->d_name[0] == '.')
|
||||
continue;
|
||||
|
||||
std::string fullpath = dirPath;
|
||||
fullpath += ent->d_name;
|
||||
struct stat path_stat;
|
||||
stat (fullpath.c_str(), &path_stat);
|
||||
|
||||
if (!S_ISREG(path_stat.st_mode)) {
|
||||
// Check if path is a directory.
|
||||
if (S_ISDIR(path_stat.st_mode)) {
|
||||
// Prepare new sub path.
|
||||
std::string newSubPath = subPath;
|
||||
newSubPath += ent->d_name;
|
||||
|
||||
// WHITECAT BEGIN
|
||||
addDir(newSubPath.c_str());
|
||||
// WHITECAT END
|
||||
|
||||
newSubPath += "/";
|
||||
|
||||
if (addFiles(dirname, newSubPath.c_str()) != 0)
|
||||
{
|
||||
std::cerr << "Error for adding content from " << ent->d_name << "!" << std::endl;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cerr << "skipping " << ent->d_name << std::endl;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Filepath with dirname as root folder.
|
||||
std::string filepath = subPath;
|
||||
filepath += ent->d_name;
|
||||
std::cout << filepath << std::endl;
|
||||
|
||||
// Add File to image.
|
||||
if (addFile((char*)filepath.c_str(), fullpath.c_str()) != 0) {
|
||||
std::cerr << "error adding file!" << std::endl;
|
||||
error = true;
|
||||
if (g_debugLevel > 0) {
|
||||
std::cout << std::endl;
|
||||
}
|
||||
break;
|
||||
}
|
||||
} // end while
|
||||
closedir (dir);
|
||||
} else {
|
||||
std::cerr << "warning: can't read source directory" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
return (error) ? 1 : 0;
|
||||
}
|
||||
|
||||
void listFiles() {
|
||||
spiffs_DIR dir;
|
||||
spiffs_dirent ent;
|
||||
|
||||
SPIFFS_opendir(&s_fs, 0, &dir);
|
||||
spiffs_dirent* it;
|
||||
while (true) {
|
||||
it = SPIFFS_readdir(&dir, &ent);
|
||||
if (!it)
|
||||
break;
|
||||
|
||||
std::cout << it->size << '\t' << it->name << std::endl;
|
||||
}
|
||||
SPIFFS_closedir(&dir);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Check if directory exists.
|
||||
* @param path Directory path.
|
||||
* @return True if exists otherwise false.
|
||||
*
|
||||
* @author Pascal Gollor (http://www.pgollor.de/cms/)
|
||||
*/
|
||||
bool dirExists(const char* path) {
|
||||
DIR *d = opendir(path);
|
||||
|
||||
if (d) {
|
||||
closedir(d);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Create directory if it not exists.
|
||||
* @param path Directory path.
|
||||
* @return True or false.
|
||||
*
|
||||
* @author Pascal Gollor (http://www.pgollor.de/cms/)
|
||||
*/
|
||||
bool dirCreate(const char* path) {
|
||||
// Check if directory also exists.
|
||||
if (dirExists(path)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// platform stuff...
|
||||
#if defined(_WIN32)
|
||||
if (_mkdir(path) != 0) {
|
||||
#else
|
||||
if (mkdir(path, S_IRWXU | S_IXGRP | S_IRGRP | S_IROTH | S_IXOTH) != 0) {
|
||||
#endif
|
||||
std::cerr << "Can not create directory!!!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unpack file from file system.
|
||||
* @param spiffsFile SPIFFS dir entry pointer.
|
||||
* @param destPath Destination file path path.
|
||||
* @return True or false.
|
||||
*
|
||||
* @author Pascal Gollor (http://www.pgollor.de/cms/)
|
||||
*/
|
||||
bool unpackFile(spiffs_dirent *spiffsFile, const char *destPath) {
|
||||
u8_t buffer[spiffsFile->size];
|
||||
std::string filename = (const char*)(spiffsFile->name);
|
||||
|
||||
// Open file from spiffs file system.
|
||||
spiffs_file src = SPIFFS_open(&s_fs, (char *)(filename.c_str()), SPIFFS_RDONLY, 0);
|
||||
|
||||
// read content into buffer
|
||||
SPIFFS_read(&s_fs, src, buffer, spiffsFile->size);
|
||||
|
||||
// Close spiffs file.
|
||||
SPIFFS_close(&s_fs, src);
|
||||
|
||||
// Open file.
|
||||
FILE* dst = fopen(destPath, "wb");
|
||||
|
||||
// Write content into file.
|
||||
fwrite(buffer, sizeof(u8_t), sizeof(buffer), dst);
|
||||
|
||||
// Close file.
|
||||
fclose(dst);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unpack files from file system.
|
||||
* @param sDest Directory path as std::string.
|
||||
* @return True or false.
|
||||
*
|
||||
* @author Pascal Gollor (http://www.pgollor.de/cms/)
|
||||
*
|
||||
* todo: Do unpack stuff for directories.
|
||||
*/
|
||||
bool unpackFiles(std::string sDest) {
|
||||
spiffs_DIR dir;
|
||||
spiffs_dirent ent;
|
||||
|
||||
// Add "./" to path if is not given.
|
||||
if (sDest.find("./") == std::string::npos && sDest.find("/") == std::string::npos) {
|
||||
sDest = "./" + sDest;
|
||||
}
|
||||
|
||||
// Check if directory exists. If it does not then try to create it with permissions 755.
|
||||
if (! dirExists(sDest.c_str())) {
|
||||
std::cout << "Directory " << sDest << " does not exists. Try to create it." << std::endl;
|
||||
|
||||
// Try to create directory.
|
||||
if (! dirCreate(sDest.c_str())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Open directory.
|
||||
SPIFFS_opendir(&s_fs, 0, &dir);
|
||||
|
||||
// Read content from directory.
|
||||
spiffs_dirent* it = SPIFFS_readdir(&dir, &ent);
|
||||
while (it) {
|
||||
// Check if content is a file.
|
||||
if ((int)(it->type) == 1) {
|
||||
std::string name = (const char*)(it->name);
|
||||
std::string sDestFilePath = sDest + name;
|
||||
size_t pos = name.find_last_of("/");
|
||||
|
||||
// If file is in sub directory?
|
||||
if (pos > 0) {
|
||||
// Subdir path.
|
||||
std::string path = sDest;
|
||||
path += name.substr(0, pos);
|
||||
|
||||
// Create subddir if subdir not exists.
|
||||
if (!dirExists(path.c_str())) {
|
||||
if (!dirCreate(path.c_str())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unpack file to destination directory.
|
||||
if (! unpackFile(it, sDestFilePath.c_str()) ) {
|
||||
std::cout << "Can not unpack " << it->name << "!" << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Output stuff.
|
||||
std::cout
|
||||
<< it->name
|
||||
<< '\t'
|
||||
<< " > " << sDestFilePath
|
||||
<< '\t'
|
||||
<< "size: " << it->size << " Bytes"
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
// Get next file handle.
|
||||
it = SPIFFS_readdir(&dir, &ent);
|
||||
} // end while
|
||||
|
||||
// Close directory.
|
||||
SPIFFS_closedir(&dir);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Actions
|
||||
|
||||
int actionPack() {
|
||||
s_flashmem.resize(s_imageSize, 0xff);
|
||||
|
||||
FILE* fdres = fopen(s_imageName.c_str(), "wb");
|
||||
if (!fdres) {
|
||||
std::cerr << "error: failed to open image file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
spiffsFormat();
|
||||
|
||||
// WHITECAT BEGIN
|
||||
addDir("");
|
||||
// WHITECAT END
|
||||
|
||||
int result = addFiles(s_dirName.c_str(), "/");
|
||||
spiffsUnmount();
|
||||
|
||||
fwrite(&s_flashmem[0], 4, s_flashmem.size()/4, fdres);
|
||||
fclose(fdres);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Unpack action.
|
||||
* @return 0 success, 1 error
|
||||
*
|
||||
* @author Pascal Gollor (http://www.pgollor.de/cms/)
|
||||
*/
|
||||
int actionUnpack(void) {
|
||||
int ret = 0;
|
||||
s_flashmem.resize(s_imageSize, 0xff);
|
||||
|
||||
// open spiffs image
|
||||
FILE* fdsrc = fopen(s_imageName.c_str(), "rb");
|
||||
if (!fdsrc) {
|
||||
std::cerr << "error: failed to open image file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
// read content into s_flashmem
|
||||
ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc);
|
||||
|
||||
// close fiel handle
|
||||
fclose(fdsrc);
|
||||
|
||||
// mount file system
|
||||
spiffsMount();
|
||||
|
||||
// unpack files
|
||||
if (! unpackFiles(s_dirName)) {
|
||||
ret = 1;
|
||||
}
|
||||
|
||||
// unmount file system
|
||||
spiffsUnmount();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int actionList() {
|
||||
int ret = 0;
|
||||
s_flashmem.resize(s_imageSize, 0xff);
|
||||
|
||||
FILE* fdsrc = fopen(s_imageName.c_str(), "rb");
|
||||
if (!fdsrc) {
|
||||
std::cerr << "error: failed to open image file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc);
|
||||
fclose(fdsrc);
|
||||
spiffsMount();
|
||||
listFiles();
|
||||
spiffsUnmount();
|
||||
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
int actionVisualize() {
|
||||
int ret = 0;
|
||||
s_flashmem.resize(s_imageSize, 0xff);
|
||||
|
||||
FILE* fdsrc = fopen(s_imageName.c_str(), "rb");
|
||||
if (!fdsrc) {
|
||||
std::cerr << "error: failed to open image file" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
ret = fread(&s_flashmem[0], 4, s_flashmem.size()/4, fdsrc);
|
||||
fclose(fdsrc);
|
||||
|
||||
spiffsMount();
|
||||
//SPIFFS_vis(&s_fs);
|
||||
uint32_t total, used;
|
||||
SPIFFS_info(&s_fs, &total, &used);
|
||||
std::cout << "total: " << total << std::endl << "used: " << used << std::endl;
|
||||
spiffsUnmount();
|
||||
|
||||
ret = 0;
|
||||
return ret;
|
||||
}
|
||||
|
||||
void processArgs(int argc, const char** argv) {
|
||||
TCLAP::CmdLine cmd("", ' ', VERSION);
|
||||
TCLAP::ValueArg<std::string> packArg( "c", "create", "create spiffs image from a directory", true, "", "pack_dir");
|
||||
TCLAP::ValueArg<std::string> unpackArg( "u", "unpack", "unpack spiffs image to a directory", true, "", "dest_dir");
|
||||
TCLAP::SwitchArg listArg( "l", "list", "list files in spiffs image", false);
|
||||
TCLAP::SwitchArg visualizeArg( "i", "visualize", "visualize spiffs image", false);
|
||||
TCLAP::UnlabeledValueArg<std::string> outNameArg( "image_file", "spiffs image file", true, "", "image_file" );
|
||||
TCLAP::ValueArg<int> imageSizeArg( "s", "size", "fs image size, in bytes", false, 0x10000, "number" );
|
||||
TCLAP::ValueArg<int> pageSizeArg( "p", "page", "fs page size, in bytes", false, 256, "number" );
|
||||
TCLAP::ValueArg<int> blockSizeArg( "b", "block", "fs block size, in bytes", false, 4096, "number" );
|
||||
TCLAP::ValueArg<int> debugArg( "d", "debug", "Debug level. 0 means no debug output.", false, 0, "0-5" );
|
||||
|
||||
cmd.add( imageSizeArg );
|
||||
cmd.add( pageSizeArg );
|
||||
cmd.add( blockSizeArg );
|
||||
cmd.add(debugArg);
|
||||
std::vector<TCLAP::Arg*> args = {&packArg, &unpackArg, &listArg, &visualizeArg};
|
||||
cmd.xorAdd( args );
|
||||
cmd.add( outNameArg );
|
||||
cmd.parse( argc, argv );
|
||||
|
||||
if (debugArg.getValue() > 0) {
|
||||
std::cout << "Debug output enabled" << std::endl;
|
||||
g_debugLevel = debugArg.getValue();
|
||||
}
|
||||
|
||||
if (packArg.isSet()) {
|
||||
s_dirName = packArg.getValue();
|
||||
s_action = ACTION_PACK;
|
||||
} else if (unpackArg.isSet()) {
|
||||
s_dirName = unpackArg.getValue();
|
||||
s_action = ACTION_UNPACK;
|
||||
} else if (listArg.isSet()) {
|
||||
s_action = ACTION_LIST;
|
||||
} else if (visualizeArg.isSet()) {
|
||||
s_action = ACTION_VISUALIZE;
|
||||
}
|
||||
|
||||
s_imageName = outNameArg.getValue();
|
||||
s_imageSize = imageSizeArg.getValue();
|
||||
s_pageSize = pageSizeArg.getValue();
|
||||
s_blockSize = blockSizeArg.getValue();
|
||||
}
|
||||
|
||||
int main(int argc, const char * argv[]) {
|
||||
|
||||
try {
|
||||
processArgs(argc, argv);
|
||||
} catch(...) {
|
||||
std::cerr << "Invalid arguments" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
switch (s_action) {
|
||||
case ACTION_PACK:
|
||||
return actionPack();
|
||||
break;
|
||||
case ACTION_UNPACK:
|
||||
return actionUnpack();
|
||||
break;
|
||||
case ACTION_LIST:
|
||||
return actionList();
|
||||
break;
|
||||
case ACTION_VISUALIZE:
|
||||
return actionVisualize();
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
BIN
components/mkspiffs/src/mkspiffs
Executable file
BIN
components/mkspiffs/src/mkspiffs
Executable file
Binary file not shown.
138
components/mkspiffs/src/spiffs/esp_spiffs.c
Normal file
138
components/mkspiffs/src/spiffs/esp_spiffs.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Lua RTOS, SPIFFS low access
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "spiffs.h"
|
||||
|
||||
#include <esp_spi_flash.h>
|
||||
|
||||
s32_t esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst) {
|
||||
u32_t aaddr;
|
||||
u8_t *buff = NULL;
|
||||
u8_t *abuff = NULL;
|
||||
u32_t asize;
|
||||
|
||||
asize = size;
|
||||
|
||||
// Align address to 4 byte
|
||||
aaddr = (addr + (4 - 1)) & (u32_t)-4;
|
||||
if (aaddr != addr) {
|
||||
aaddr -= 4;
|
||||
asize += (addr - aaddr);
|
||||
}
|
||||
|
||||
// Align size to 4 byte
|
||||
asize = (asize + (4 - 1)) & (u32_t)-4;
|
||||
|
||||
if ((aaddr != addr) || (asize != size)) {
|
||||
// Align buffer
|
||||
buff = malloc(asize + 4);
|
||||
if (!buff) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
abuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & (u32_t)-4);
|
||||
|
||||
if (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {
|
||||
free(buff);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(dst, abuff + (addr - aaddr), size);
|
||||
|
||||
free(buff);
|
||||
} else {
|
||||
if (spi_flash_read(addr, (void *)dst, size) != 0) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
s32_t esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src) {
|
||||
u32_t aaddr;
|
||||
u8_t *buff = NULL;
|
||||
u8_t *abuff = NULL;
|
||||
u32_t asize;
|
||||
|
||||
asize = size;
|
||||
|
||||
// Align address to 4 byte
|
||||
aaddr = (addr + (4 - 1)) & -4;
|
||||
if (aaddr != addr) {
|
||||
aaddr -= 4;
|
||||
asize += (addr - aaddr);
|
||||
}
|
||||
|
||||
// Align size to 4 byte
|
||||
asize = (asize + (4 - 1)) & -4;
|
||||
|
||||
if ((aaddr != addr) || (asize != size)) {
|
||||
// Align buffer
|
||||
buff = malloc(asize + 4);
|
||||
if (!buff) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
abuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & -4);
|
||||
|
||||
if (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {
|
||||
free(buff);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(abuff + (addr - aaddr), src, size);
|
||||
|
||||
if (spi_flash_write(aaddr, (uint32_t *)abuff, asize) != 0) {
|
||||
free(buff);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
free(buff);
|
||||
} else {
|
||||
if (spi_flash_write(addr, (uint32_t *)src, size) != 0) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
s32_t IRAM_ATTR esp32_spi_flash_erase(u32_t addr, u32_t size) {
|
||||
if (spi_flash_erase_sector(addr >> 12) != 0) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
return SPIFFS_OK;
|
||||
}
|
43
components/mkspiffs/src/spiffs/esp_spiffs.h
Normal file
43
components/mkspiffs/src/spiffs/esp_spiffs.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Lua RTOS, write syscall implementation
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
|
||||
#ifndef __ESP_SPIFFS_H__
|
||||
#define __ESP_SPIFFS_H__
|
||||
|
||||
#include "spiffs.h"
|
||||
|
||||
s32_t esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst);
|
||||
s32_t esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src);
|
||||
s32_t esp32_spi_flash_erase(u32_t addr, u32_t size);
|
||||
|
||||
#define low_spiffs_read (spiffs_read *)esp32_spi_flash_read
|
||||
#define low_spiffs_write (spiffs_write *)esp32_spi_flash_write
|
||||
#define low_spiffs_erase (spiffs_erase *)esp32_spi_flash_erase
|
||||
|
||||
#endif // __ESP_SPIFFS_H__
|
813
components/mkspiffs/src/spiffs/spiffs.h
Normal file
813
components/mkspiffs/src/spiffs/spiffs.h
Normal file
@ -0,0 +1,813 @@
|
||||
/*
|
||||
* spiffs.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_H_
|
||||
#define SPIFFS_H_
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "spiffs_config.h"
|
||||
|
||||
#define SPIFFS_OK 0
|
||||
#define SPIFFS_ERR_NOT_MOUNTED -10000
|
||||
#define SPIFFS_ERR_FULL -10001
|
||||
#define SPIFFS_ERR_NOT_FOUND -10002
|
||||
#define SPIFFS_ERR_END_OF_OBJECT -10003
|
||||
#define SPIFFS_ERR_DELETED -10004
|
||||
#define SPIFFS_ERR_NOT_FINALIZED -10005
|
||||
#define SPIFFS_ERR_NOT_INDEX -10006
|
||||
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
|
||||
#define SPIFFS_ERR_FILE_CLOSED -10008
|
||||
#define SPIFFS_ERR_FILE_DELETED -10009
|
||||
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
|
||||
#define SPIFFS_ERR_IS_INDEX -10011
|
||||
#define SPIFFS_ERR_IS_FREE -10012
|
||||
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013
|
||||
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014
|
||||
#define SPIFFS_ERR_INDEX_REF_FREE -10015
|
||||
#define SPIFFS_ERR_INDEX_REF_LU -10016
|
||||
#define SPIFFS_ERR_INDEX_REF_INVALID -10017
|
||||
#define SPIFFS_ERR_INDEX_FREE -10018
|
||||
#define SPIFFS_ERR_INDEX_LU -10019
|
||||
#define SPIFFS_ERR_INDEX_INVALID -10020
|
||||
#define SPIFFS_ERR_NOT_WRITABLE -10021
|
||||
#define SPIFFS_ERR_NOT_READABLE -10022
|
||||
#define SPIFFS_ERR_CONFLICTING_NAME -10023
|
||||
#define SPIFFS_ERR_NOT_CONFIGURED -10024
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FS -10025
|
||||
#define SPIFFS_ERR_MOUNTED -10026
|
||||
#define SPIFFS_ERR_ERASE_FAIL -10027
|
||||
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
||||
|
||||
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
|
||||
|
||||
#define SPIFFS_ERR_FILE_EXISTS -10030
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FILE -10031
|
||||
#define SPIFFS_ERR_RO_NOT_IMPL -10032
|
||||
#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033
|
||||
#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034
|
||||
#define SPIFFS_ERR_PROBE_NOT_A_FS -10035
|
||||
#define SPIFFS_ERR_NAME_TOO_LONG -10036
|
||||
|
||||
#define SPIFFS_ERR_IX_MAP_UNMAPPED -10037
|
||||
#define SPIFFS_ERR_IX_MAP_MAPPED -10038
|
||||
#define SPIFFS_ERR_IX_MAP_BAD_RANGE -10039
|
||||
|
||||
#define SPIFFS_ERR_INTERNAL -10050
|
||||
|
||||
#define SPIFFS_ERR_TEST -10100
|
||||
|
||||
|
||||
// spiffs file descriptor index type. must be signed
|
||||
typedef s16_t spiffs_file;
|
||||
// spiffs file descriptor flags
|
||||
typedef u16_t spiffs_flags;
|
||||
// spiffs file mode
|
||||
typedef u16_t spiffs_mode;
|
||||
// object type
|
||||
typedef u8_t spiffs_obj_type;
|
||||
|
||||
struct spiffs_t;
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system check callback report operation */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_LOOKUP = 0,
|
||||
SPIFFS_CHECK_INDEX,
|
||||
SPIFFS_CHECK_PAGE
|
||||
} spiffs_check_type;
|
||||
|
||||
/* file system check callback report type */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_PROGRESS = 0,
|
||||
SPIFFS_CHECK_ERROR,
|
||||
SPIFFS_CHECK_FIX_INDEX,
|
||||
SPIFFS_CHECK_FIX_LOOKUP,
|
||||
SPIFFS_CHECK_DELETE_ORPHANED_INDEX,
|
||||
SPIFFS_CHECK_DELETE_PAGE,
|
||||
SPIFFS_CHECK_DELETE_BAD_FILE
|
||||
} spiffs_check_report;
|
||||
|
||||
/* file system check callback function */
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system listener callback operation */
|
||||
typedef enum {
|
||||
/* the file has been created */
|
||||
SPIFFS_CB_CREATED = 0,
|
||||
/* the file has been updated or moved to another page */
|
||||
SPIFFS_CB_UPDATED,
|
||||
/* the file has been deleted */
|
||||
SPIFFS_CB_DELETED
|
||||
} spiffs_fileop_type;
|
||||
|
||||
/* file system listener callback function */
|
||||
typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);
|
||||
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) \
|
||||
printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Any write to the filehandle is appended to end of the file */
|
||||
#define SPIFFS_APPEND (1<<0)
|
||||
#define SPIFFS_O_APPEND SPIFFS_APPEND
|
||||
/* If the opened file exists, it will be truncated to zero length before opened */
|
||||
#define SPIFFS_TRUNC (1<<1)
|
||||
#define SPIFFS_O_TRUNC SPIFFS_TRUNC
|
||||
/* If the opened file does not exist, it will be created before opened */
|
||||
#define SPIFFS_CREAT (1<<2)
|
||||
#define SPIFFS_O_CREAT SPIFFS_CREAT
|
||||
/* The opened file may only be read */
|
||||
#define SPIFFS_RDONLY (1<<3)
|
||||
#define SPIFFS_O_RDONLY SPIFFS_RDONLY
|
||||
/* The opened file may only be written */
|
||||
#define SPIFFS_WRONLY (1<<4)
|
||||
#define SPIFFS_O_WRONLY SPIFFS_WRONLY
|
||||
/* The opened file may be both read and written */
|
||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
||||
#define SPIFFS_O_RDWR SPIFFS_RDWR
|
||||
/* Any writes to the filehandle will never be cached but flushed directly */
|
||||
#define SPIFFS_DIRECT (1<<5)
|
||||
#define SPIFFS_O_DIRECT SPIFFS_DIRECT
|
||||
/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */
|
||||
#define SPIFFS_EXCL (1<<6)
|
||||
#define SPIFFS_O_EXCL SPIFFS_EXCL
|
||||
|
||||
#define SPIFFS_SEEK_SET (0)
|
||||
#define SPIFFS_SEEK_CUR (1)
|
||||
#define SPIFFS_SEEK_END (2)
|
||||
|
||||
#define SPIFFS_TYPE_FILE (1)
|
||||
#define SPIFFS_TYPE_DIR (2)
|
||||
#define SPIFFS_TYPE_HARD_LINK (3)
|
||||
#define SPIFFS_TYPE_SOFT_LINK (4)
|
||||
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// phys structs
|
||||
|
||||
// spiffs spi configuration struct
|
||||
typedef struct {
|
||||
// physical read function
|
||||
spiffs_read hal_read_f;
|
||||
// physical write function
|
||||
spiffs_write hal_write_f;
|
||||
// physical erase function
|
||||
spiffs_erase hal_erase_f;
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
// physical size of the spi flash
|
||||
u32_t phys_size;
|
||||
// physical offset in spi flash used for spiffs,
|
||||
// must be on block boundary
|
||||
u32_t phys_addr;
|
||||
// physical size when erasing a block
|
||||
u32_t phys_erase_block;
|
||||
|
||||
// logical size of a block, must be on physical
|
||||
// block size boundary and must never be less than
|
||||
// a physical block
|
||||
u32_t log_block_size;
|
||||
// logical size of a page, must be at least
|
||||
// log_block_size / 8
|
||||
u32_t log_page_size;
|
||||
|
||||
#endif
|
||||
#if SPIFFS_FILEHDL_OFFSET
|
||||
// an integer offset added to each file handle
|
||||
u16_t fh_ix_offset;
|
||||
#endif
|
||||
} spiffs_config;
|
||||
|
||||
typedef struct spiffs_t {
|
||||
// file system configuration
|
||||
spiffs_config cfg;
|
||||
// number of logical blocks
|
||||
u32_t block_count;
|
||||
|
||||
// cursor for free blocks, block index
|
||||
spiffs_block_ix free_cursor_block_ix;
|
||||
// cursor for free blocks, entry index
|
||||
int free_cursor_obj_lu_entry;
|
||||
// cursor when searching, block index
|
||||
spiffs_block_ix cursor_block_ix;
|
||||
// cursor when searching, entry index
|
||||
int cursor_obj_lu_entry;
|
||||
|
||||
// primary work buffer, size of a logical page
|
||||
u8_t *lu_work;
|
||||
// secondary work buffer, size of a logical page
|
||||
u8_t *work;
|
||||
// file descriptor memory area
|
||||
u8_t *fd_space;
|
||||
// available file descriptors
|
||||
u32_t fd_count;
|
||||
|
||||
// last error
|
||||
s32_t err_code;
|
||||
|
||||
// current number of free blocks
|
||||
u32_t free_blocks;
|
||||
// current number of busy pages
|
||||
u32_t stats_p_allocated;
|
||||
// current number of deleted pages
|
||||
u32_t stats_p_deleted;
|
||||
// flag indicating that garbage collector is cleaning
|
||||
u8_t cleaning;
|
||||
// max erase count amongst all blocks
|
||||
spiffs_obj_id max_erase_count;
|
||||
|
||||
#if SPIFFS_GC_STATS
|
||||
u32_t stats_gc_runs;
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
// cache memory
|
||||
void *cache;
|
||||
// cache size
|
||||
u32_t cache_size;
|
||||
#if SPIFFS_CACHE_STATS
|
||||
u32_t cache_hits;
|
||||
u32_t cache_misses;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// check callback function
|
||||
spiffs_check_callback check_cb_f;
|
||||
// file callback function
|
||||
spiffs_file_callback file_cb_f;
|
||||
// mounted flag
|
||||
u8_t mounted;
|
||||
// user data
|
||||
void *user_data;
|
||||
// config magic
|
||||
u32_t config_magic;
|
||||
} spiffs;
|
||||
|
||||
/* spiffs file status struct */
|
||||
typedef struct {
|
||||
spiffs_obj_id obj_id;
|
||||
u32_t size;
|
||||
spiffs_obj_type type;
|
||||
spiffs_page_ix pix;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
} spiffs_stat;
|
||||
|
||||
struct spiffs_dirent {
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
spiffs_obj_type type;
|
||||
u32_t size;
|
||||
spiffs_page_ix pix;
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
spiffs_block_ix block;
|
||||
int entry;
|
||||
} spiffs_DIR;
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
typedef struct {
|
||||
// buffer with looked up data pixes
|
||||
spiffs_page_ix *map_buf;
|
||||
// precise file byte offset
|
||||
u32_t offset;
|
||||
// start data span index of lookup buffer
|
||||
spiffs_span_ix start_spix;
|
||||
// end data span index of lookup buffer
|
||||
spiffs_span_ix end_spix;
|
||||
} spiffs_ix_map;
|
||||
|
||||
#endif
|
||||
|
||||
// functions
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
/**
|
||||
* Special function. This takes a spiffs config struct and returns the number
|
||||
* of blocks this file system was formatted with. This function relies on
|
||||
* that following info is set correctly in given config struct:
|
||||
*
|
||||
* phys_addr, log_page_size, and log_block_size.
|
||||
*
|
||||
* Also, hal_read_f must be set in the config struct.
|
||||
*
|
||||
* One must be sure of the correct page size and that the physical address is
|
||||
* correct in the probed file system when calling this function. It is not
|
||||
* checked if the phys_addr actually points to the start of the file system,
|
||||
* so one might get a false positive if entering a phys_addr somewhere in the
|
||||
* middle of the file system at block boundary. In addition, it is not checked
|
||||
* if the page size is actually correct. If it is not, weird file system sizes
|
||||
* will be returned.
|
||||
*
|
||||
* If this function detects a file system it returns the assumed file system
|
||||
* size, which can be used to set the phys_size.
|
||||
*
|
||||
* Otherwise, it returns an error indicating why it is not regarded as a file
|
||||
* system.
|
||||
*
|
||||
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
||||
* macros. It returns the error code directly, instead of as read by
|
||||
* SPIFFS_errno.
|
||||
*
|
||||
* @param config essential parts of the physical and logical
|
||||
* configuration of the file system.
|
||||
*/
|
||||
s32_t SPIFFS_probe_fs(spiffs_config *config);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
|
||||
/**
|
||||
* Initializes the file system dynamic parameters and mounts the filesystem.
|
||||
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
||||
* if the flash does not contain a recognizable file system.
|
||||
* In this case, SPIFFS_format must be called prior to remounting.
|
||||
* @param fs the file system struct
|
||||
* @param config the physical and logical configuration of the file system
|
||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
||||
* bytes used throughout all file system operations
|
||||
* @param fd_space memory for file descriptors
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
* @param check_cb_f callback function for reporting during consistency checks
|
||||
*/
|
||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
void *cache, u32_t cache_size,
|
||||
spiffs_check_callback check_cb_f);
|
||||
|
||||
/**
|
||||
* Unmounts the file system. All file handles will be flushed of any
|
||||
* cached writes and closed.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_unmount(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Creates a new file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens/creates a file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
|
||||
* SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given dir entry.
|
||||
* Optimization purposes, when traversing a file system with SPIFFS_readdir
|
||||
* a normal SPIFFS_open would need to traverse the filesystem again to find
|
||||
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
||||
* @param fs the file system struct
|
||||
* @param e the dir entry to the file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given page index.
|
||||
* Optimization purposes, opens a file by directly pointing to the page
|
||||
* index in the spi flash.
|
||||
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
||||
* is returned.
|
||||
* @param fs the file system struct
|
||||
* @param page_ix the page index
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Reads from given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf where to put read data
|
||||
* @param len how much to read
|
||||
* @returns number of bytes read, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Writes to given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf the data to write
|
||||
* @param len how much to write
|
||||
* @returns number of bytes written, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Moves the read/write file offset. Resulting offset is returned or negative if error.
|
||||
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param offs how much/where to move the offset
|
||||
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
||||
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
||||
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
||||
*/
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
||||
|
||||
/**
|
||||
* Removes a file by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
||||
|
||||
/**
|
||||
* Removes a file by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Gets file status by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Gets file status by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Flushes all pending write operations from cache for given file
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to flush
|
||||
*/
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to close
|
||||
*/
|
||||
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Renames a file
|
||||
* @param fs the file system struct
|
||||
* @param old path of file to rename
|
||||
* @param newPath new path of file
|
||||
*/
|
||||
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
|
||||
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
/**
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param path path to the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);
|
||||
|
||||
/**
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param fh file handle of the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns last error of last file operation.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_errno(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Clears last error.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_clearerr(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Opens a directory stream corresponding to the given name.
|
||||
* The stream is positioned at the first entry in the directory.
|
||||
* On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
||||
* to a flat file structure - no directories.
|
||||
* @param fs the file system struct
|
||||
* @param name the name of the directory
|
||||
* @param d pointer the directory stream to be populated
|
||||
*/
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Closes a directory stream
|
||||
* @param d the directory stream to close
|
||||
*/
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Reads a directory into given spifs_dirent struct.
|
||||
* @param d pointer to the directory stream
|
||||
* @param e the dirent struct to be populated
|
||||
* @returns null if error or end of stream, else given dirent is returned
|
||||
*/
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||
|
||||
/**
|
||||
* Runs a consistency check on given filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_check(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns number of total bytes available and number of used bytes.
|
||||
* This is an estimation, and depends on if there a many files with little
|
||||
* data or few files with much data.
|
||||
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||
* run. This indicates a power loss in midst of things. In worst case
|
||||
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param total total number of bytes in filesystem
|
||||
* @param used used number of bytes in filesystem
|
||||
*/
|
||||
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
||||
|
||||
/**
|
||||
* Formats the entire file system. All data will be lost.
|
||||
* The filesystem must not be mounted when calling this.
|
||||
*
|
||||
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
||||
* MUST be called prior to formatting in order to configure the filesystem.
|
||||
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
||||
* SPIFFS_format.
|
||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||
* SPIFFS_unmount first.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_format(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
u8_t SPIFFS_mounted(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Tries to find a block where most or all pages are deleted, and erase that
|
||||
* block if found. Does not care for wear levelling. Will not move pages
|
||||
* around.
|
||||
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||
* pages will be selected.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* Setting max_free_pages to anything larger than zero will eventually wear
|
||||
* flash more as a block containing free pages can be erased.
|
||||
*
|
||||
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||
* or other error.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param max_free_pages maximum number allowed free pages in block
|
||||
*/
|
||||
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
/**
|
||||
* Will try to make room for given amount of bytes in the filesystem by moving
|
||||
* pages and erasing blocks.
|
||||
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||
* there already is this amount (or more) of free space, SPIFFS_gc will
|
||||
* silently return. It is recommended to call SPIFFS_info before invoking
|
||||
* this method in order to determine what amount of bytes to give.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param size amount of bytes that should be freed
|
||||
*/
|
||||
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
||||
|
||||
/**
|
||||
* Check if EOF reached.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Get position in file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Registers a callback function that keeps track on operations on file
|
||||
* headers. Do note, that this callback is called from within internal spiffs
|
||||
* mechanisms. Any operations on the actual file system being callbacked from
|
||||
* in this callback will mess things up for sure - do not do this.
|
||||
* This can be used to track where files are and move around during garbage
|
||||
* collection, which in turn can be used to build location tables in ram.
|
||||
* Used in conjuction with SPIFFS_open_by_page this may improve performance
|
||||
* when opening a lot of files.
|
||||
* Must be invoked after mount.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param cb_func the callback on file operations
|
||||
*/
|
||||
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
/**
|
||||
* Maps the first level index lookup to a given memory map.
|
||||
* This will make reading big files faster, as the memory map will be used for
|
||||
* looking up data pages instead of searching for the indices on the physical
|
||||
* medium. When mapping, all affected indicies are found and the information is
|
||||
* copied to the array.
|
||||
* Whole file or only parts of it may be mapped. The index map will cover file
|
||||
* contents from argument offset until and including arguments (offset+len).
|
||||
* It is valid to map a longer range than the current file size. The map will
|
||||
* then be populated when the file grows.
|
||||
* On garbage collections and file data page movements, the map array will be
|
||||
* automatically updated. Do not tamper with the map array, as this contains
|
||||
* the references to the data pages. Modifying it from outside will corrupt any
|
||||
* future readings using this file descriptor.
|
||||
* The map will no longer be used when the file descriptor closed or the file
|
||||
* is unmapped.
|
||||
* This can be useful to get faster and more deterministic timing when reading
|
||||
* large files, or when seeking and reading a lot within a file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to map
|
||||
* @param map a spiffs_ix_map struct, describing the index map
|
||||
* @param offset absolute file offset where to start the index map
|
||||
* @param len length of the mapping in actual file bytes
|
||||
* @param map_buf the array buffer for the look up data - number of required
|
||||
* elements in the array can be derived from function
|
||||
* SPIFFS_bytes_to_ix_map_entries given the length
|
||||
*/
|
||||
s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
|
||||
u32_t offset, u32_t len, spiffs_page_ix *map_buf);
|
||||
|
||||
/**
|
||||
* Unmaps the index lookup from this filehandle. All future readings will
|
||||
* proceed as normal, requiring reading of the first level indices from
|
||||
* physical media.
|
||||
* The map and map buffer given in function SPIFFS_ix_map will no longer be
|
||||
* referenced by spiffs.
|
||||
* It is not strictly necessary to unmap a file before closing it, as closing
|
||||
* a file will automatically unmap it.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to unmap
|
||||
*/
|
||||
s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
|
||||
* all of the map buffer will repopulated.
|
||||
* @param fs the file system struct
|
||||
* @param fh the mapped file handle of the file to remap
|
||||
* @param offset new absolute file offset where to start the index map
|
||||
*/
|
||||
s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);
|
||||
|
||||
/**
|
||||
* Utility function to get number of spiffs_page_ix entries a map buffer must
|
||||
* contain on order to map given amount of file data in bytes.
|
||||
* See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
|
||||
* @param fs the file system struct
|
||||
* @param bytes number of file data bytes to map
|
||||
* @return needed number of elements in a spiffs_page_ix array needed to
|
||||
* map given amount of bytes in a file
|
||||
*/
|
||||
s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);
|
||||
|
||||
/**
|
||||
* Utility function to amount of file data bytes that can be mapped when
|
||||
* mapping a file with buffer having given number of spiffs_page_ix entries.
|
||||
* See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
|
||||
* @param fs the file system struct
|
||||
* @param map_page_ix_entries number of entries in a spiffs_page_ix array
|
||||
* @return amount of file data in bytes that can be mapped given a map
|
||||
* buffer having given amount of spiffs_page_ix entries
|
||||
*/
|
||||
s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
|
||||
|
||||
#endif // SPIFFS_IX_MAP
|
||||
|
||||
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
/**
|
||||
* Prints out a visualization of the filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_vis(spiffs *fs);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_BUFFER_HELP
|
||||
/**
|
||||
* Returns number of bytes needed for the filedescriptor buffer given
|
||||
* amount of file descriptors.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
/**
|
||||
* Returns number of bytes needed for the cache buffer given
|
||||
* amount of cache pages.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SPIFFS_H_ */
|
314
components/mkspiffs/src/spiffs/spiffs_cache.c
Normal file
314
components/mkspiffs/src/spiffs/spiffs_cache.c
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* spiffs_cache.c
|
||||
*
|
||||
* Created on: Jun 23, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
// returns cached page for give page index, or null if no such cached page
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
cp->pix == pix ) {
|
||||
SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix);
|
||||
cp->last_access = cache->last_access;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for "_SPIPRIpg"\n", pix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees cached page
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
||||
if (cache->cpage_use_map & (1<<ix)) {
|
||||
if (write_back &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||
}
|
||||
|
||||
cp->flags = 0;
|
||||
cache->cpage_use_map &= ~(1 << ix);
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" objid "_SPIPRIid"\n", ix, cp->obj_id);
|
||||
} else {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// removes the oldest accessed cached page
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
||||
// at least one free cpage
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
// all busy, scan thru all to find the cpage which has oldest access
|
||||
int i;
|
||||
int cand_ix = -1;
|
||||
u32_t oldest_val = 0;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
||||
(cp->flags & flag_mask) == flags) {
|
||||
oldest_val = cache->last_access - cp->last_access;
|
||||
cand_ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cand_ix >= 0) {
|
||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// allocates a new cached page and returns it, or null if all cache pages are busy
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if (cache->cpage_use_map == 0xffffffff) {
|
||||
// out of cache memory
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
cache->cpage_use_map |= (1<<i);
|
||||
cp->last_access = cache->last_access;
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i);
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
// out of cache entries
|
||||
return 0;
|
||||
}
|
||||
|
||||
// drops the cache page for give page index
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
if (cp) {
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
// reads from spi flash or the cache
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst) {
|
||||
(void)fh;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
||||
cache->last_access++;
|
||||
if (cp) {
|
||||
// we've already got one, you see
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_hits++;
|
||||
#endif
|
||||
cp->last_access = cache->last_access;
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
} else {
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
}
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_misses++;
|
||||
#endif
|
||||
// this operation will always free one cache page (unless all already free),
|
||||
// the result code stems from the write operation of the possibly freed cache page
|
||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
|
||||
cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp) {
|
||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs,
|
||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
} else {
|
||||
// this will never happen, last resort for sake of symmetry
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// writes to spi flash and/or the cache
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src) {
|
||||
(void)fh;
|
||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
|
||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
|
||||
// have a cache page
|
||||
// copy in data to cache page
|
||||
|
||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||
|
||||
cache->last_access++;
|
||||
cp->last_access = cache->last_access;
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||
// page is being updated, no write-cache, just pass thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
} else {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
} else {
|
||||
// no cache page, no write cache - just write thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
// returns the cache page that this fd refers, or null if no cache page
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
||||
// all cpages free, no cpage cannot be assigned to obj_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
||||
cp->obj_id == fd->obj_id) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
||||
// page if all cache is busy
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
// before this function is called, it is ensured that there is no already existing
|
||||
// cache page with same object id
|
||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp == 0) {
|
||||
// could not get cache page
|
||||
return 0;
|
||||
}
|
||||
|
||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
||||
cp->obj_id = fd->obj_id;
|
||||
fd->cache_page = cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
// unrefers all fds that this cache page refers to and releases the cache page
|
||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
||||
if (cp == 0) return;
|
||||
u32_t i;
|
||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||
for (i = 0; i < fs->fd_count; i++) {
|
||||
spiffs_fd *cur_fd = &fds[i];
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
||||
cur_fd->cache_page = 0;
|
||||
}
|
||||
}
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
|
||||
cp->obj_id = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// initializes the cache
|
||||
void spiffs_cache_init(spiffs *fs) {
|
||||
if (fs->cache == 0) return;
|
||||
u32_t sz = fs->cache_size;
|
||||
u32_t cache_mask = 0;
|
||||
int i;
|
||||
int cache_entries =
|
||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
if (cache_entries <= 0) return;
|
||||
|
||||
for (i = 0; i < cache_entries; i++) {
|
||||
cache_mask <<= 1;
|
||||
cache_mask |= 1;
|
||||
}
|
||||
|
||||
spiffs_cache cache;
|
||||
memset(&cache, 0, sizeof(spiffs_cache));
|
||||
cache.cpage_count = cache_entries;
|
||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
||||
|
||||
cache.cpage_use_map = 0xffffffff;
|
||||
cache.cpage_use_mask = cache_mask;
|
||||
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
||||
|
||||
spiffs_cache *c = spiffs_get_cache(fs);
|
||||
|
||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
|
||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||
for (i = 0; i < cache.cpage_count; i++) {
|
||||
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SPIFFS_CACHE
|
995
components/mkspiffs/src/spiffs/spiffs_check.c
Normal file
995
components/mkspiffs/src/spiffs/spiffs_check.c
Normal file
@ -0,0 +1,995 @@
|
||||
/*
|
||||
* spiffs_check.c
|
||||
*
|
||||
* Contains functionality for checking file system consistency
|
||||
* and mending problems.
|
||||
* Three levels of consistency checks are implemented:
|
||||
*
|
||||
* Look up consistency
|
||||
* Checks if indices in lookup pages are coherent with page headers
|
||||
* Object index consistency
|
||||
* Checks if there are any orphaned object indices (missing object index headers).
|
||||
* If an object index is found but not its header, the object index is deleted.
|
||||
* This is critical for the following page consistency check.
|
||||
* Page consistency
|
||||
* Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
|
||||
*
|
||||
*
|
||||
* Created on: Jul 7, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||
do { \
|
||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||
do { \
|
||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
//---------------------------------------
|
||||
// Look up consistency
|
||||
|
||||
// searches in the object indices and returns the referenced page index given
|
||||
// the object id and the data span index
|
||||
// destroys fs->lu_work
|
||||
static s32_t spiffs_object_get_data_page_index_reference(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix data_spix,
|
||||
spiffs_page_ix *pix,
|
||||
spiffs_page_ix *objix_pix) {
|
||||
s32_t res;
|
||||
|
||||
// calculate object index span index for given data page span index
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
|
||||
// find obj index for obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// load obj index entry
|
||||
u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);
|
||||
if (objix_spix == 0) {
|
||||
// get referenced page from object index header
|
||||
addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);
|
||||
} else {
|
||||
// get referenced page from object index
|
||||
addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);
|
||||
}
|
||||
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// copies page contents to a new page
|
||||
static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {
|
||||
s32_t res;
|
||||
res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0,
|
||||
SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_DATA_PAGE_SIZE(fs));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// rewrites the object index for given object id and replaces the
|
||||
// data page index to a new page index
|
||||
static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {
|
||||
s32_t res;
|
||||
spiffs_block_ix bix;
|
||||
int entry;
|
||||
spiffs_page_ix free_pix;
|
||||
obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
|
||||
|
||||
// find free entry
|
||||
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
|
||||
|
||||
// calculate object index span index for given data page span index
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
if (objix_spix == 0) {
|
||||
// calc index in index header
|
||||
entry = data_spix;
|
||||
} else {
|
||||
// calc entry in index
|
||||
entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
|
||||
|
||||
}
|
||||
// load index
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
||||
|
||||
// be ultra safe, double check header against provided data
|
||||
if (objix_p_hdr->obj_id != obj_id) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_OBJ_ID_MISM;
|
||||
}
|
||||
if (objix_p_hdr->span_ix != objix_spix) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_SPIX_MISM;
|
||||
}
|
||||
if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |
|
||||
SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=
|
||||
(SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_FLAGS_BAD;
|
||||
}
|
||||
|
||||
// rewrite in mem
|
||||
if (objix_spix == 0) {
|
||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
|
||||
} else {
|
||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
|
||||
}
|
||||
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),
|
||||
sizeof(spiffs_obj_id),
|
||||
(u8_t *)&obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_page_delete(fs, objix_pix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// deletes an object just by marking object index header as deleted
|
||||
static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
s32_t res;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
|
||||
sizeof(u8_t),
|
||||
(u8_t *)&flags);
|
||||
return res;
|
||||
}
|
||||
|
||||
// validates the given look up entry
|
||||
static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
|
||||
spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
|
||||
(void)cur_block;
|
||||
(void)cur_entry;
|
||||
u8_t delete_page = 0;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_ix objix_pix;
|
||||
spiffs_page_ix ref_pix;
|
||||
// check validity, take actions
|
||||
if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
|
||||
((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
|
||||
// look up entry deleted / free but used in page header
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix);
|
||||
*reload_lu = 1;
|
||||
delete_page = 1;
|
||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
||||
// header says data page
|
||||
// data page can be removed if not referenced by some object index
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (ref_pix == cur_pix) {
|
||||
// data page referenced by object index but deleted in lu
|
||||
// copy page to new place and re-write the object index to new place
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix);
|
||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
res = spiffs_page_delete(fs, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// header says index page
|
||||
// index page can be removed if other index with same obj_id and spanix is found
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no such index page found, check for a data page amongst page headers
|
||||
// lu cannot be trusted
|
||||
res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
|
||||
if (res == SPIFFS_OK) { // ignore other errors
|
||||
// got a data page also, assume lu corruption only, rewrite to new page
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
}
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
|
||||
// look up entry used
|
||||
if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id);
|
||||
delete_page = 1;
|
||||
if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
|
||||
(p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
|
||||
(p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
|
||||
// page deleted or not finalized, just remove it
|
||||
} else {
|
||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
||||
// if data page, check for reference to this page
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// if found, rewrite page with object id, update index, and delete current
|
||||
if (ref_pix == cur_pix) {
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
res = spiffs_page_delete(fs, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||
*reload_lu = 1;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// else if index, check for other pages with both obj_id's and spanix
|
||||
spiffs_page_ix objix_pix_lu, objix_pix_ph;
|
||||
// see if other object index page exists for lookup obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_lu = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other object index exists for page header obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_ph = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// if both obj_id's found, just delete current
|
||||
if (objix_pix_ph == 0 || objix_pix_lu == 0) {
|
||||
// otherwise try finding first corresponding data pages
|
||||
spiffs_page_ix data_pix_lu, data_pix_ph;
|
||||
// see if other data page exists for look up obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_lu = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other data page exists for page header obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_ph = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_page_header new_ph;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
spiffs_page_ix new_pix;
|
||||
if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
|
||||
(objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
|
||||
// got a data page for page header obj id
|
||||
// rewrite as obj_id_ph
|
||||
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
|
||||
(objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
|
||||
// got a data page for look up obj id
|
||||
// rewrite as obj_id_lu
|
||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
} else {
|
||||
// cannot safely do anything
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
|
||||
((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
|
||||
SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix);
|
||||
spiffs_page_ix data_pix, objix_pix_d;
|
||||
// see if other data page exists for given obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other object index exists for given obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_d = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
delete_page = 1;
|
||||
// if other data page exists and object index exists, just delete page
|
||||
if (data_pix && objix_pix_d) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n");
|
||||
} else
|
||||
// if only data page exists, make this page index
|
||||
if (data_pix && objix_pix_d == 0) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
|
||||
spiffs_page_header new_ph;
|
||||
spiffs_page_ix new_pix;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
|
||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else
|
||||
// if only index exists, make data page
|
||||
if (data_pix == 0 && objix_pix_d) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
|
||||
spiffs_page_header new_ph;
|
||||
spiffs_page_ix new_pix;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// if nothing exists, we cannot safely make a decision - delete
|
||||
}
|
||||
}
|
||||
else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix);
|
||||
delete_page = 1;
|
||||
} else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix);
|
||||
// page can be removed if not referenced by object index
|
||||
*reload_lu = 1;
|
||||
res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
delete_page = 1;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (ref_pix != cur_pix) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n");
|
||||
delete_page = 1;
|
||||
} else {
|
||||
// page referenced by object index but not final
|
||||
// just finalize
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
|
||||
sizeof(u8_t), (u8_t*)&flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_page) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
|
||||
const void *user_const_p, void *user_var_p) {
|
||||
(void)user_const_p;
|
||||
(void)user_var_p;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
|
||||
(cur_block * 256)/fs->block_count, 0);
|
||||
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
int reload_lu = 0;
|
||||
|
||||
res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Scans all object look up. For each entry, corresponding page header is checked for validity.
|
||||
// If an object index header page is found, this is also checked
|
||||
s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
|
||||
(void)check_all_objects;
|
||||
s32_t res = SPIFFS_OK;
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
|
||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
|
||||
|
||||
if (res == SPIFFS_VIS_END) {
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Page consistency
|
||||
|
||||
// Scans all pages (except lu pages), reserves 4 bits in working memory for each page
|
||||
// bit 0: 0 == FREE|DELETED, 1 == USED
|
||||
// bit 1: 0 == UNREFERENCED, 1 == REFERENCED
|
||||
// bit 2: 0 == NOT_INDEX, 1 == INDEX
|
||||
// bit 3: unused
|
||||
// A consistent file system will have only pages being
|
||||
// * x000 free, unreferenced, not index
|
||||
// * x011 used, referenced only once, not index
|
||||
// * x101 used, unreferenced, index
|
||||
// The working memory might not fit all pages so several scans might be needed
|
||||
static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
||||
const u32_t bits = 4;
|
||||
const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
|
||||
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_ix pix_offset = 0;
|
||||
|
||||
// for each range of pages fitting into work memory
|
||||
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
|
||||
// set this flag to abort all checks and rescan the page range
|
||||
u8_t restart = 0;
|
||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
spiffs_block_ix cur_block = 0;
|
||||
// build consistency bitmap for id range traversing all blocks
|
||||
while (!restart && cur_block < fs->block_count) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
|
||||
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
|
||||
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
|
||||
0);
|
||||
// traverse each page except for lookup pages
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
||||
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
||||
//if ((cur_pix & 0xff) == 0)
|
||||
// SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
|
||||
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
|
||||
|
||||
// read header
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
|
||||
const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);
|
||||
const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;
|
||||
|
||||
if (within_range &&
|
||||
(p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
|
||||
// used
|
||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));
|
||||
}
|
||||
if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
|
||||
(p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
|
||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
|
||||
// found non-deleted index
|
||||
if (within_range) {
|
||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));
|
||||
}
|
||||
|
||||
// load non-deleted index
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// traverse index for referenced pages
|
||||
spiffs_page_ix *object_page_index;
|
||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
||||
|
||||
int entries;
|
||||
int i;
|
||||
spiffs_span_ix data_spix_offset;
|
||||
if (p_hdr.span_ix == 0) {
|
||||
// object header page index
|
||||
entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
|
||||
data_spix_offset = 0;
|
||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
|
||||
} else {
|
||||
// object page index
|
||||
entries = SPIFFS_OBJ_IX_LEN(fs);
|
||||
data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
|
||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
|
||||
}
|
||||
|
||||
// for all entries in index
|
||||
for (i = 0; !restart && i < entries; i++) {
|
||||
spiffs_page_ix rpix = object_page_index[i];
|
||||
u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
|
||||
|
||||
if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))
|
||||
|| (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
|
||||
|
||||
// bad reference
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n",
|
||||
rpix, cur_pix);
|
||||
// check for data page elsewhere
|
||||
spiffs_page_ix data_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, 0, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (data_pix == 0) {
|
||||
// if not, allocate free page
|
||||
spiffs_page_header new_ph;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = data_spix_offset + i;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix);
|
||||
}
|
||||
// remap index
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix);
|
||||
res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, data_pix, cur_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
|
||||
// delete file
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
|
||||
} else if (rpix_within_range) {
|
||||
|
||||
// valid reference
|
||||
// read referenced page header
|
||||
spiffs_page_header rp_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// cross reference page header check
|
||||
if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
|
||||
rp_hdr.span_ix != data_spix_offset + i ||
|
||||
(rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
|
||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n",
|
||||
rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
|
||||
rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
|
||||
// try finding correct page
|
||||
spiffs_page_ix data_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, rpix, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (data_pix == 0) {
|
||||
// not found, this index is badly borked
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
break;
|
||||
} else {
|
||||
// found it, so rewrite index
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n",
|
||||
data_pix, cur_pix, p_hdr.obj_id);
|
||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// mark rpix as referenced
|
||||
const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);
|
||||
const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;
|
||||
if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n",
|
||||
rpix, cur_pix);
|
||||
// Here, we should have fixed all broken references - getting this means there
|
||||
// must be multiple files with same object id. Only solution is to delete
|
||||
// the object which is referring to this page
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n",
|
||||
p_hdr.obj_id, cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// extra precaution, delete this page also
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
}
|
||||
fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));
|
||||
}
|
||||
}
|
||||
} // for all index entries
|
||||
} // found index
|
||||
|
||||
// next page
|
||||
cur_pix++;
|
||||
}
|
||||
// next block
|
||||
cur_block++;
|
||||
}
|
||||
// check consistency bitmap
|
||||
if (!restart) {
|
||||
spiffs_page_ix objix_pix;
|
||||
spiffs_page_ix rpix;
|
||||
|
||||
u32_t byte_ix;
|
||||
u8_t bit_ix;
|
||||
for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
|
||||
for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {
|
||||
u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
|
||||
spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;
|
||||
|
||||
// 000 ok - free, unreferenced, not index
|
||||
|
||||
if (bitmask == 0x1) {
|
||||
|
||||
// 001
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix);
|
||||
|
||||
u8_t rewrite_ix_to_this = 0;
|
||||
u8_t delete_page = 0;
|
||||
// check corresponding object index entry
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
|
||||
&rpix, &objix_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
|
||||
// pointing to a bad page altogether, rewrite index to this
|
||||
rewrite_ix_to_this = 1;
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix);
|
||||
} else {
|
||||
// pointing to something else, check what
|
||||
spiffs_page_header rp_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
|
||||
((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
|
||||
(SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
|
||||
// pointing to something else valid, just delete this page then
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix);
|
||||
delete_page = 1;
|
||||
} else {
|
||||
// pointing to something weird, update index to point to this page instead
|
||||
if (rpix != cur_pix) {
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix,
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
|
||||
cur_pix);
|
||||
rewrite_ix_to_this = 1;
|
||||
} else {
|
||||
// should not happen, destined for fubar
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix);
|
||||
delete_page = 1;
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
|
||||
if (rewrite_ix_to_this) {
|
||||
// if pointing to invalid page, redirect index to this page
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n",
|
||||
p_hdr.obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
continue;
|
||||
} else if (delete_page) {
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
if (bitmask == 0x2) {
|
||||
|
||||
// 010
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
|
||||
// 011 ok - busy, referenced, not index
|
||||
|
||||
if (bitmask == 0x4) {
|
||||
|
||||
// 100
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix);
|
||||
|
||||
// this should never happen, major fubar
|
||||
}
|
||||
|
||||
// 101 ok - busy, unreferenced, index
|
||||
|
||||
if (bitmask == 0x6) {
|
||||
|
||||
// 110
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
if (bitmask == 0x7) {
|
||||
|
||||
// 111
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart);
|
||||
// next page range
|
||||
if (!restart) {
|
||||
pix_offset += pages_per_scan;
|
||||
}
|
||||
} // while page range not reached end
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks consistency amongst all pages and fixes irregularities
|
||||
s32_t spiffs_page_consistency_check(spiffs *fs) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
s32_t res = spiffs_page_consistency_check_i(fs);
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Object index consistency
|
||||
|
||||
// searches for given object id in temporary object id index,
|
||||
// returns the index or -1
|
||||
static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
|
||||
u32_t i;
|
||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||
obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
|
||||
if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
|
||||
int cur_entry, const void *user_const_p, void *user_var_p) {
|
||||
(void)user_const_p;
|
||||
s32_t res_c = SPIFFS_VIS_COUNTINUE;
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t *log_ix = (u32_t*)user_var_p;
|
||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
|
||||
(cur_block * 256)/fs->block_count, 0);
|
||||
|
||||
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
if (p_hdr.span_ix == 0 &&
|
||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
||||
(SPIFFS_PH_FLAG_DELET)) {
|
||||
SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n",
|
||||
cur_pix, obj_id, p_hdr.span_ix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
return res_c;
|
||||
}
|
||||
|
||||
if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
|
||||
return res_c;
|
||||
}
|
||||
|
||||
if (p_hdr.span_ix == 0) {
|
||||
// objix header page, register objid as reachable
|
||||
int r = spiffs_object_index_search(fs, obj_id);
|
||||
if (r == -1) {
|
||||
// not registered, do it
|
||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
(*log_ix)++;
|
||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
||||
*log_ix = 0;
|
||||
}
|
||||
}
|
||||
} else { // span index
|
||||
// objix page, see if header can be found
|
||||
int r = spiffs_object_index_search(fs, obj_id);
|
||||
u8_t delete = 0;
|
||||
if (r == -1) {
|
||||
// not in temporary index, try finding it
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
|
||||
res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
|
||||
if (res == SPIFFS_OK) {
|
||||
// found, register as reachable
|
||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// not found, register as unreachable
|
||||
delete = 1;
|
||||
obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
(*log_ix)++;
|
||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
||||
*log_ix = 0;
|
||||
}
|
||||
} else {
|
||||
// in temporary index, check reachable flag
|
||||
if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// registered as unreachable
|
||||
delete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n",
|
||||
cur_pix, obj_id, p_hdr.span_ix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
} // span index
|
||||
} // valid object index id
|
||||
|
||||
return res_c;
|
||||
}
|
||||
|
||||
// Removes orphaned and partially deleted index pages.
|
||||
// Scans for index pages. When an index page is found, corresponding index header is searched for.
|
||||
// If no such page exists, the index page cannot be reached as no index header exists and must be
|
||||
// deleted.
|
||||
s32_t spiffs_object_index_consistency_check(spiffs *fs) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
// impl note:
|
||||
// fs->work is used for a temporary object index memory, listing found object ids and
|
||||
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
|
||||
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
|
||||
// a reachable/unreachable object id.
|
||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
u32_t obj_id_log_ix = 0;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
|
||||
0, 0);
|
||||
if (res == SPIFFS_VIS_END) {
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
361
components/mkspiffs/src/spiffs/spiffs_config.h
Normal file
361
components/mkspiffs/src/spiffs/spiffs_config.h
Normal file
@ -0,0 +1,361 @@
|
||||
/*
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
// ----------- 8< ------------
|
||||
// Following includes are for the linux test build of spiffs
|
||||
// These may/should/must be removed/altered/replaced in your target
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
// ----------- >8 ------------
|
||||
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned char u8_t;
|
||||
|
||||
// compile time switches
|
||||
|
||||
// Set generic spiffs debug output call.
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for garbage collecting.
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for caching.
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for system consistency checks.
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
// Defines spiffs debug print formatters
|
||||
// some general signed number
|
||||
#ifndef _SPIPRIi
|
||||
#define _SPIPRIi "%d"
|
||||
#endif
|
||||
// address
|
||||
#ifndef _SPIPRIad
|
||||
#define _SPIPRIad "%08x"
|
||||
#endif
|
||||
// block
|
||||
#ifndef _SPIPRIbl
|
||||
#define _SPIPRIbl "%04x"
|
||||
#endif
|
||||
// page
|
||||
#ifndef _SPIPRIpg
|
||||
#define _SPIPRIpg "%04x"
|
||||
#endif
|
||||
// span index
|
||||
#ifndef _SPIPRIsp
|
||||
#define _SPIPRIsp "%04x"
|
||||
#endif
|
||||
// file descriptor
|
||||
#ifndef _SPIPRIfd
|
||||
#define _SPIPRIfd "%d"
|
||||
#endif
|
||||
// file object id
|
||||
#ifndef _SPIPRIid
|
||||
#define _SPIPRIid "%04x"
|
||||
#endif
|
||||
// file flags
|
||||
#ifndef _SPIPRIfl
|
||||
#define _SPIPRIfl "%02x"
|
||||
#endif
|
||||
|
||||
// Enable/disable API functions to determine exact number of bytes
|
||||
// for filedescriptor and cache buffers. Once decided for a configuration,
|
||||
// this can be disabled to reduce flash.
|
||||
#ifndef SPIFFS_BUFFER_HELP
|
||||
#define SPIFFS_BUFFER_HELP 0
|
||||
#endif
|
||||
|
||||
// Enables/disable memory read caching of nucleus file system operations.
|
||||
// If enabled, memory area must be provided for cache in SPIFFS_mount.
|
||||
#ifndef SPIFFS_CACHE
|
||||
#define SPIFFS_CACHE 1
|
||||
#endif
|
||||
#if SPIFFS_CACHE
|
||||
// Enables memory write caching for file descriptors in hydrogen
|
||||
#ifndef SPIFFS_CACHE_WR
|
||||
#define SPIFFS_CACHE_WR 1
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on caching. Debug/test purpose only.
|
||||
#ifndef SPIFFS_CACHE_STATS
|
||||
#define SPIFFS_CACHE_STATS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Always check header of each accessed page to ensure consistent state.
|
||||
// If enabled it will increase number of reads, will increase flash.
|
||||
#ifndef SPIFFS_PAGE_CHECK
|
||||
#define SPIFFS_PAGE_CHECK 1
|
||||
#endif
|
||||
|
||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
||||
#ifndef SPIFFS_GC_MAX_RUNS
|
||||
#define SPIFFS_GC_MAX_RUNS 5
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
||||
#ifndef SPIFFS_GC_STATS
|
||||
#define SPIFFS_GC_STATS 0
|
||||
#endif
|
||||
|
||||
// Garbage collecting examines all pages in a block which and sums up
|
||||
// to a block score. Deleted pages normally gives positive score and
|
||||
// used pages normally gives a negative score (as these must be moved).
|
||||
// To have a fair wear-leveling, the erase age is also included in score,
|
||||
// whose factor normally is the most positive.
|
||||
// The larger the score, the more likely it is that the block will
|
||||
// picked for garbage collection.
|
||||
|
||||
// Garbage collecting heuristics - weight used for deleted pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_DELET
|
||||
#define SPIFFS_GC_HEUR_W_DELET (5)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for used pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_USED
|
||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for time between
|
||||
// last erased and erase of this block.
|
||||
#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE
|
||||
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
|
||||
#endif
|
||||
|
||||
// Object name maximum length. Note that this length include the
|
||||
// zero-termination character, meaning maximum string of characters
|
||||
// can at most be SPIFFS_OBJ_NAME_LEN - 1.
|
||||
#ifndef SPIFFS_OBJ_NAME_LEN
|
||||
#define SPIFFS_OBJ_NAME_LEN (64)
|
||||
#endif
|
||||
|
||||
// Maximum length of the metadata associated with an object.
|
||||
// Setting to non-zero value enables metadata-related API but also
|
||||
// changes the on-disk format, so the change is not backward-compatible.
|
||||
//
|
||||
// Do note: the meta length must never exceed
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)
|
||||
//
|
||||
// This is derived from following:
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
||||
// spiffs_object_ix_header fields + at least some LUT entries)
|
||||
#ifndef SPIFFS_OBJ_META_LEN
|
||||
#define SPIFFS_OBJ_META_LEN (64)
|
||||
#endif
|
||||
|
||||
// Size of buffer allocated on stack used when copying data.
|
||||
// Lower value generates more read/writes. No meaning having it bigger
|
||||
// than logical page size.
|
||||
#ifndef SPIFFS_COPY_BUFFER_STACK
|
||||
#define SPIFFS_COPY_BUFFER_STACK (256)
|
||||
#endif
|
||||
|
||||
// Enable this to have an identifiable spiffs filesystem. This will look for
|
||||
// a magic in all sectors to determine if this is a valid spiffs system or
|
||||
// not on mount point. If not, SPIFFS_format must be called prior to mounting
|
||||
// again.
|
||||
#ifndef SPIFFS_USE_MAGIC
|
||||
#define SPIFFS_USE_MAGIC (1)
|
||||
#endif
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
|
||||
// enabled, the magic will also be dependent on the length of the filesystem.
|
||||
// For example, a filesystem configured and formatted for 4 megabytes will not
|
||||
// be accepted for mounting with a configuration defining the filesystem as 2
|
||||
// megabytes.
|
||||
#ifndef SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_USE_MAGIC_LENGTH (1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
|
||||
// These should be defined on a multithreaded system
|
||||
|
||||
// define this to enter a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
// define this to exit a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// Enable if only one spiffs instance with constant configuration will exist
|
||||
// on the target. This will reduce calculations, flash and memory accesses.
|
||||
// Parts of configuration must be defined below instead of at time of mount.
|
||||
#ifndef SPIFFS_SINGLETON
|
||||
#define SPIFFS_SINGLETON 0
|
||||
#endif
|
||||
|
||||
#if SPIFFS_SINGLETON
|
||||
// Instead of giving parameters in config struct, singleton build must
|
||||
// give parameters in defines below.
|
||||
#ifndef SPIFFS_CFG_PHYS_SZ
|
||||
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ADDR
|
||||
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_PAGE_SZ
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_BLOCK_SZ
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable this if your target needs aligned data for index tables
|
||||
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
|
||||
#endif
|
||||
|
||||
// Enable this if you want the HAL callbacks to be called with the spiffs struct
|
||||
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define SPIFFS_HAL_CALLBACK_EXTRA 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want to add an integer offset to all file handles
|
||||
// (spiffs_file). This is useful if running multiple instances of spiffs on
|
||||
// same target, in order to recognise to what spiffs instance a file handle
|
||||
// belongs.
|
||||
// NB: This adds config field fh_ix_offset in the configuration struct when
|
||||
// mounting, which must be defined.
|
||||
#ifndef SPIFFS_FILEHDL_OFFSET
|
||||
#define SPIFFS_FILEHDL_OFFSET 0
|
||||
#endif
|
||||
|
||||
// Enable this to compile a read only version of spiffs.
|
||||
// This will reduce binary size of spiffs. All code comprising modification
|
||||
// of the file system will not be compiled. Some config will be ignored.
|
||||
// HAL functions for erasing and writing to spi-flash may be null. Cache
|
||||
// can be disabled for even further binary size reduction (and ram savings).
|
||||
// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
|
||||
// If the file system cannot be mounted due to aborted erase operation and
|
||||
// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
|
||||
// returned.
|
||||
// Might be useful for e.g. bootloaders and such.
|
||||
#ifndef SPIFFS_READ_ONLY
|
||||
#define SPIFFS_READ_ONLY 0
|
||||
#endif
|
||||
|
||||
// Enable this to add a temporal file cache using the fd buffer.
|
||||
// The effects of the cache is that SPIFFS_open will find the file faster in
|
||||
// certain cases. It will make it a lot easier for spiffs to find files
|
||||
// opened frequently, reducing number of readings from the spi flash for
|
||||
// finding those files.
|
||||
// This will grow each fd by 6 bytes. If your files are opened in patterns
|
||||
// with a degree of temporal locality, the system is optimized.
|
||||
// Examples can be letting spiffs serve web content, where one file is the css.
|
||||
// The css is accessed for each html file that is opened, meaning it is
|
||||
// accessed almost every second time a file is opened. Another example could be
|
||||
// a log file that is often opened, written, and closed.
|
||||
// The size of the cache is number of given file descriptors, as it piggybacks
|
||||
// on the fd update mechanism. The cache lives in the closed file descriptors.
|
||||
// When closed, the fd know the whereabouts of the file. Instead of forgetting
|
||||
// this, the temporal cache will keep handling updates to that file even if the
|
||||
// fd is closed. If the file is opened again, the location of the file is found
|
||||
// directly. If all available descriptors become opened, all cache memory is
|
||||
// lost.
|
||||
#ifndef SPIFFS_TEMPORAL_FD_CACHE
|
||||
#define SPIFFS_TEMPORAL_FD_CACHE 1
|
||||
#endif
|
||||
|
||||
// Temporal file cache hit score. Each time a file is opened, all cached files
|
||||
// will lose one point. If the opened file is found in cache, that entry will
|
||||
// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this
|
||||
// value for the specific access patterns of the application. However, it must
|
||||
// be between 1 (no gain for hitting a cached entry often) and 255.
|
||||
#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE
|
||||
#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 8
|
||||
#endif
|
||||
|
||||
// Enable to be able to map object indices to memory.
|
||||
// This allows for faster and more deterministic reading if cases of reading
|
||||
// large files and when changing file offset by seeking around a lot.
|
||||
// When mapping a file's index, the file system will be scanned for index pages
|
||||
// and the info will be put in memory provided by user. When reading, the
|
||||
// memory map can be looked up instead of searching for index pages on the
|
||||
// medium. This way, user can trade memory against performance.
|
||||
// Whole, parts of, or future parts not being written yet can be mapped. The
|
||||
// memory array will be owned by spiffs and updated accordingly during garbage
|
||||
// collecting or when modifying the indices. The latter is invoked by when the
|
||||
// file is modified in some way. The index buffer is tied to the file
|
||||
// descriptor.
|
||||
#ifndef SPIFFS_IX_MAP
|
||||
#define SPIFFS_IX_MAP 1
|
||||
#endif
|
||||
|
||||
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
|
||||
// in the api. This function will visualize all filesystem using given printf
|
||||
// function.
|
||||
#ifndef SPIFFS_TEST_VISUALISATION
|
||||
#define SPIFFS_TEST_VISUALISATION 0
|
||||
#endif
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
#ifndef spiffs_printf
|
||||
#define spiffs_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
// spiffs_printf argument for a free page
|
||||
#ifndef SPIFFS_TEST_VIS_FREE_STR
|
||||
#define SPIFFS_TEST_VIS_FREE_STR "_"
|
||||
#endif
|
||||
// spiffs_printf argument for a deleted page
|
||||
#ifndef SPIFFS_TEST_VIS_DELE_STR
|
||||
#define SPIFFS_TEST_VIS_DELE_STR "/"
|
||||
#endif
|
||||
// spiffs_printf argument for an index page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_INDX_STR
|
||||
#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
|
||||
#endif
|
||||
// spiffs_printf argument for a data page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_DATA_STR
|
||||
#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Types depending on configuration such as the amount of flash bytes
|
||||
// given to spiffs file system in total (spiffs_file_system_size),
|
||||
// the logical block size (log_block_size), and the logical page size
|
||||
// (log_page_size)
|
||||
|
||||
// Block index type. Make sure the size of this type can hold
|
||||
// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
|
||||
typedef u16_t spiffs_block_ix;
|
||||
// Page index type. Make sure the size of this type can hold
|
||||
// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
|
||||
typedef u16_t spiffs_page_ix;
|
||||
// Object id type - most significant bit is reserved for index flag. Make sure the
|
||||
// size of this type can hold the highest object id on a full system,
|
||||
// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
|
||||
typedef u16_t spiffs_obj_id;
|
||||
// Object span index type. Make sure the size of this type can
|
||||
// hold the largest possible span index on the system -
|
||||
// i.e. (spiffs_file_system_size / log_page_size) - 1
|
||||
typedef u16_t spiffs_span_ix;
|
||||
|
||||
#endif /* SPIFFS_CONFIG_H_ */
|
606
components/mkspiffs/src/spiffs/spiffs_gc.c
Normal file
606
components/mkspiffs/src/spiffs/spiffs_gc.c
Normal file
@ -0,0 +1,606 @@
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
// Erases a logical block and updates the erase counter.
|
||||
// If cache is enabled, all pages that might be cached in this block
|
||||
// is dropped.
|
||||
static s32_t spiffs_gc_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res;
|
||||
|
||||
SPIFFS_GC_DBG("gc: erase block "_SPIPRIbl"\n", bix);
|
||||
res = spiffs_erase_block(fs, bix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
{
|
||||
u32_t i;
|
||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
|
||||
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
// Searches for blocks where all entries are deleted - if one is found,
|
||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
||||
// that no updates are needed on existing objects on pages that are erased.
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_quick: running\n");
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// find fully deleted blocks
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t free_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// kill scan, go for next block
|
||||
free_pages_in_block++;
|
||||
if (free_pages_in_block > max_free_pages) {
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// kill scan, go for next block
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
if (res == SPIFFS_OK &&
|
||||
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
||||
free_pages_in_block <= max_free_pages) {
|
||||
// found a fully deleted block
|
||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
||||
res = spiffs_gc_erase_block(fs, cur_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks if garbage collecting is necessary. If so a candidate block is found,
|
||||
// cleansed and erased
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len) {
|
||||
s32_t res;
|
||||
s32_t free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
int tries = 0;
|
||||
|
||||
if (fs->free_blocks > 3 &&
|
||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
||||
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
||||
// SPIFFS_GC_DBG("gc: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
// return SPIFFS_ERR_FULL;
|
||||
// }
|
||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
||||
SPIFFS_GC_DBG("gc_check: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
return SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
do {
|
||||
SPIFFS_GC_DBG("\ngc_check #"_SPIPRIi": run gc free_blocks:"_SPIPRIi" pfree:"_SPIPRIi" pallo:"_SPIPRIi" pdele:"_SPIPRIi" ["_SPIPRIi"] len:"_SPIPRIi" of "_SPIPRIi"\n",
|
||||
tries,
|
||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
||||
len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
spiffs_block_ix *cands;
|
||||
int count;
|
||||
spiffs_block_ix cand;
|
||||
s32_t prev_free_pages = free_pages;
|
||||
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
|
||||
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (count == 0) {
|
||||
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
|
||||
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
|
||||
}
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
cand = cands[0];
|
||||
fs->cleaning = 1;
|
||||
//SPIFFS_GC_DBG("gcing: cleaning block "_SPIPRIi"\n", cand);
|
||||
res = spiffs_gc_clean(fs, cand);
|
||||
fs->cleaning = 0;
|
||||
if (res < 0) {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res);
|
||||
} else {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_page_stats(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_block(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
|
||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
|
||||
// abort early to reduce wear, at least tried once
|
||||
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
||||
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
res = SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
SPIFFS_GC_DBG("gc_check: finished, "_SPIPRIi" dirty, blocks "_SPIPRIi" free, "_SPIPRIi" pages free, "_SPIPRIi" tries, res "_SPIPRIi"\n",
|
||||
fs->stats_p_allocated + fs->stats_p_deleted,
|
||||
fs->free_blocks, free_pages, tries, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Updates page statistics for a block that is about to be erased
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
int obj_lookup_page = 0;
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
u32_t dele = 0;
|
||||
u32_t allo = 0;
|
||||
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
dele++;
|
||||
} else {
|
||||
allo++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
SPIFFS_GC_DBG("gc_check: wipe pallo:"_SPIPRIi" pdele:"_SPIPRIi"\n", allo, dele);
|
||||
fs->stats_p_allocated -= allo;
|
||||
fs->stats_p_deleted -= dele;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Finds block candidates to erase
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidates,
|
||||
int *candidate_count,
|
||||
char fs_crammed) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
|
||||
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
||||
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
||||
*candidate_count = 0;
|
||||
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
// divide up work area into block indices and scores
|
||||
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
||||
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
||||
|
||||
// align cand_scores on s32_t boundary
|
||||
cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));
|
||||
|
||||
*block_candidates = cand_blocks;
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t used_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// when a free entry is encountered, scan logic ensures that all following entries are free also
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else {
|
||||
used_pages_in_block++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
// calculate score and insert into candidate table
|
||||
// stoneage sort, but probably not so many blocks
|
||||
if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {
|
||||
// read erase count
|
||||
spiffs_obj_id erase_count;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
|
||||
SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),
|
||||
sizeof(spiffs_obj_id), (u8_t *)&erase_count);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_obj_id erase_age;
|
||||
if (fs->max_erase_count > erase_count) {
|
||||
erase_age = fs->max_erase_count - erase_count;
|
||||
} else {
|
||||
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
|
||||
}
|
||||
|
||||
s32_t score =
|
||||
deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
|
||||
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
||||
int cand_ix = 0;
|
||||
SPIFFS_GC_DBG("gc_check: bix:"_SPIPRIbl" del:"_SPIPRIi" use:"_SPIPRIi" score:"_SPIPRIi"\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
||||
while (cand_ix < max_candidates) {
|
||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
} else if (cand_scores[cand_ix] < score) {
|
||||
int reorder_cand_ix = max_candidates - 2;
|
||||
while (reorder_cand_ix >= cand_ix) {
|
||||
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
|
||||
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
|
||||
reorder_cand_ix--;
|
||||
}
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
}
|
||||
cand_ix++;
|
||||
}
|
||||
(*candidate_count)++;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FIND_OBJ_DATA,
|
||||
MOVE_OBJ_DATA,
|
||||
MOVE_OBJ_IX,
|
||||
FINISHED
|
||||
} spiffs_gc_clean_state;
|
||||
|
||||
typedef struct {
|
||||
spiffs_gc_clean_state state;
|
||||
spiffs_obj_id cur_obj_id;
|
||||
spiffs_span_ix cur_objix_spix;
|
||||
spiffs_page_ix cur_objix_pix;
|
||||
spiffs_page_ix cur_data_pix;
|
||||
int stored_scan_entry_index;
|
||||
u8_t obj_id_found;
|
||||
} spiffs_gc;
|
||||
|
||||
// Empties given block by moving all data into free pages of another block
|
||||
// Strategy:
|
||||
// loop:
|
||||
// scan object lookup for object data pages
|
||||
// for first found id, check spix and load corresponding object index page to memory
|
||||
// push object scan lookup entry index
|
||||
// rescan object lookup, find data pages with same id and referenced by same object index
|
||||
// move data page, update object index in memory
|
||||
// when reached end of lookup, store updated object index
|
||||
// pop object scan lookup entry index
|
||||
// repeat loop until end of object lookup
|
||||
// scan object lookup again for remaining object index pages, move to new page in other block
|
||||
//
|
||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
// this is the global localizer being pushed and popped
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
spiffs_gc gc; // our stack frame/state
|
||||
spiffs_page_ix cur_pix = 0;
|
||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_clean: cleaning block "_SPIPRIbl"\n", bix);
|
||||
|
||||
memset(&gc, 0, sizeof(spiffs_gc));
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
|
||||
if (fs->free_cursor_block_ix == bix) {
|
||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
||||
fs->free_cursor_obj_lu_entry = 0;
|
||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block "_SPIPRIbl"\n", fs->free_cursor_block_ix);
|
||||
}
|
||||
|
||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
||||
SPIFFS_GC_DBG("gc_clean: state = "_SPIPRIi" entry:"_SPIPRIi"\n", gc.state, cur_entry);
|
||||
gc.obj_id_found = 0; // reset (to no found data page)
|
||||
|
||||
// scan through lookup pages
|
||||
int obj_lookup_page = cur_entry / entries_per_page;
|
||||
u8_t scan = 1;
|
||||
// check each object lookup page
|
||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each object lookup entry
|
||||
while (scan && res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
|
||||
|
||||
// act upon object id depending on gc state
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
// find a data page
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
||||
// found a data page, stop scanning and handle in switch case below
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:"_SPIPRIi" - found obj id "_SPIPRIid"\n", gc.state, obj_id);
|
||||
gc.obj_id_found = 1;
|
||||
gc.cur_obj_id = obj_id;
|
||||
gc.cur_data_pix = cur_pix;
|
||||
scan = 0;
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA:
|
||||
// evacuate found data pages for corresponding object index we have in memory,
|
||||
// update memory representation
|
||||
if (obj_id == gc.cur_obj_id) {
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page "_SPIPRIid":"_SPIPRIsp" @ "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
|
||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
|
||||
} else {
|
||||
spiffs_page_ix new_data_pix;
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
new_data_pix = SPIFFS_OBJ_ID_FREE;
|
||||
}
|
||||
// update memory representation of object index page with new data page
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// update object index header page
|
||||
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
} else {
|
||||
// update object index page
|
||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
// find and evacuate object index pages
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// found an index object id
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix new_pix;
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr,
|
||||
SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
|
||||
SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
|
||||
}
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scan = 0;
|
||||
break;
|
||||
} // switch gc state
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop
|
||||
} // per object lookup page
|
||||
if (res != SPIFFS_OK) break;
|
||||
|
||||
// state finalization and switch
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
if (gc.obj_id_found) {
|
||||
// handle found data page -
|
||||
// find out corresponding obj ix page and load it to memory
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix objix_pix;
|
||||
gc.stored_scan_entry_index = cur_entry; // push cursor
|
||||
cur_entry = 0; // restart scan from start
|
||||
gc.state = MOVE_OBJ_DATA;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:"_SPIPRIsp"\n", gc.cur_objix_spix);
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// on borked systems we might get an ERR_NOT_FOUND here -
|
||||
// this is handled by simply deleting the page as it is not referenced
|
||||
// from anywhere
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_OBJ_DATA objix not found! Wipe page "_SPIPRIpg"\n", gc.cur_data_pix);
|
||||
res = spiffs_page_delete(fs, gc.cur_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// then we restore states and continue scanning for data pages
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
break; // done
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page "_SPIPRIpg"\n", objix_pix);
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// cannot allow a gc if the presumed index in fact is no index, a
|
||||
// check must run or lot of data may be lost
|
||||
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
|
||||
gc.cur_objix_pix = objix_pix;
|
||||
} else {
|
||||
// no more data pages found, passed thru all block, start evacuating object indices
|
||||
gc.state = MOVE_OBJ_IX;
|
||||
cur_entry = 0; // restart entry scan index
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA: {
|
||||
// store modified objix (hdr) page residing in memory now that all
|
||||
// data pages belonging to this object index and residing in the block
|
||||
// we want to evacuate
|
||||
spiffs_page_ix new_objix_pix;
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// store object index header page
|
||||
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// store object index page
|
||||
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
|
||||
SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
// scanned thru all block, no more object indices found - our work here is done
|
||||
gc.state = FINISHED;
|
||||
break;
|
||||
default:
|
||||
cur_entry = 0;
|
||||
break;
|
||||
} // switch gc.state
|
||||
SPIFFS_GC_DBG("gc_clean: state-> "_SPIPRIi"\n", gc.state);
|
||||
} // while state != FINISHED
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
1405
components/mkspiffs/src/spiffs/spiffs_hydrogen.c
Normal file
1405
components/mkspiffs/src/spiffs/spiffs_hydrogen.c
Normal file
File diff suppressed because it is too large
Load Diff
2327
components/mkspiffs/src/spiffs/spiffs_nucleus.c
Normal file
2327
components/mkspiffs/src/spiffs/spiffs_nucleus.c
Normal file
File diff suppressed because it is too large
Load Diff
797
components/mkspiffs/src/spiffs/spiffs_nucleus.h
Normal file
797
components/mkspiffs/src/spiffs/spiffs_nucleus.h
Normal file
@ -0,0 +1,797 @@
|
||||
/*
|
||||
* spiffs_nucleus.h
|
||||
*
|
||||
* Created on: Jun 15, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/* SPIFFS layout
|
||||
*
|
||||
* spiffs is designed for following spi flash characteristics:
|
||||
* - only big areas of data (blocks) can be erased
|
||||
* - erasing resets all bits in a block to ones
|
||||
* - writing pulls ones to zeroes
|
||||
* - zeroes cannot be pulled to ones, without erase
|
||||
* - wear leveling
|
||||
*
|
||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
*
|
||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
* Each block contains same number of pages. A page cannot be erased, but a
|
||||
* block can be erased.
|
||||
*
|
||||
* Entire area must be block_size * x
|
||||
* page_size must be block_size / (2^y) where y > 2
|
||||
*
|
||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
*
|
||||
* BLOCK 0 PAGE 0 object lookup 1
|
||||
* PAGE 1 object lookup 2
|
||||
* ...
|
||||
* PAGE n-1 object lookup n
|
||||
* PAGE n object data 1
|
||||
* PAGE n+1 object data 2
|
||||
* ...
|
||||
* PAGE n+m-1 object data m
|
||||
*
|
||||
* BLOCK 1 PAGE n+m object lookup 1
|
||||
* PAGE n+m+1 object lookup 2
|
||||
* ...
|
||||
* PAGE 2n+m-1 object lookup n
|
||||
* PAGE 2n+m object data 1
|
||||
* PAGE 2n+m object data 2
|
||||
* ...
|
||||
* PAGE 2n+2m-1 object data m
|
||||
* ...
|
||||
*
|
||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
* in a block by object id
|
||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
* thus, n+m is total number of pages in a block
|
||||
* : block_size / page_size
|
||||
*
|
||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
*
|
||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
* data page.
|
||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
* An object id being 0x0000 represents a deleted page.
|
||||
*
|
||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
* page 2 : data : data for object id 0008
|
||||
* page 3 : data : data for object id 0001
|
||||
* page 4 : data : data for object id 0aaa
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Object data pages can be either object index pages or object content.
|
||||
* All object data pages contains a data page header, containing object id and span index.
|
||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
||||
* This applies to both object index pages (when index spans more than one page of entries),
|
||||
* and object data pages.
|
||||
* An object index page contains page entries pointing to object content page. The entry index
|
||||
* in a object index page correlates to the span index in the actual object data page.
|
||||
* The first object index page (span index 0) is called object index header page, and also
|
||||
* contains object flags (directory/file), size, object name etc.
|
||||
*
|
||||
* ex:
|
||||
* BLOCK 1
|
||||
* PAGE 256: objectl lookup page 1
|
||||
* [*123] [ 123] [ 123] [ 123]
|
||||
* [ 123] [*123] [ 123] [ 123]
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 257: objectl lookup page 2
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 258: object index page (header)
|
||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
||||
* size:1600 name:ex.txt type:file
|
||||
* [259] [260] [261] [262]
|
||||
* PAGE 259: object data page
|
||||
* obj.id:0123 span.ix:0000 flags:DATA
|
||||
* PAGE 260: object data page
|
||||
* obj.id:0123 span.ix:0001 flags:DATA
|
||||
* PAGE 261: object data page
|
||||
* obj.id:0123 span.ix:0002 flags:DATA
|
||||
* PAGE 262: object data page
|
||||
* obj.id:0123 span.ix:0003 flags:DATA
|
||||
* PAGE 263: object index page
|
||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
||||
* [264] [265] [fre] [fre]
|
||||
* [fre] [fre] [fre] [fre]
|
||||
* PAGE 264: object data page
|
||||
* obj.id:0123 span.ix:0004 flags:DATA
|
||||
* PAGE 265: object data page
|
||||
* obj.id:0123 span.ix:0005 flags:DATA
|
||||
*
|
||||
*/
|
||||
#ifndef SPIFFS_NUCLEUS_H_
|
||||
#define SPIFFS_NUCLEUS_H_
|
||||
|
||||
#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
|
||||
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
|
||||
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
|
||||
|
||||
// visitor result, continue searching
|
||||
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
|
||||
// visitor result, continue searching after reloading lu buffer
|
||||
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
|
||||
// visitor result, stop searching
|
||||
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
|
||||
|
||||
// updating an object index contents
|
||||
#define SPIFFS_EV_IX_UPD (0)
|
||||
// creating a new object index
|
||||
#define SPIFFS_EV_IX_NEW (1)
|
||||
// deleting an object index
|
||||
#define SPIFFS_EV_IX_DEL (2)
|
||||
// moving an object index without updating contents
|
||||
#define SPIFFS_EV_IX_MOV (3)
|
||||
// updating an object index header data only, not the table itself
|
||||
#define SPIFFS_EV_IX_UPD_HDR (4)
|
||||
|
||||
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
||||
|
||||
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
||||
|
||||
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
|
||||
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
#if !SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
|
||||
#else // SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
|
||||
#endif // SPIFFS_USE_MAGIC_LENGTH
|
||||
#endif // SPIFFS_USE_MAGIC
|
||||
|
||||
#define SPIFFS_CONFIG_MAGIC (0x20090315)
|
||||
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
||||
((fs)->cfg.log_page_size)
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
||||
((fs)->cfg.log_block_size)
|
||||
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
||||
((fs)->cfg.phys_size)
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
||||
((fs)->cfg.phys_erase_block)
|
||||
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
||||
((fs)->cfg.phys_addr)
|
||||
#endif
|
||||
|
||||
// total number of pages
|
||||
#define SPIFFS_MAX_PAGES(fs) \
|
||||
( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// total number of pages per block, including object lookup pages
|
||||
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
||||
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// number of object lookup pages per block
|
||||
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
||||
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
||||
// checks if page index belongs to object lookup
|
||||
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
||||
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// number of object lookup entries in all object lookup pages
|
||||
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// converts a block to physical address
|
||||
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
||||
// converts a object lookup entry to page index
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
||||
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
||||
// converts a object lookup entry to physical address of corresponding page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
||||
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a page to physical address
|
||||
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a physical address to page
|
||||
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// gives index in page for a physical address
|
||||
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// returns containing block for given page
|
||||
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
||||
( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// returns starting page for block
|
||||
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
||||
( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// converts page to entry in object lookup page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
||||
( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
|
||||
// returns data size in a data page
|
||||
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
||||
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
||||
// returns physical address for block's erase count,
|
||||
// always in the physical last entry of the last object lookup page
|
||||
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
|
||||
// returns physical address for block's magic,
|
||||
// always in the physical second last entry of the last object lookup page
|
||||
#define SPIFFS_MAGIC_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
|
||||
// checks if there is any room for magic in the object luts
|
||||
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
|
||||
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
|
||||
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
|
||||
|
||||
// define helpers object
|
||||
|
||||
// entries in an object header page index
|
||||
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
||||
// entries in an object page index
|
||||
#define SPIFFS_OBJ_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
||||
// object index entry for given data span index
|
||||
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// object index span index number for given data span index or entry
|
||||
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// get data span index for object index span index
|
||||
#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
|
||||
( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
|
||||
|
||||
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
||||
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
||||
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
||||
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
||||
#define SPIFFS_OP_C_DELE (0<<2)
|
||||
#define SPIFFS_OP_C_UPDT (1<<2)
|
||||
#define SPIFFS_OP_C_MOVS (2<<2)
|
||||
#define SPIFFS_OP_C_MOVD (3<<2)
|
||||
#define SPIFFS_OP_C_FLSH (4<<2)
|
||||
#define SPIFFS_OP_C_READ (5<<2)
|
||||
#define SPIFFS_OP_C_WRTHRU (6<<2)
|
||||
|
||||
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
||||
#define SPIFFS_OP_COM_MASK (7<<2)
|
||||
|
||||
|
||||
// if 0, this page is written to, else clean
|
||||
#define SPIFFS_PH_FLAG_USED (1<<0)
|
||||
// if 0, writing is finalized, else under modification
|
||||
#define SPIFFS_PH_FLAG_FINAL (1<<1)
|
||||
// if 0, this is an index page, else a data page
|
||||
#define SPIFFS_PH_FLAG_INDEX (1<<2)
|
||||
// if 0, page is deleted, else valid
|
||||
#define SPIFFS_PH_FLAG_DELET (1<<7)
|
||||
// if 0, this index header is being deleted
|
||||
#define SPIFFS_PH_FLAG_IXDELE (1<<6)
|
||||
|
||||
|
||||
#define SPIFFS_CHECK_MOUNT(fs) \
|
||||
((fs)->mounted != 0)
|
||||
|
||||
#define SPIFFS_CHECK_CFG(fs) \
|
||||
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
|
||||
|
||||
#define SPIFFS_CHECK_RES(res) \
|
||||
do { \
|
||||
if ((res) < SPIFFS_OK) return (res); \
|
||||
} while (0);
|
||||
|
||||
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
||||
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
||||
return SPIFFS_ERR_NOT_MOUNTED; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_CFG(fs) \
|
||||
if (!SPIFFS_CHECK_CFG((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
return SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
return (res); \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
SPIFFS_UNLOCK(fs); \
|
||||
return (res); \
|
||||
}
|
||||
|
||||
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
||||
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
||||
|
||||
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
|
||||
|
||||
|
||||
// check id, only visit matching objec ids
|
||||
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
||||
// report argument object id to visitor - else object lookup id is reported
|
||||
#define SPIFFS_VIS_CHECK_PH (1<<1)
|
||||
// stop searching at end of all look up pages
|
||||
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
||||
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||||
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
||||
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
||||
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
||||
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
||||
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
||||
|
||||
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
||||
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
||||
|
||||
#define spiffs_get_cache(fs) \
|
||||
((spiffs_cache *)((fs)->cache))
|
||||
|
||||
#define spiffs_get_cache_page_hdr(fs, c, ix) \
|
||||
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
||||
|
||||
#define spiffs_get_cache_page(fs, c, ix) \
|
||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||
|
||||
// cache page struct
|
||||
typedef struct {
|
||||
// cache flags
|
||||
u8_t flags;
|
||||
// cache page index
|
||||
u8_t ix;
|
||||
// last access of this cache page
|
||||
u32_t last_access;
|
||||
union {
|
||||
// type read cache
|
||||
struct {
|
||||
// read cache page index
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
#if SPIFFS_CACHE_WR
|
||||
// type write cache
|
||||
struct {
|
||||
// write cache
|
||||
spiffs_obj_id obj_id;
|
||||
// offset in cache page
|
||||
u32_t offset;
|
||||
// size of cache page
|
||||
u16_t size;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
} spiffs_cache_page;
|
||||
|
||||
// cache struct
|
||||
typedef struct {
|
||||
u8_t cpage_count;
|
||||
u32_t last_access;
|
||||
u32_t cpage_use_map;
|
||||
u32_t cpage_use_mask;
|
||||
u8_t *cpages;
|
||||
} spiffs_cache;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// spiffs nucleus file descriptor
|
||||
typedef struct {
|
||||
// the filesystem of this descriptor
|
||||
spiffs *fs;
|
||||
// number of file descriptor - if 0, the file descriptor is closed
|
||||
spiffs_file file_nbr;
|
||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||||
spiffs_obj_id obj_id;
|
||||
// size of the file
|
||||
u32_t size;
|
||||
// cached object index header page index
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
// cached offset object index page index
|
||||
spiffs_page_ix cursor_objix_pix;
|
||||
// cached offset object index span index
|
||||
spiffs_span_ix cursor_objix_spix;
|
||||
// current absolute offset
|
||||
u32_t offset;
|
||||
// current file descriptor offset
|
||||
u32_t fdoffset;
|
||||
// fd flags
|
||||
spiffs_flags flags;
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *cache_page;
|
||||
#endif
|
||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||
// djb2 hash of filename
|
||||
u32_t name_hash;
|
||||
// hit score (score == 0 indicates never used fd)
|
||||
u16_t score;
|
||||
#endif
|
||||
#if SPIFFS_IX_MAP
|
||||
// spiffs index map, if 0 it means unmapped
|
||||
spiffs_ix_map *ix_map;
|
||||
#endif
|
||||
} spiffs_fd;
|
||||
|
||||
|
||||
// object structs
|
||||
|
||||
// page header, part of each page except object lookup pages
|
||||
// NB: this is always aligned when the data page is an object index,
|
||||
// as in this case struct spiffs_page_object_ix is used
|
||||
typedef struct __attribute(( packed )) {
|
||||
// object id
|
||||
spiffs_obj_id obj_id;
|
||||
// object span index
|
||||
spiffs_span_ix span_ix;
|
||||
// flags
|
||||
u8_t flags;
|
||||
} spiffs_page_header;
|
||||
|
||||
// object index header page header
|
||||
typedef struct __attribute(( packed ))
|
||||
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
||||
#endif
|
||||
{
|
||||
// common page header
|
||||
spiffs_page_header p_hdr;
|
||||
// alignment
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
// size of object
|
||||
u32_t size;
|
||||
// type of object
|
||||
spiffs_obj_type type;
|
||||
// name of object
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
// metadata. not interpreted by SPIFFS in any way.
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
} spiffs_page_object_ix_header;
|
||||
|
||||
// object index page header
|
||||
typedef struct __attribute(( packed )) {
|
||||
spiffs_page_header p_hdr;
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
} spiffs_page_object_ix;
|
||||
|
||||
// callback func for object lookup visitor
|
||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||||
const void *user_const_p, void *user_var_p);
|
||||
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
||||
#else
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (addr), (len), (src))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src);
|
||||
|
||||
s32_t spiffs_phys_cpy(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u32_t dst,
|
||||
u32_t src,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_phys_count_free_blocks(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_entry_visitor(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
u8_t flags,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_visitor_f v,
|
||||
const void *user_const_p,
|
||||
void *user_var_p,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
s32_t spiffs_probe(
|
||||
spiffs_config *cfg);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_obj_lu_scan(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free_obj_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id *obj_id,
|
||||
const u8_t *conflicting_name);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_page_allocate_data(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *ph,
|
||||
u8_t *data,
|
||||
u32_t len,
|
||||
u32_t page_offs,
|
||||
u8_t finalize,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_page_move(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u8_t *page_data,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *page_hdr,
|
||||
spiffs_page_ix src_pix,
|
||||
spiffs_page_ix *dst_pix);
|
||||
|
||||
s32_t spiffs_page_delete(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_object_create(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
const u8_t name[],
|
||||
const u8_t meta[],
|
||||
spiffs_obj_type type,
|
||||
spiffs_page_ix *objix_hdr_pix);
|
||||
|
||||
s32_t spiffs_object_update_index_hdr(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_ix objix_hdr_pix,
|
||||
u8_t *new_objix_hdr_data,
|
||||
const u8_t name[],
|
||||
const u8_t meta[],
|
||||
u32_t size,
|
||||
spiffs_page_ix *new_pix);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
s32_t spiffs_populate_ix_map(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
u32_t vec_entry_start,
|
||||
u32_t vec_entry_end);
|
||||
|
||||
#endif
|
||||
|
||||
void spiffs_cb_object_event(
|
||||
spiffs *fs,
|
||||
spiffs_page_object_ix *objix,
|
||||
int ev,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix new_pix,
|
||||
u32_t new_size);
|
||||
|
||||
s32_t spiffs_object_open_by_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_open_by_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_append(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_modify(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_read(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_object_truncate(
|
||||
spiffs_fd *fd,
|
||||
u32_t new_len,
|
||||
u8_t remove_object);
|
||||
|
||||
s32_t spiffs_object_find_object_index_header_by_name(
|
||||
spiffs *fs,
|
||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidate,
|
||||
int *candidate_count,
|
||||
char fs_crammed);
|
||||
|
||||
s32_t spiffs_gc_clean(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_fd_find_new(
|
||||
spiffs *fs,
|
||||
spiffs_fd **fd,
|
||||
const char *name);
|
||||
|
||||
s32_t spiffs_fd_return(
|
||||
spiffs *fs,
|
||||
spiffs_file f);
|
||||
|
||||
s32_t spiffs_fd_get(
|
||||
spiffs *fs,
|
||||
spiffs_file f,
|
||||
spiffs_fd **fd);
|
||||
|
||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||
void spiffs_fd_temporal_cache_rehash(
|
||||
spiffs *fs,
|
||||
const char *old_path,
|
||||
const char *new_path);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
void spiffs_cache_init(
|
||||
spiffs *fs);
|
||||
|
||||
void spiffs_cache_drop_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
|
||||
void spiffs_cache_fd_release(
|
||||
spiffs *fs,
|
||||
spiffs_cache_page *cp);
|
||||
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
s32_t spiffs_lookup_consistency_check(
|
||||
spiffs *fs,
|
||||
u8_t check_all_objects);
|
||||
|
||||
s32_t spiffs_page_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_object_index_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
#endif /* SPIFFS_NUCLEUS_H_ */
|
692
components/mkspiffs/src/tclap/Arg.h
Normal file
692
components/mkspiffs/src/tclap/Arg.h
Normal file
@ -0,0 +1,692 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: Arg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_ARGUMENT_H
|
||||
#define TCLAP_ARGUMENT_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#else
|
||||
#define HAVE_SSTREAM
|
||||
#endif
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <cstdio>
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
#include <sstream>
|
||||
typedef std::istringstream istringstream;
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
#include <strstream>
|
||||
typedef std::istrstream istringstream;
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
#include "ArgException.h"
|
||||
#include "Visitor.h"
|
||||
#include "CmdLineInterface.h"
|
||||
#include "ArgTraits.h"
|
||||
#include "StandardTraits.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A virtual base class that defines the essential data for all arguments.
|
||||
* This class, or one of its existing children, must be subclassed to do
|
||||
* anything.
|
||||
*/
|
||||
class Arg
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Prevent accidental copying.
|
||||
*/
|
||||
Arg(const Arg& rhs);
|
||||
|
||||
/**
|
||||
* Prevent accidental copying.
|
||||
*/
|
||||
Arg& operator=(const Arg& rhs);
|
||||
|
||||
/**
|
||||
* Indicates whether the rest of the arguments should be ignored.
|
||||
*/
|
||||
static bool& ignoreRestRef() { static bool ign = false; return ign; }
|
||||
|
||||
/**
|
||||
* The delimiter that separates an argument flag/name from the
|
||||
* value.
|
||||
*/
|
||||
static char& delimiterRef() { static char delim = ' '; return delim; }
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The single char flag used to identify the argument.
|
||||
* This value (preceded by a dash {-}), can be used to identify
|
||||
* an argument on the command line. The _flag can be blank,
|
||||
* in fact this is how unlabeled args work. Unlabeled args must
|
||||
* override appropriate functions to get correct handling. Note
|
||||
* that the _flag does NOT include the dash as part of the flag.
|
||||
*/
|
||||
std::string _flag;
|
||||
|
||||
/**
|
||||
* A single work namd indentifying the argument.
|
||||
* This value (preceded by two dashed {--}) can also be used
|
||||
* to identify an argument on the command line. Note that the
|
||||
* _name does NOT include the two dashes as part of the _name. The
|
||||
* _name cannot be blank.
|
||||
*/
|
||||
std::string _name;
|
||||
|
||||
/**
|
||||
* Description of the argument.
|
||||
*/
|
||||
std::string _description;
|
||||
|
||||
/**
|
||||
* Indicating whether the argument is required.
|
||||
*/
|
||||
bool _required;
|
||||
|
||||
/**
|
||||
* Label to be used in usage description. Normally set to
|
||||
* "required", but can be changed when necessary.
|
||||
*/
|
||||
std::string _requireLabel;
|
||||
|
||||
/**
|
||||
* Indicates whether a value is required for the argument.
|
||||
* Note that the value may be required but the argument/value
|
||||
* combination may not be, as specified by _required.
|
||||
*/
|
||||
bool _valueRequired;
|
||||
|
||||
/**
|
||||
* Indicates whether the argument has been set.
|
||||
* Indicates that a value on the command line has matched the
|
||||
* name/flag of this argument and the values have been set accordingly.
|
||||
*/
|
||||
bool _alreadySet;
|
||||
|
||||
/**
|
||||
* A pointer to a vistitor object.
|
||||
* The visitor allows special handling to occur as soon as the
|
||||
* argument is matched. This defaults to NULL and should not
|
||||
* be used unless absolutely necessary.
|
||||
*/
|
||||
Visitor* _visitor;
|
||||
|
||||
/**
|
||||
* Whether this argument can be ignored, if desired.
|
||||
*/
|
||||
bool _ignoreable;
|
||||
|
||||
/**
|
||||
* Indicates that the arg was set as part of an XOR and not on the
|
||||
* command line.
|
||||
*/
|
||||
bool _xorSet;
|
||||
|
||||
bool _acceptsMultipleValues;
|
||||
|
||||
/**
|
||||
* Performs the special handling described by the Vistitor.
|
||||
*/
|
||||
void _checkWithVisitor() const;
|
||||
|
||||
/**
|
||||
* Primary constructor. YOU (yes you) should NEVER construct an Arg
|
||||
* directly, this is a base class that is extended by various children
|
||||
* that are meant to be used. Use SwitchArg, ValueArg, MultiArg,
|
||||
* UnlabeledValueArg, or UnlabeledMultiArg instead.
|
||||
*
|
||||
* \param flag - The flag identifying the argument.
|
||||
* \param name - The name identifying the argument.
|
||||
* \param desc - The description of the argument, used in the usage.
|
||||
* \param req - Whether the argument is required.
|
||||
* \param valreq - Whether the a value is required for the argument.
|
||||
* \param v - The visitor checked by the argument. Defaults to NULL.
|
||||
*/
|
||||
Arg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
bool valreq,
|
||||
Visitor* v = NULL );
|
||||
|
||||
public:
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~Arg();
|
||||
|
||||
/**
|
||||
* Adds this to the specified list of Args.
|
||||
* \param argList - The list to add this to.
|
||||
*/
|
||||
virtual void addToList( std::list<Arg*>& argList ) const;
|
||||
|
||||
/**
|
||||
* Begin ignoring arguments since the "--" argument was specified.
|
||||
*/
|
||||
static void beginIgnoring() { ignoreRestRef() = true; }
|
||||
|
||||
/**
|
||||
* Whether to ignore the rest.
|
||||
*/
|
||||
static bool ignoreRest() { return ignoreRestRef(); }
|
||||
|
||||
/**
|
||||
* The delimiter that separates an argument flag/name from the
|
||||
* value.
|
||||
*/
|
||||
static char delimiter() { return delimiterRef(); }
|
||||
|
||||
/**
|
||||
* The char used as a place holder when SwitchArgs are combined.
|
||||
* Currently set to the bell char (ASCII 7).
|
||||
*/
|
||||
static char blankChar() { return (char)7; }
|
||||
|
||||
/**
|
||||
* The char that indicates the beginning of a flag. Defaults to '-', but
|
||||
* clients can define TCLAP_FLAGSTARTCHAR to override.
|
||||
*/
|
||||
#ifndef TCLAP_FLAGSTARTCHAR
|
||||
#define TCLAP_FLAGSTARTCHAR '-'
|
||||
#endif
|
||||
static char flagStartChar() { return TCLAP_FLAGSTARTCHAR; }
|
||||
|
||||
/**
|
||||
* The sting that indicates the beginning of a flag. Defaults to "-", but
|
||||
* clients can define TCLAP_FLAGSTARTSTRING to override. Should be the same
|
||||
* as TCLAP_FLAGSTARTCHAR.
|
||||
*/
|
||||
#ifndef TCLAP_FLAGSTARTSTRING
|
||||
#define TCLAP_FLAGSTARTSTRING "-"
|
||||
#endif
|
||||
static const std::string flagStartString() { return TCLAP_FLAGSTARTSTRING; }
|
||||
|
||||
/**
|
||||
* The sting that indicates the beginning of a name. Defaults to "--", but
|
||||
* clients can define TCLAP_NAMESTARTSTRING to override.
|
||||
*/
|
||||
#ifndef TCLAP_NAMESTARTSTRING
|
||||
#define TCLAP_NAMESTARTSTRING "--"
|
||||
#endif
|
||||
static const std::string nameStartString() { return TCLAP_NAMESTARTSTRING; }
|
||||
|
||||
/**
|
||||
* The name used to identify the ignore rest argument.
|
||||
*/
|
||||
static const std::string ignoreNameString() { return "ignore_rest"; }
|
||||
|
||||
/**
|
||||
* Sets the delimiter for all arguments.
|
||||
* \param c - The character that delimits flags/names from values.
|
||||
*/
|
||||
static void setDelimiter( char c ) { delimiterRef() = c; }
|
||||
|
||||
/**
|
||||
* Pure virtual method meant to handle the parsing and value assignment
|
||||
* of the string on the command line.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. What is
|
||||
* passed in from main.
|
||||
*/
|
||||
virtual bool processArg(int *i, std::vector<std::string>& args) = 0;
|
||||
|
||||
/**
|
||||
* Operator ==.
|
||||
* Equality operator. Must be virtual to handle unlabeled args.
|
||||
* \param a - The Arg to be compared to this.
|
||||
*/
|
||||
virtual bool operator==(const Arg& a) const;
|
||||
|
||||
/**
|
||||
* Returns the argument flag.
|
||||
*/
|
||||
const std::string& getFlag() const;
|
||||
|
||||
/**
|
||||
* Returns the argument name.
|
||||
*/
|
||||
const std::string& getName() const;
|
||||
|
||||
/**
|
||||
* Returns the argument description.
|
||||
*/
|
||||
std::string getDescription() const;
|
||||
|
||||
/**
|
||||
* Indicates whether the argument is required.
|
||||
*/
|
||||
virtual bool isRequired() const;
|
||||
|
||||
/**
|
||||
* Sets _required to true. This is used by the XorHandler.
|
||||
* You really have no reason to ever use it.
|
||||
*/
|
||||
void forceRequired();
|
||||
|
||||
/**
|
||||
* Sets the _alreadySet value to true. This is used by the XorHandler.
|
||||
* You really have no reason to ever use it.
|
||||
*/
|
||||
void xorSet();
|
||||
|
||||
/**
|
||||
* Indicates whether a value must be specified for argument.
|
||||
*/
|
||||
bool isValueRequired() const;
|
||||
|
||||
/**
|
||||
* Indicates whether the argument has already been set. Only true
|
||||
* if the arg has been matched on the command line.
|
||||
*/
|
||||
bool isSet() const;
|
||||
|
||||
/**
|
||||
* Indicates whether the argument can be ignored, if desired.
|
||||
*/
|
||||
bool isIgnoreable() const;
|
||||
|
||||
/**
|
||||
* A method that tests whether a string matches this argument.
|
||||
* This is generally called by the processArg() method. This
|
||||
* method could be re-implemented by a child to change how
|
||||
* arguments are specified on the command line.
|
||||
* \param s - The string to be compared to the flag/name to determine
|
||||
* whether the arg matches.
|
||||
*/
|
||||
virtual bool argMatches( const std::string& s ) const;
|
||||
|
||||
/**
|
||||
* Returns a simple string representation of the argument.
|
||||
* Primarily for debugging.
|
||||
*/
|
||||
virtual std::string toString() const;
|
||||
|
||||
/**
|
||||
* Returns a short ID for the usage.
|
||||
* \param valueId - The value used in the id.
|
||||
*/
|
||||
virtual std::string shortID( const std::string& valueId = "val" ) const;
|
||||
|
||||
/**
|
||||
* Returns a long ID for the usage.
|
||||
* \param valueId - The value used in the id.
|
||||
*/
|
||||
virtual std::string longID( const std::string& valueId = "val" ) const;
|
||||
|
||||
/**
|
||||
* Trims a value off of the flag.
|
||||
* \param flag - The string from which the flag and value will be
|
||||
* trimmed. Contains the flag once the value has been trimmed.
|
||||
* \param value - Where the value trimmed from the string will
|
||||
* be stored.
|
||||
*/
|
||||
virtual void trimFlag( std::string& flag, std::string& value ) const;
|
||||
|
||||
/**
|
||||
* Checks whether a given string has blank chars, indicating that
|
||||
* it is a combined SwitchArg. If so, return true, otherwise return
|
||||
* false.
|
||||
* \param s - string to be checked.
|
||||
*/
|
||||
bool _hasBlanks( const std::string& s ) const;
|
||||
|
||||
/**
|
||||
* Sets the requireLabel. Used by XorHandler. You shouldn't ever
|
||||
* use this.
|
||||
* \param s - Set the requireLabel to this value.
|
||||
*/
|
||||
void setRequireLabel( const std::string& s );
|
||||
|
||||
/**
|
||||
* Used for MultiArgs and XorHandler to determine whether args
|
||||
* can still be set.
|
||||
*/
|
||||
virtual bool allowMore();
|
||||
|
||||
/**
|
||||
* Use by output classes to determine whether an Arg accepts
|
||||
* multiple values.
|
||||
*/
|
||||
virtual bool acceptsMultipleValues();
|
||||
|
||||
/**
|
||||
* Clears the Arg object and allows it to be reused by new
|
||||
* command lines.
|
||||
*/
|
||||
virtual void reset();
|
||||
};
|
||||
|
||||
/**
|
||||
* Typedef of an Arg list iterator.
|
||||
*/
|
||||
typedef std::list<Arg*>::iterator ArgListIterator;
|
||||
|
||||
/**
|
||||
* Typedef of an Arg vector iterator.
|
||||
*/
|
||||
typedef std::vector<Arg*>::iterator ArgVectorIterator;
|
||||
|
||||
/**
|
||||
* Typedef of a Visitor list iterator.
|
||||
*/
|
||||
typedef std::list<Visitor*>::iterator VisitorListIterator;
|
||||
|
||||
/*
|
||||
* Extract a value of type T from it's string representation contained
|
||||
* in strVal. The ValueLike parameter used to select the correct
|
||||
* specialization of ExtractValue depending on the value traits of T.
|
||||
* ValueLike traits use operator>> to assign the value from strVal.
|
||||
*/
|
||||
template<typename T> void
|
||||
ExtractValue(T &destVal, const std::string& strVal, ValueLike vl)
|
||||
{
|
||||
static_cast<void>(vl); // Avoid warning about unused vl
|
||||
std::istringstream is(strVal);
|
||||
|
||||
int valuesRead = 0;
|
||||
while ( is.good() ) {
|
||||
if ( is.peek() != EOF )
|
||||
#ifdef TCLAP_SETBASE_ZERO
|
||||
is >> std::setbase(0) >> destVal;
|
||||
#else
|
||||
is >> destVal;
|
||||
#endif
|
||||
else
|
||||
break;
|
||||
|
||||
valuesRead++;
|
||||
}
|
||||
|
||||
if ( is.fail() )
|
||||
throw( ArgParseException("Couldn't read argument value "
|
||||
"from string '" + strVal + "'"));
|
||||
|
||||
|
||||
if ( valuesRead > 1 )
|
||||
throw( ArgParseException("More than one valid value parsed from "
|
||||
"string '" + strVal + "'"));
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* Extract a value of type T from it's string representation contained
|
||||
* in strVal. The ValueLike parameter used to select the correct
|
||||
* specialization of ExtractValue depending on the value traits of T.
|
||||
* StringLike uses assignment (operator=) to assign from strVal.
|
||||
*/
|
||||
template<typename T> void
|
||||
ExtractValue(T &destVal, const std::string& strVal, StringLike sl)
|
||||
{
|
||||
static_cast<void>(sl); // Avoid warning about unused sl
|
||||
SetString(destVal, strVal);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//BEGIN Arg.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline Arg::Arg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
bool valreq,
|
||||
Visitor* v) :
|
||||
_flag(flag),
|
||||
_name(name),
|
||||
_description(desc),
|
||||
_required(req),
|
||||
_requireLabel("required"),
|
||||
_valueRequired(valreq),
|
||||
_alreadySet(false),
|
||||
_visitor( v ),
|
||||
_ignoreable(true),
|
||||
_xorSet(false),
|
||||
_acceptsMultipleValues(false)
|
||||
{
|
||||
if ( _flag.length() > 1 )
|
||||
throw(SpecificationException(
|
||||
"Argument flag can only be one character long", toString() ) );
|
||||
|
||||
if ( _name != ignoreNameString() &&
|
||||
( _flag == Arg::flagStartString() ||
|
||||
_flag == Arg::nameStartString() ||
|
||||
_flag == " " ) )
|
||||
throw(SpecificationException("Argument flag cannot be either '" +
|
||||
Arg::flagStartString() + "' or '" +
|
||||
Arg::nameStartString() + "' or a space.",
|
||||
toString() ) );
|
||||
|
||||
if ( ( _name.substr( 0, Arg::flagStartString().length() ) == Arg::flagStartString() ) ||
|
||||
( _name.substr( 0, Arg::nameStartString().length() ) == Arg::nameStartString() ) ||
|
||||
( _name.find( " ", 0 ) != std::string::npos ) )
|
||||
throw(SpecificationException("Argument name begin with either '" +
|
||||
Arg::flagStartString() + "' or '" +
|
||||
Arg::nameStartString() + "' or space.",
|
||||
toString() ) );
|
||||
|
||||
}
|
||||
|
||||
inline Arg::~Arg() { }
|
||||
|
||||
inline std::string Arg::shortID( const std::string& valueId ) const
|
||||
{
|
||||
std::string id = "";
|
||||
|
||||
if ( _flag != "" )
|
||||
id = Arg::flagStartString() + _flag;
|
||||
else
|
||||
id = Arg::nameStartString() + _name;
|
||||
|
||||
if ( _valueRequired )
|
||||
id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
|
||||
|
||||
if ( !_required )
|
||||
id = "[" + id + "]";
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
inline std::string Arg::longID( const std::string& valueId ) const
|
||||
{
|
||||
std::string id = "";
|
||||
|
||||
if ( _flag != "" )
|
||||
{
|
||||
id += Arg::flagStartString() + _flag;
|
||||
|
||||
if ( _valueRequired )
|
||||
id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
|
||||
|
||||
id += ", ";
|
||||
}
|
||||
|
||||
id += Arg::nameStartString() + _name;
|
||||
|
||||
if ( _valueRequired )
|
||||
id += std::string( 1, Arg::delimiter() ) + "<" + valueId + ">";
|
||||
|
||||
return id;
|
||||
|
||||
}
|
||||
|
||||
inline bool Arg::operator==(const Arg& a) const
|
||||
{
|
||||
if ( ( _flag != "" && _flag == a._flag ) || _name == a._name)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string Arg::getDescription() const
|
||||
{
|
||||
std::string desc = "";
|
||||
if ( _required )
|
||||
desc = "(" + _requireLabel + ") ";
|
||||
|
||||
// if ( _valueRequired )
|
||||
// desc += "(value required) ";
|
||||
|
||||
desc += _description;
|
||||
return desc;
|
||||
}
|
||||
|
||||
inline const std::string& Arg::getFlag() const { return _flag; }
|
||||
|
||||
inline const std::string& Arg::getName() const { return _name; }
|
||||
|
||||
inline bool Arg::isRequired() const { return _required; }
|
||||
|
||||
inline bool Arg::isValueRequired() const { return _valueRequired; }
|
||||
|
||||
inline bool Arg::isSet() const
|
||||
{
|
||||
if ( _alreadySet && !_xorSet )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Arg::isIgnoreable() const { return _ignoreable; }
|
||||
|
||||
inline void Arg::setRequireLabel( const std::string& s)
|
||||
{
|
||||
_requireLabel = s;
|
||||
}
|
||||
|
||||
inline bool Arg::argMatches( const std::string& argFlag ) const
|
||||
{
|
||||
if ( ( argFlag == Arg::flagStartString() + _flag && _flag != "" ) ||
|
||||
argFlag == Arg::nameStartString() + _name )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string Arg::toString() const
|
||||
{
|
||||
std::string s = "";
|
||||
|
||||
if ( _flag != "" )
|
||||
s += Arg::flagStartString() + _flag + " ";
|
||||
|
||||
s += "(" + Arg::nameStartString() + _name + ")";
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
inline void Arg::_checkWithVisitor() const
|
||||
{
|
||||
if ( _visitor != NULL )
|
||||
_visitor->visit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of trimFlag.
|
||||
*/
|
||||
inline void Arg::trimFlag(std::string& flag, std::string& value) const
|
||||
{
|
||||
int stop = 0;
|
||||
for ( int i = 0; static_cast<unsigned int>(i) < flag.length(); i++ )
|
||||
if ( flag[i] == Arg::delimiter() )
|
||||
{
|
||||
stop = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if ( stop > 1 )
|
||||
{
|
||||
value = flag.substr(stop+1);
|
||||
flag = flag.substr(0,stop);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of _hasBlanks.
|
||||
*/
|
||||
inline bool Arg::_hasBlanks( const std::string& s ) const
|
||||
{
|
||||
for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
|
||||
if ( s[i] == Arg::blankChar() )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void Arg::forceRequired()
|
||||
{
|
||||
_required = true;
|
||||
}
|
||||
|
||||
inline void Arg::xorSet()
|
||||
{
|
||||
_alreadySet = true;
|
||||
_xorSet = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden by Args that need to added to the end of the list.
|
||||
*/
|
||||
inline void Arg::addToList( std::list<Arg*>& argList ) const
|
||||
{
|
||||
argList.push_front( const_cast<Arg*>(this) );
|
||||
}
|
||||
|
||||
inline bool Arg::allowMore()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool Arg::acceptsMultipleValues()
|
||||
{
|
||||
return _acceptsMultipleValues;
|
||||
}
|
||||
|
||||
inline void Arg::reset()
|
||||
{
|
||||
_xorSet = false;
|
||||
_alreadySet = false;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//END Arg.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} //namespace TCLAP
|
||||
|
||||
#endif
|
||||
|
200
components/mkspiffs/src/tclap/ArgException.h
Normal file
200
components/mkspiffs/src/tclap/ArgException.h
Normal file
@ -0,0 +1,200 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: ArgException.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_ARG_EXCEPTION_H
|
||||
#define TCLAP_ARG_EXCEPTION_H
|
||||
|
||||
#include <string>
|
||||
#include <exception>
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A simple class that defines and argument exception. Should be caught
|
||||
* whenever a CmdLine is created and parsed.
|
||||
*/
|
||||
class ArgException : public std::exception
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param text - The text of the exception.
|
||||
* \param id - The text identifying the argument source.
|
||||
* \param td - Text describing the type of ArgException it is.
|
||||
* of the exception.
|
||||
*/
|
||||
ArgException( const std::string& text = "undefined exception",
|
||||
const std::string& id = "undefined",
|
||||
const std::string& td = "Generic ArgException")
|
||||
: std::exception(),
|
||||
_errorText(text),
|
||||
_argId( id ),
|
||||
_typeDescription(td)
|
||||
{ }
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
*/
|
||||
virtual ~ArgException() throw() { }
|
||||
|
||||
/**
|
||||
* Returns the error text.
|
||||
*/
|
||||
std::string error() const { return ( _errorText ); }
|
||||
|
||||
/**
|
||||
* Returns the argument id.
|
||||
*/
|
||||
std::string argId() const
|
||||
{
|
||||
if ( _argId == "undefined" )
|
||||
return " ";
|
||||
else
|
||||
return ( "Argument: " + _argId );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the arg id and error text.
|
||||
*/
|
||||
const char* what() const throw()
|
||||
{
|
||||
static std::string ex;
|
||||
ex = _argId + " -- " + _errorText;
|
||||
return ex.c_str();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the type of the exception. Used to explain and distinguish
|
||||
* between different child exceptions.
|
||||
*/
|
||||
std::string typeDescription() const
|
||||
{
|
||||
return _typeDescription;
|
||||
}
|
||||
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* The text of the exception message.
|
||||
*/
|
||||
std::string _errorText;
|
||||
|
||||
/**
|
||||
* The argument related to this exception.
|
||||
*/
|
||||
std::string _argId;
|
||||
|
||||
/**
|
||||
* Describes the type of the exception. Used to distinguish
|
||||
* between different child exceptions.
|
||||
*/
|
||||
std::string _typeDescription;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Thrown from within the child Arg classes when it fails to properly
|
||||
* parse the argument it has been passed.
|
||||
*/
|
||||
class ArgParseException : public ArgException
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* \param text - The text of the exception.
|
||||
* \param id - The text identifying the argument source
|
||||
* of the exception.
|
||||
*/
|
||||
ArgParseException( const std::string& text = "undefined exception",
|
||||
const std::string& id = "undefined" )
|
||||
: ArgException( text,
|
||||
id,
|
||||
std::string( "Exception found while parsing " ) +
|
||||
std::string( "the value the Arg has been passed." ))
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* Thrown from CmdLine when the arguments on the command line are not
|
||||
* properly specified, e.g. too many arguments, required argument missing, etc.
|
||||
*/
|
||||
class CmdLineParseException : public ArgException
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* \param text - The text of the exception.
|
||||
* \param id - The text identifying the argument source
|
||||
* of the exception.
|
||||
*/
|
||||
CmdLineParseException( const std::string& text = "undefined exception",
|
||||
const std::string& id = "undefined" )
|
||||
: ArgException( text,
|
||||
id,
|
||||
std::string( "Exception found when the values ") +
|
||||
std::string( "on the command line do not meet ") +
|
||||
std::string( "the requirements of the defined ") +
|
||||
std::string( "Args." ))
|
||||
{ }
|
||||
};
|
||||
|
||||
/**
|
||||
* Thrown from Arg and CmdLine when an Arg is improperly specified, e.g.
|
||||
* same flag as another Arg, same name, etc.
|
||||
*/
|
||||
class SpecificationException : public ArgException
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* Constructor.
|
||||
* \param text - The text of the exception.
|
||||
* \param id - The text identifying the argument source
|
||||
* of the exception.
|
||||
*/
|
||||
SpecificationException( const std::string& text = "undefined exception",
|
||||
const std::string& id = "undefined" )
|
||||
: ArgException( text,
|
||||
id,
|
||||
std::string("Exception found when an Arg object ")+
|
||||
std::string("is improperly defined by the ") +
|
||||
std::string("developer." ))
|
||||
{ }
|
||||
|
||||
};
|
||||
|
||||
class ExitException {
|
||||
public:
|
||||
ExitException(int estat) : _estat(estat) {}
|
||||
|
||||
int getExitStatus() const { return _estat; }
|
||||
|
||||
private:
|
||||
int _estat;
|
||||
};
|
||||
|
||||
} // namespace TCLAP
|
||||
|
||||
#endif
|
||||
|
87
components/mkspiffs/src/tclap/ArgTraits.h
Normal file
87
components/mkspiffs/src/tclap/ArgTraits.h
Normal file
@ -0,0 +1,87 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: ArgTraits.h
|
||||
*
|
||||
* Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// This is an internal tclap file, you should probably not have to
|
||||
// include this directly
|
||||
|
||||
#ifndef TCLAP_ARGTRAITS_H
|
||||
#define TCLAP_ARGTRAITS_H
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
// We use two empty structs to get compile type specialization
|
||||
// function to work
|
||||
|
||||
/**
|
||||
* A value like argument value type is a value that can be set using
|
||||
* operator>>. This is the default value type.
|
||||
*/
|
||||
struct ValueLike {
|
||||
typedef ValueLike ValueCategory;
|
||||
virtual ~ValueLike() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A string like argument value type is a value that can be set using
|
||||
* operator=(string). Usefull if the value type contains spaces which
|
||||
* will be broken up into individual tokens by operator>>.
|
||||
*/
|
||||
struct StringLike {
|
||||
virtual ~StringLike() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class can inherit from this object to make it have string like
|
||||
* traits. This is a compile time thing and does not add any overhead
|
||||
* to the inherenting class.
|
||||
*/
|
||||
struct StringLikeTrait {
|
||||
typedef StringLike ValueCategory;
|
||||
virtual ~StringLikeTrait() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* A class can inherit from this object to make it have value like
|
||||
* traits. This is a compile time thing and does not add any overhead
|
||||
* to the inherenting class.
|
||||
*/
|
||||
struct ValueLikeTrait {
|
||||
typedef ValueLike ValueCategory;
|
||||
virtual ~ValueLikeTrait() {}
|
||||
};
|
||||
|
||||
/**
|
||||
* Arg traits are used to get compile type specialization when parsing
|
||||
* argument values. Using an ArgTraits you can specify the way that
|
||||
* values gets assigned to any particular type during parsing. The two
|
||||
* supported types are StringLike and ValueLike.
|
||||
*/
|
||||
template<typename T>
|
||||
struct ArgTraits {
|
||||
typedef typename T::ValueCategory ValueCategory;
|
||||
virtual ~ArgTraits() {}
|
||||
//typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
} // namespace
|
25
components/mkspiffs/src/tclap/COPYING
Normal file
25
components/mkspiffs/src/tclap/COPYING
Normal file
@ -0,0 +1,25 @@
|
||||
|
||||
|
||||
Copyright (c) 2003 Michael E. Smoot
|
||||
|
||||
Permission is hereby granted, free of charge, to any person
|
||||
obtaining a copy of this software and associated documentation
|
||||
files (the "Software"), to deal in the Software without restriction,
|
||||
including without limitation the rights to use, copy, modify, merge,
|
||||
publish, distribute, sublicense, and/or sell copies of the Software,
|
||||
and to permit persons to whom the Software is furnished to do so,
|
||||
subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
|
||||
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
|
||||
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
|
||||
AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
|
||||
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
|
||||
|
633
components/mkspiffs/src/tclap/CmdLine.h
Normal file
633
components/mkspiffs/src/tclap/CmdLine.h
Normal file
@ -0,0 +1,633 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: CmdLine.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_CMDLINE_H
|
||||
#define TCLAP_CMDLINE_H
|
||||
|
||||
#include "SwitchArg.h"
|
||||
#include "MultiSwitchArg.h"
|
||||
#include "UnlabeledValueArg.h"
|
||||
#include "UnlabeledMultiArg.h"
|
||||
|
||||
#include "XorHandler.h"
|
||||
#include "HelpVisitor.h"
|
||||
#include "VersionVisitor.h"
|
||||
#include "IgnoreRestVisitor.h"
|
||||
|
||||
#include "CmdLineOutput.h"
|
||||
#include "StdOutput.h"
|
||||
|
||||
#include "Constraint.h"
|
||||
#include "ValuesConstraint.h"
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
#include <stdlib.h> // Needed for exit(), which isn't defined in some envs.
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
template<typename T> void DelPtr(T ptr)
|
||||
{
|
||||
delete ptr;
|
||||
}
|
||||
|
||||
template<typename C> void ClearContainer(C &c)
|
||||
{
|
||||
typedef typename C::value_type value_type;
|
||||
std::for_each(c.begin(), c.end(), DelPtr<value_type>);
|
||||
c.clear();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The base class that manages the command line definition and passes
|
||||
* along the parsing to the appropriate Arg classes.
|
||||
*/
|
||||
class CmdLine : public CmdLineInterface
|
||||
{
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The list of arguments that will be tested against the
|
||||
* command line.
|
||||
*/
|
||||
std::list<Arg*> _argList;
|
||||
|
||||
/**
|
||||
* The name of the program. Set to argv[0].
|
||||
*/
|
||||
std::string _progName;
|
||||
|
||||
/**
|
||||
* A message used to describe the program. Used in the usage output.
|
||||
*/
|
||||
std::string _message;
|
||||
|
||||
/**
|
||||
* The version to be displayed with the --version switch.
|
||||
*/
|
||||
std::string _version;
|
||||
|
||||
/**
|
||||
* The number of arguments that are required to be present on
|
||||
* the command line. This is set dynamically, based on the
|
||||
* Args added to the CmdLine object.
|
||||
*/
|
||||
int _numRequired;
|
||||
|
||||
/**
|
||||
* The character that is used to separate the argument flag/name
|
||||
* from the value. Defaults to ' ' (space).
|
||||
*/
|
||||
char _delimiter;
|
||||
|
||||
/**
|
||||
* The handler that manages xoring lists of args.
|
||||
*/
|
||||
XorHandler _xorHandler;
|
||||
|
||||
/**
|
||||
* A list of Args to be explicitly deleted when the destructor
|
||||
* is called. At the moment, this only includes the three default
|
||||
* Args.
|
||||
*/
|
||||
std::list<Arg*> _argDeleteOnExitList;
|
||||
|
||||
/**
|
||||
* A list of Visitors to be explicitly deleted when the destructor
|
||||
* is called. At the moment, these are the Vistors created for the
|
||||
* default Args.
|
||||
*/
|
||||
std::list<Visitor*> _visitorDeleteOnExitList;
|
||||
|
||||
/**
|
||||
* Object that handles all output for the CmdLine.
|
||||
*/
|
||||
CmdLineOutput* _output;
|
||||
|
||||
/**
|
||||
* Should CmdLine handle parsing exceptions internally?
|
||||
*/
|
||||
bool _handleExceptions;
|
||||
|
||||
/**
|
||||
* Throws an exception listing the missing args.
|
||||
*/
|
||||
void missingArgsException();
|
||||
|
||||
/**
|
||||
* Checks whether a name/flag string matches entirely matches
|
||||
* the Arg::blankChar. Used when multiple switches are combined
|
||||
* into a single argument.
|
||||
* \param s - The message to be used in the usage.
|
||||
*/
|
||||
bool _emptyCombined(const std::string& s);
|
||||
|
||||
/**
|
||||
* Perform a delete ptr; operation on ptr when this object is deleted.
|
||||
*/
|
||||
void deleteOnExit(Arg* ptr);
|
||||
|
||||
/**
|
||||
* Perform a delete ptr; operation on ptr when this object is deleted.
|
||||
*/
|
||||
void deleteOnExit(Visitor* ptr);
|
||||
|
||||
private:
|
||||
|
||||
/**
|
||||
* Prevent accidental copying.
|
||||
*/
|
||||
CmdLine(const CmdLine& rhs);
|
||||
CmdLine& operator=(const CmdLine& rhs);
|
||||
|
||||
/**
|
||||
* Encapsulates the code common to the constructors
|
||||
* (which is all of it).
|
||||
*/
|
||||
void _constructor();
|
||||
|
||||
|
||||
/**
|
||||
* Is set to true when a user sets the output object. We use this so
|
||||
* that we don't delete objects that are created outside of this lib.
|
||||
*/
|
||||
bool _userSetOutput;
|
||||
|
||||
/**
|
||||
* Whether or not to automatically create help and version switches.
|
||||
*/
|
||||
bool _helpAndVersion;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Command line constructor. Defines how the arguments will be
|
||||
* parsed.
|
||||
* \param message - The message to be used in the usage
|
||||
* output.
|
||||
* \param delimiter - The character that is used to separate
|
||||
* the argument flag/name from the value. Defaults to ' ' (space).
|
||||
* \param version - The version number to be used in the
|
||||
* --version switch.
|
||||
* \param helpAndVersion - Whether or not to create the Help and
|
||||
* Version switches. Defaults to true.
|
||||
*/
|
||||
CmdLine(const std::string& message,
|
||||
const char delimiter = ' ',
|
||||
const std::string& version = "none",
|
||||
bool helpAndVersion = true);
|
||||
|
||||
/**
|
||||
* Deletes any resources allocated by a CmdLine object.
|
||||
*/
|
||||
virtual ~CmdLine();
|
||||
|
||||
/**
|
||||
* Adds an argument to the list of arguments to be parsed.
|
||||
* \param a - Argument to be added.
|
||||
*/
|
||||
void add( Arg& a );
|
||||
|
||||
/**
|
||||
* An alternative add. Functionally identical.
|
||||
* \param a - Argument to be added.
|
||||
*/
|
||||
void add( Arg* a );
|
||||
|
||||
/**
|
||||
* Add two Args that will be xor'd. If this method is used, add does
|
||||
* not need to be called.
|
||||
* \param a - Argument to be added and xor'd.
|
||||
* \param b - Argument to be added and xor'd.
|
||||
*/
|
||||
void xorAdd( Arg& a, Arg& b );
|
||||
|
||||
/**
|
||||
* Add a list of Args that will be xor'd. If this method is used,
|
||||
* add does not need to be called.
|
||||
* \param xors - List of Args to be added and xor'd.
|
||||
*/
|
||||
void xorAdd( std::vector<Arg*>& xors );
|
||||
|
||||
/**
|
||||
* Parses the command line.
|
||||
* \param argc - Number of arguments.
|
||||
* \param argv - Array of arguments.
|
||||
*/
|
||||
void parse(int argc, const char * const * argv);
|
||||
|
||||
/**
|
||||
* Parses the command line.
|
||||
* \param args - A vector of strings representing the args.
|
||||
* args[0] is still the program name.
|
||||
*/
|
||||
void parse(std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
CmdLineOutput* getOutput();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
void setOutput(CmdLineOutput* co);
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::string& getVersion();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::string& getProgramName();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::list<Arg*>& getArgList();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
XorHandler& getXorHandler();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
char getDelimiter();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
std::string& getMessage();
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
bool hasHelpAndVersion();
|
||||
|
||||
/**
|
||||
* Disables or enables CmdLine's internal parsing exception handling.
|
||||
*
|
||||
* @param state Should CmdLine handle parsing exceptions internally?
|
||||
*/
|
||||
void setExceptionHandling(const bool state);
|
||||
|
||||
/**
|
||||
* Returns the current state of the internal exception handling.
|
||||
*
|
||||
* @retval true Parsing exceptions are handled internally.
|
||||
* @retval false Parsing exceptions are propagated to the caller.
|
||||
*/
|
||||
bool getExceptionHandling() const;
|
||||
|
||||
/**
|
||||
* Allows the CmdLine object to be reused.
|
||||
*/
|
||||
void reset();
|
||||
|
||||
};
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//Begin CmdLine.cpp
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline CmdLine::CmdLine(const std::string& m,
|
||||
char delim,
|
||||
const std::string& v,
|
||||
bool help )
|
||||
:
|
||||
_argList(std::list<Arg*>()),
|
||||
_progName("not_set_yet"),
|
||||
_message(m),
|
||||
_version(v),
|
||||
_numRequired(0),
|
||||
_delimiter(delim),
|
||||
_xorHandler(XorHandler()),
|
||||
_argDeleteOnExitList(std::list<Arg*>()),
|
||||
_visitorDeleteOnExitList(std::list<Visitor*>()),
|
||||
_output(0),
|
||||
_handleExceptions(true),
|
||||
_userSetOutput(false),
|
||||
_helpAndVersion(help)
|
||||
{
|
||||
_constructor();
|
||||
}
|
||||
|
||||
inline CmdLine::~CmdLine()
|
||||
{
|
||||
ClearContainer(_argDeleteOnExitList);
|
||||
ClearContainer(_visitorDeleteOnExitList);
|
||||
|
||||
if ( !_userSetOutput ) {
|
||||
delete _output;
|
||||
_output = 0;
|
||||
}
|
||||
}
|
||||
|
||||
inline void CmdLine::_constructor()
|
||||
{
|
||||
_output = new StdOutput;
|
||||
|
||||
Arg::setDelimiter( _delimiter );
|
||||
|
||||
Visitor* v;
|
||||
|
||||
if ( _helpAndVersion )
|
||||
{
|
||||
v = new HelpVisitor( this, &_output );
|
||||
SwitchArg* help = new SwitchArg("h","help",
|
||||
"Displays usage information and exits.",
|
||||
false, v);
|
||||
add( help );
|
||||
deleteOnExit(help);
|
||||
deleteOnExit(v);
|
||||
|
||||
v = new VersionVisitor( this, &_output );
|
||||
SwitchArg* vers = new SwitchArg("","version",
|
||||
"Displays version information and exits.",
|
||||
false, v);
|
||||
add( vers );
|
||||
deleteOnExit(vers);
|
||||
deleteOnExit(v);
|
||||
}
|
||||
|
||||
v = new IgnoreRestVisitor();
|
||||
SwitchArg* ignore = new SwitchArg(Arg::flagStartString(),
|
||||
Arg::ignoreNameString(),
|
||||
"Ignores the rest of the labeled arguments following this flag.",
|
||||
false, v);
|
||||
add( ignore );
|
||||
deleteOnExit(ignore);
|
||||
deleteOnExit(v);
|
||||
}
|
||||
|
||||
inline void CmdLine::xorAdd( std::vector<Arg*>& ors )
|
||||
{
|
||||
_xorHandler.add( ors );
|
||||
|
||||
for (ArgVectorIterator it = ors.begin(); it != ors.end(); it++)
|
||||
{
|
||||
(*it)->forceRequired();
|
||||
(*it)->setRequireLabel( "OR required" );
|
||||
add( *it );
|
||||
}
|
||||
}
|
||||
|
||||
inline void CmdLine::xorAdd( Arg& a, Arg& b )
|
||||
{
|
||||
std::vector<Arg*> ors;
|
||||
ors.push_back( &a );
|
||||
ors.push_back( &b );
|
||||
xorAdd( ors );
|
||||
}
|
||||
|
||||
inline void CmdLine::add( Arg& a )
|
||||
{
|
||||
add( &a );
|
||||
}
|
||||
|
||||
inline void CmdLine::add( Arg* a )
|
||||
{
|
||||
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
|
||||
if ( *a == *(*it) )
|
||||
throw( SpecificationException(
|
||||
"Argument with same flag/name already exists!",
|
||||
a->longID() ) );
|
||||
|
||||
a->addToList( _argList );
|
||||
|
||||
if ( a->isRequired() )
|
||||
_numRequired++;
|
||||
}
|
||||
|
||||
|
||||
inline void CmdLine::parse(int argc, const char * const * argv)
|
||||
{
|
||||
// this step is necessary so that we have easy access to
|
||||
// mutable strings.
|
||||
std::vector<std::string> args;
|
||||
for (int i = 0; i < argc; i++)
|
||||
args.push_back(argv[i]);
|
||||
|
||||
parse(args);
|
||||
}
|
||||
|
||||
inline void CmdLine::parse(std::vector<std::string>& args)
|
||||
{
|
||||
bool shouldExit = false;
|
||||
int estat = 0;
|
||||
|
||||
try {
|
||||
_progName = args.front();
|
||||
args.erase(args.begin());
|
||||
|
||||
int requiredCount = 0;
|
||||
|
||||
for (int i = 0; static_cast<unsigned int>(i) < args.size(); i++)
|
||||
{
|
||||
bool matched = false;
|
||||
for (ArgListIterator it = _argList.begin();
|
||||
it != _argList.end(); it++) {
|
||||
if ( (*it)->processArg( &i, args ) )
|
||||
{
|
||||
requiredCount += _xorHandler.check( *it );
|
||||
matched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// checks to see if the argument is an empty combined
|
||||
// switch and if so, then we've actually matched it
|
||||
if ( !matched && _emptyCombined( args[i] ) )
|
||||
matched = true;
|
||||
|
||||
if ( !matched && !Arg::ignoreRest() )
|
||||
throw(CmdLineParseException("Couldn't find match "
|
||||
"for argument",
|
||||
args[i]));
|
||||
}
|
||||
|
||||
if ( requiredCount < _numRequired )
|
||||
missingArgsException();
|
||||
|
||||
if ( requiredCount > _numRequired )
|
||||
throw(CmdLineParseException("Too many arguments!"));
|
||||
|
||||
} catch ( ArgException& e ) {
|
||||
// If we're not handling the exceptions, rethrow.
|
||||
if ( !_handleExceptions) {
|
||||
throw;
|
||||
}
|
||||
|
||||
try {
|
||||
_output->failure(*this,e);
|
||||
} catch ( ExitException &ee ) {
|
||||
estat = ee.getExitStatus();
|
||||
shouldExit = true;
|
||||
}
|
||||
} catch (ExitException &ee) {
|
||||
// If we're not handling the exceptions, rethrow.
|
||||
if ( !_handleExceptions) {
|
||||
throw;
|
||||
}
|
||||
|
||||
estat = ee.getExitStatus();
|
||||
shouldExit = true;
|
||||
}
|
||||
|
||||
if (shouldExit)
|
||||
exit(estat);
|
||||
}
|
||||
|
||||
inline bool CmdLine::_emptyCombined(const std::string& s)
|
||||
{
|
||||
if ( s.length() > 0 && s[0] != Arg::flagStartChar() )
|
||||
return false;
|
||||
|
||||
for ( int i = 1; static_cast<unsigned int>(i) < s.length(); i++ )
|
||||
if ( s[i] != Arg::blankChar() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline void CmdLine::missingArgsException()
|
||||
{
|
||||
int count = 0;
|
||||
|
||||
std::string missingArgList;
|
||||
for (ArgListIterator it = _argList.begin(); it != _argList.end(); it++)
|
||||
{
|
||||
if ( (*it)->isRequired() && !(*it)->isSet() )
|
||||
{
|
||||
missingArgList += (*it)->getName();
|
||||
missingArgList += ", ";
|
||||
count++;
|
||||
}
|
||||
}
|
||||
missingArgList = missingArgList.substr(0,missingArgList.length()-2);
|
||||
|
||||
std::string msg;
|
||||
if ( count > 1 )
|
||||
msg = "Required arguments missing: ";
|
||||
else
|
||||
msg = "Required argument missing: ";
|
||||
|
||||
msg += missingArgList;
|
||||
|
||||
throw(CmdLineParseException(msg));
|
||||
}
|
||||
|
||||
inline void CmdLine::deleteOnExit(Arg* ptr)
|
||||
{
|
||||
_argDeleteOnExitList.push_back(ptr);
|
||||
}
|
||||
|
||||
inline void CmdLine::deleteOnExit(Visitor* ptr)
|
||||
{
|
||||
_visitorDeleteOnExitList.push_back(ptr);
|
||||
}
|
||||
|
||||
inline CmdLineOutput* CmdLine::getOutput()
|
||||
{
|
||||
return _output;
|
||||
}
|
||||
|
||||
inline void CmdLine::setOutput(CmdLineOutput* co)
|
||||
{
|
||||
if ( !_userSetOutput )
|
||||
delete _output;
|
||||
_userSetOutput = true;
|
||||
_output = co;
|
||||
}
|
||||
|
||||
inline std::string& CmdLine::getVersion()
|
||||
{
|
||||
return _version;
|
||||
}
|
||||
|
||||
inline std::string& CmdLine::getProgramName()
|
||||
{
|
||||
return _progName;
|
||||
}
|
||||
|
||||
inline std::list<Arg*>& CmdLine::getArgList()
|
||||
{
|
||||
return _argList;
|
||||
}
|
||||
|
||||
inline XorHandler& CmdLine::getXorHandler()
|
||||
{
|
||||
return _xorHandler;
|
||||
}
|
||||
|
||||
inline char CmdLine::getDelimiter()
|
||||
{
|
||||
return _delimiter;
|
||||
}
|
||||
|
||||
inline std::string& CmdLine::getMessage()
|
||||
{
|
||||
return _message;
|
||||
}
|
||||
|
||||
inline bool CmdLine::hasHelpAndVersion()
|
||||
{
|
||||
return _helpAndVersion;
|
||||
}
|
||||
|
||||
inline void CmdLine::setExceptionHandling(const bool state)
|
||||
{
|
||||
_handleExceptions = state;
|
||||
}
|
||||
|
||||
inline bool CmdLine::getExceptionHandling() const
|
||||
{
|
||||
return _handleExceptions;
|
||||
}
|
||||
|
||||
inline void CmdLine::reset()
|
||||
{
|
||||
for( ArgListIterator it = _argList.begin(); it != _argList.end(); it++ )
|
||||
(*it)->reset();
|
||||
|
||||
_progName.clear();
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
//End CmdLine.cpp
|
||||
///////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
150
components/mkspiffs/src/tclap/CmdLineInterface.h
Normal file
150
components/mkspiffs/src/tclap/CmdLineInterface.h
Normal file
@ -0,0 +1,150 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: CmdLineInterface.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_COMMANDLINE_INTERFACE_H
|
||||
#define TCLAP_COMMANDLINE_INTERFACE_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
class Arg;
|
||||
class CmdLineOutput;
|
||||
class XorHandler;
|
||||
|
||||
/**
|
||||
* The base class that manages the command line definition and passes
|
||||
* along the parsing to the appropriate Arg classes.
|
||||
*/
|
||||
class CmdLineInterface
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Destructor
|
||||
*/
|
||||
virtual ~CmdLineInterface() {}
|
||||
|
||||
/**
|
||||
* Adds an argument to the list of arguments to be parsed.
|
||||
* \param a - Argument to be added.
|
||||
*/
|
||||
virtual void add( Arg& a )=0;
|
||||
|
||||
/**
|
||||
* An alternative add. Functionally identical.
|
||||
* \param a - Argument to be added.
|
||||
*/
|
||||
virtual void add( Arg* a )=0;
|
||||
|
||||
/**
|
||||
* Add two Args that will be xor'd.
|
||||
* If this method is used, add does
|
||||
* not need to be called.
|
||||
* \param a - Argument to be added and xor'd.
|
||||
* \param b - Argument to be added and xor'd.
|
||||
*/
|
||||
virtual void xorAdd( Arg& a, Arg& b )=0;
|
||||
|
||||
/**
|
||||
* Add a list of Args that will be xor'd. If this method is used,
|
||||
* add does not need to be called.
|
||||
* \param xors - List of Args to be added and xor'd.
|
||||
*/
|
||||
virtual void xorAdd( std::vector<Arg*>& xors )=0;
|
||||
|
||||
/**
|
||||
* Parses the command line.
|
||||
* \param argc - Number of arguments.
|
||||
* \param argv - Array of arguments.
|
||||
*/
|
||||
virtual void parse(int argc, const char * const * argv)=0;
|
||||
|
||||
/**
|
||||
* Parses the command line.
|
||||
* \param args - A vector of strings representing the args.
|
||||
* args[0] is still the program name.
|
||||
*/
|
||||
void parse(std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Returns the CmdLineOutput object.
|
||||
*/
|
||||
virtual CmdLineOutput* getOutput()=0;
|
||||
|
||||
/**
|
||||
* \param co - CmdLineOutput object that we want to use instead.
|
||||
*/
|
||||
virtual void setOutput(CmdLineOutput* co)=0;
|
||||
|
||||
/**
|
||||
* Returns the version string.
|
||||
*/
|
||||
virtual std::string& getVersion()=0;
|
||||
|
||||
/**
|
||||
* Returns the program name string.
|
||||
*/
|
||||
virtual std::string& getProgramName()=0;
|
||||
|
||||
/**
|
||||
* Returns the argList.
|
||||
*/
|
||||
virtual std::list<Arg*>& getArgList()=0;
|
||||
|
||||
/**
|
||||
* Returns the XorHandler.
|
||||
*/
|
||||
virtual XorHandler& getXorHandler()=0;
|
||||
|
||||
/**
|
||||
* Returns the delimiter string.
|
||||
*/
|
||||
virtual char getDelimiter()=0;
|
||||
|
||||
/**
|
||||
* Returns the message string.
|
||||
*/
|
||||
virtual std::string& getMessage()=0;
|
||||
|
||||
/**
|
||||
* Indicates whether or not the help and version switches were created
|
||||
* automatically.
|
||||
*/
|
||||
virtual bool hasHelpAndVersion()=0;
|
||||
|
||||
/**
|
||||
* Resets the instance as if it had just been constructed so that the
|
||||
* instance can be reused.
|
||||
*/
|
||||
virtual void reset()=0;
|
||||
};
|
||||
|
||||
} //namespace
|
||||
|
||||
|
||||
#endif
|
74
components/mkspiffs/src/tclap/CmdLineOutput.h
Normal file
74
components/mkspiffs/src/tclap/CmdLineOutput.h
Normal file
@ -0,0 +1,74 @@
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: CmdLineOutput.h
|
||||
*
|
||||
* Copyright (c) 2004, Michael E. Smoot
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_CMDLINEOUTPUT_H
|
||||
#define TCLAP_CMDLINEOUTPUT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
class CmdLineInterface;
|
||||
class ArgException;
|
||||
|
||||
/**
|
||||
* The interface that any output object must implement.
|
||||
*/
|
||||
class CmdLineOutput
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~CmdLineOutput() {}
|
||||
|
||||
/**
|
||||
* Generates some sort of output for the USAGE.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void usage(CmdLineInterface& c)=0;
|
||||
|
||||
/**
|
||||
* Generates some sort of output for the version.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void version(CmdLineInterface& c)=0;
|
||||
|
||||
/**
|
||||
* Generates some sort of output for a failure.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
* \param e - The ArgException that caused the failure.
|
||||
*/
|
||||
virtual void failure( CmdLineInterface& c,
|
||||
ArgException& e )=0;
|
||||
|
||||
};
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
68
components/mkspiffs/src/tclap/Constraint.h
Normal file
68
components/mkspiffs/src/tclap/Constraint.h
Normal file
@ -0,0 +1,68 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: Constraint.h
|
||||
*
|
||||
* Copyright (c) 2005, Michael E. Smoot
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_CONSTRAINT_H
|
||||
#define TCLAP_CONSTRAINT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <iomanip>
|
||||
#include <algorithm>
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* The interface that defines the interaction between the Arg and Constraint.
|
||||
*/
|
||||
template<class T>
|
||||
class Constraint
|
||||
{
|
||||
|
||||
public:
|
||||
/**
|
||||
* Returns a description of the Constraint.
|
||||
*/
|
||||
virtual std::string description() const =0;
|
||||
|
||||
/**
|
||||
* Returns the short ID for the Constraint.
|
||||
*/
|
||||
virtual std::string shortID() const =0;
|
||||
|
||||
/**
|
||||
* The method used to verify that the value parsed from the command
|
||||
* line meets the constraint.
|
||||
* \param value - The value that will be checked.
|
||||
*/
|
||||
virtual bool check(const T& value) const =0;
|
||||
|
||||
/**
|
||||
* Destructor.
|
||||
* Silences warnings about Constraint being a base class with virtual
|
||||
* functions but without a virtual destructor.
|
||||
*/
|
||||
virtual ~Constraint() { ; }
|
||||
};
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
299
components/mkspiffs/src/tclap/DocBookOutput.h
Normal file
299
components/mkspiffs/src/tclap/DocBookOutput.h
Normal file
@ -0,0 +1,299 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: DocBookOutput.h
|
||||
*
|
||||
* Copyright (c) 2004, Michael E. Smoot
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_DOCBOOKOUTPUT_H
|
||||
#define TCLAP_DOCBOOKOUTPUT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "CmdLineInterface.h"
|
||||
#include "CmdLineOutput.h"
|
||||
#include "XorHandler.h"
|
||||
#include "Arg.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A class that generates DocBook output for usage() method for the
|
||||
* given CmdLine and its Args.
|
||||
*/
|
||||
class DocBookOutput : public CmdLineOutput
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Prints the usage to stdout. Can be overridden to
|
||||
* produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void usage(CmdLineInterface& c);
|
||||
|
||||
/**
|
||||
* Prints the version to stdout. Can be overridden
|
||||
* to produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void version(CmdLineInterface& c);
|
||||
|
||||
/**
|
||||
* Prints (to stderr) an error message, short usage
|
||||
* Can be overridden to produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
* \param e - The ArgException that caused the failure.
|
||||
*/
|
||||
virtual void failure(CmdLineInterface& c,
|
||||
ArgException& e );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Substitutes the char r for string x in string s.
|
||||
* \param s - The string to operate on.
|
||||
* \param r - The char to replace.
|
||||
* \param x - What to replace r with.
|
||||
*/
|
||||
void substituteSpecialChars( std::string& s, char r, std::string& x );
|
||||
void removeChar( std::string& s, char r);
|
||||
void basename( std::string& s );
|
||||
|
||||
void printShortArg(Arg* it);
|
||||
void printLongArg(Arg* it);
|
||||
|
||||
char theDelimiter;
|
||||
};
|
||||
|
||||
|
||||
inline void DocBookOutput::version(CmdLineInterface& _cmd)
|
||||
{
|
||||
std::cout << _cmd.getVersion() << std::endl;
|
||||
}
|
||||
|
||||
inline void DocBookOutput::usage(CmdLineInterface& _cmd )
|
||||
{
|
||||
std::list<Arg*> argList = _cmd.getArgList();
|
||||
std::string progName = _cmd.getProgramName();
|
||||
std::string xversion = _cmd.getVersion();
|
||||
theDelimiter = _cmd.getDelimiter();
|
||||
XorHandler xorHandler = _cmd.getXorHandler();
|
||||
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
|
||||
basename(progName);
|
||||
|
||||
std::cout << "<?xml version='1.0'?>" << std::endl;
|
||||
std::cout << "<!DOCTYPE refentry PUBLIC \"-//OASIS//DTD DocBook XML V4.2//EN\"" << std::endl;
|
||||
std::cout << "\t\"http://www.oasis-open.org/docbook/xml/4.2/docbookx.dtd\">" << std::endl << std::endl;
|
||||
|
||||
std::cout << "<refentry>" << std::endl;
|
||||
|
||||
std::cout << "<refmeta>" << std::endl;
|
||||
std::cout << "<refentrytitle>" << progName << "</refentrytitle>" << std::endl;
|
||||
std::cout << "<manvolnum>1</manvolnum>" << std::endl;
|
||||
std::cout << "</refmeta>" << std::endl;
|
||||
|
||||
std::cout << "<refnamediv>" << std::endl;
|
||||
std::cout << "<refname>" << progName << "</refname>" << std::endl;
|
||||
std::cout << "<refpurpose>" << _cmd.getMessage() << "</refpurpose>" << std::endl;
|
||||
std::cout << "</refnamediv>" << std::endl;
|
||||
|
||||
std::cout << "<refsynopsisdiv>" << std::endl;
|
||||
std::cout << "<cmdsynopsis>" << std::endl;
|
||||
|
||||
std::cout << "<command>" << progName << "</command>" << std::endl;
|
||||
|
||||
// xor
|
||||
for ( int i = 0; (unsigned int)i < xorList.size(); i++ )
|
||||
{
|
||||
std::cout << "<group choice='req'>" << std::endl;
|
||||
for ( ArgVectorIterator it = xorList[i].begin();
|
||||
it != xorList[i].end(); it++ )
|
||||
printShortArg((*it));
|
||||
|
||||
std::cout << "</group>" << std::endl;
|
||||
}
|
||||
|
||||
// rest of args
|
||||
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
|
||||
if ( !xorHandler.contains( (*it) ) )
|
||||
printShortArg((*it));
|
||||
|
||||
std::cout << "</cmdsynopsis>" << std::endl;
|
||||
std::cout << "</refsynopsisdiv>" << std::endl;
|
||||
|
||||
std::cout << "<refsect1>" << std::endl;
|
||||
std::cout << "<title>Description</title>" << std::endl;
|
||||
std::cout << "<para>" << std::endl;
|
||||
std::cout << _cmd.getMessage() << std::endl;
|
||||
std::cout << "</para>" << std::endl;
|
||||
std::cout << "</refsect1>" << std::endl;
|
||||
|
||||
std::cout << "<refsect1>" << std::endl;
|
||||
std::cout << "<title>Options</title>" << std::endl;
|
||||
|
||||
std::cout << "<variablelist>" << std::endl;
|
||||
|
||||
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
|
||||
printLongArg((*it));
|
||||
|
||||
std::cout << "</variablelist>" << std::endl;
|
||||
std::cout << "</refsect1>" << std::endl;
|
||||
|
||||
std::cout << "<refsect1>" << std::endl;
|
||||
std::cout << "<title>Version</title>" << std::endl;
|
||||
std::cout << "<para>" << std::endl;
|
||||
std::cout << xversion << std::endl;
|
||||
std::cout << "</para>" << std::endl;
|
||||
std::cout << "</refsect1>" << std::endl;
|
||||
|
||||
std::cout << "</refentry>" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
inline void DocBookOutput::failure( CmdLineInterface& _cmd,
|
||||
ArgException& e )
|
||||
{
|
||||
static_cast<void>(_cmd); // unused
|
||||
std::cout << e.what() << std::endl;
|
||||
throw ExitException(1);
|
||||
}
|
||||
|
||||
inline void DocBookOutput::substituteSpecialChars( std::string& s,
|
||||
char r,
|
||||
std::string& x )
|
||||
{
|
||||
size_t p;
|
||||
while ( (p = s.find_first_of(r)) != std::string::npos )
|
||||
{
|
||||
s.erase(p,1);
|
||||
s.insert(p,x);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DocBookOutput::removeChar( std::string& s, char r)
|
||||
{
|
||||
size_t p;
|
||||
while ( (p = s.find_first_of(r)) != std::string::npos )
|
||||
{
|
||||
s.erase(p,1);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DocBookOutput::basename( std::string& s )
|
||||
{
|
||||
size_t p = s.find_last_of('/');
|
||||
if ( p != std::string::npos )
|
||||
{
|
||||
s.erase(0, p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
inline void DocBookOutput::printShortArg(Arg* a)
|
||||
{
|
||||
std::string lt = "<";
|
||||
std::string gt = ">";
|
||||
|
||||
std::string id = a->shortID();
|
||||
substituteSpecialChars(id,'<',lt);
|
||||
substituteSpecialChars(id,'>',gt);
|
||||
removeChar(id,'[');
|
||||
removeChar(id,']');
|
||||
|
||||
std::string choice = "opt";
|
||||
if ( a->isRequired() )
|
||||
choice = "plain";
|
||||
|
||||
std::cout << "<arg choice='" << choice << '\'';
|
||||
if ( a->acceptsMultipleValues() )
|
||||
std::cout << " rep='repeat'";
|
||||
|
||||
|
||||
std::cout << '>';
|
||||
if ( !a->getFlag().empty() )
|
||||
std::cout << a->flagStartChar() << a->getFlag();
|
||||
else
|
||||
std::cout << a->nameStartString() << a->getName();
|
||||
if ( a->isValueRequired() )
|
||||
{
|
||||
std::string arg = a->shortID();
|
||||
removeChar(arg,'[');
|
||||
removeChar(arg,']');
|
||||
removeChar(arg,'<');
|
||||
removeChar(arg,'>');
|
||||
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
|
||||
std::cout << theDelimiter;
|
||||
std::cout << "<replaceable>" << arg << "</replaceable>";
|
||||
}
|
||||
std::cout << "</arg>" << std::endl;
|
||||
|
||||
}
|
||||
|
||||
inline void DocBookOutput::printLongArg(Arg* a)
|
||||
{
|
||||
std::string lt = "<";
|
||||
std::string gt = ">";
|
||||
|
||||
std::string desc = a->getDescription();
|
||||
substituteSpecialChars(desc,'<',lt);
|
||||
substituteSpecialChars(desc,'>',gt);
|
||||
|
||||
std::cout << "<varlistentry>" << std::endl;
|
||||
|
||||
if ( !a->getFlag().empty() )
|
||||
{
|
||||
std::cout << "<term>" << std::endl;
|
||||
std::cout << "<option>";
|
||||
std::cout << a->flagStartChar() << a->getFlag();
|
||||
std::cout << "</option>" << std::endl;
|
||||
std::cout << "</term>" << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "<term>" << std::endl;
|
||||
std::cout << "<option>";
|
||||
std::cout << a->nameStartString() << a->getName();
|
||||
if ( a->isValueRequired() )
|
||||
{
|
||||
std::string arg = a->shortID();
|
||||
removeChar(arg,'[');
|
||||
removeChar(arg,']');
|
||||
removeChar(arg,'<');
|
||||
removeChar(arg,'>');
|
||||
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
|
||||
std::cout << theDelimiter;
|
||||
std::cout << "<replaceable>" << arg << "</replaceable>";
|
||||
}
|
||||
std::cout << "</option>" << std::endl;
|
||||
std::cout << "</term>" << std::endl;
|
||||
|
||||
std::cout << "<listitem>" << std::endl;
|
||||
std::cout << "<para>" << std::endl;
|
||||
std::cout << desc << std::endl;
|
||||
std::cout << "</para>" << std::endl;
|
||||
std::cout << "</listitem>" << std::endl;
|
||||
|
||||
std::cout << "</varlistentry>" << std::endl;
|
||||
}
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
76
components/mkspiffs/src/tclap/HelpVisitor.h
Normal file
76
components/mkspiffs/src/tclap/HelpVisitor.h
Normal file
@ -0,0 +1,76 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: HelpVisitor.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_HELP_VISITOR_H
|
||||
#define TCLAP_HELP_VISITOR_H
|
||||
|
||||
#include "CmdLineInterface.h"
|
||||
#include "CmdLineOutput.h"
|
||||
#include "Visitor.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A Visitor object that calls the usage method of the given CmdLineOutput
|
||||
* object for the specified CmdLine object.
|
||||
*/
|
||||
class HelpVisitor: public Visitor
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Prevent accidental copying.
|
||||
*/
|
||||
HelpVisitor(const HelpVisitor& rhs);
|
||||
HelpVisitor& operator=(const HelpVisitor& rhs);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The CmdLine the output will be generated for.
|
||||
*/
|
||||
CmdLineInterface* _cmd;
|
||||
|
||||
/**
|
||||
* The output object.
|
||||
*/
|
||||
CmdLineOutput** _out;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param cmd - The CmdLine the output will be generated for.
|
||||
* \param out - The type of output.
|
||||
*/
|
||||
HelpVisitor(CmdLineInterface* cmd, CmdLineOutput** out)
|
||||
: Visitor(), _cmd( cmd ), _out( out ) { }
|
||||
|
||||
/**
|
||||
* Calls the usage method of the CmdLineOutput for the
|
||||
* specified CmdLine.
|
||||
*/
|
||||
void visit() { (*_out)->usage(*_cmd); throw ExitException(0); }
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
52
components/mkspiffs/src/tclap/IgnoreRestVisitor.h
Normal file
52
components/mkspiffs/src/tclap/IgnoreRestVisitor.h
Normal file
@ -0,0 +1,52 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: IgnoreRestVisitor.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_IGNORE_REST_VISITOR_H
|
||||
#define TCLAP_IGNORE_REST_VISITOR_H
|
||||
|
||||
#include "Visitor.h"
|
||||
#include "Arg.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A Vistor that tells the CmdLine to begin ignoring arguments after
|
||||
* this one is parsed.
|
||||
*/
|
||||
class IgnoreRestVisitor: public Visitor
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*/
|
||||
IgnoreRestVisitor() : Visitor() {}
|
||||
|
||||
/**
|
||||
* Sets Arg::_ignoreRest.
|
||||
*/
|
||||
void visit() { Arg::beginIgnoring(); }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
433
components/mkspiffs/src/tclap/MultiArg.h
Normal file
433
components/mkspiffs/src/tclap/MultiArg.h
Normal file
@ -0,0 +1,433 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: MultiArg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_MULTIPLE_ARGUMENT_H
|
||||
#define TCLAP_MULTIPLE_ARGUMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Arg.h"
|
||||
#include "Constraint.h"
|
||||
|
||||
namespace TCLAP {
|
||||
/**
|
||||
* An argument that allows multiple values of type T to be specified. Very
|
||||
* similar to a ValueArg, except a vector of values will be returned
|
||||
* instead of just one.
|
||||
*/
|
||||
template<class T>
|
||||
class MultiArg : public Arg
|
||||
{
|
||||
public:
|
||||
typedef std::vector<T> container_type;
|
||||
typedef typename container_type::iterator iterator;
|
||||
typedef typename container_type::const_iterator const_iterator;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The list of values parsed from the CmdLine.
|
||||
*/
|
||||
std::vector<T> _values;
|
||||
|
||||
/**
|
||||
* The description of type T to be used in the usage.
|
||||
*/
|
||||
std::string _typeDesc;
|
||||
|
||||
/**
|
||||
* A list of constraint on this Arg.
|
||||
*/
|
||||
Constraint<T>* _constraint;
|
||||
|
||||
/**
|
||||
* Extracts the value from the string.
|
||||
* Attempts to parse string as type T, if this fails an exception
|
||||
* is thrown.
|
||||
* \param val - The string to be read.
|
||||
*/
|
||||
void _extractValue( const std::string& val );
|
||||
|
||||
/**
|
||||
* Used by XorHandler to decide whether to keep parsing for this arg.
|
||||
*/
|
||||
bool _allowMore;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
Visitor* v = NULL);
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately. It knows the difference
|
||||
* between labeled and unlabeled.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Returns a vector of type T containing the values parsed from
|
||||
* the command line.
|
||||
*/
|
||||
const std::vector<T>& getValue();
|
||||
|
||||
/**
|
||||
* Returns an iterator over the values parsed from the command
|
||||
* line.
|
||||
*/
|
||||
const_iterator begin() const { return _values.begin(); }
|
||||
|
||||
/**
|
||||
* Returns the end of the values parsed from the command
|
||||
* line.
|
||||
*/
|
||||
const_iterator end() const { return _values.end(); }
|
||||
|
||||
/**
|
||||
* Returns the a short id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string shortID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Returns the a long id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string longID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Once we've matched the first value, then the arg is no longer
|
||||
* required.
|
||||
*/
|
||||
virtual bool isRequired() const;
|
||||
|
||||
virtual bool allowMore();
|
||||
|
||||
virtual void reset();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Prevent accidental copying
|
||||
*/
|
||||
MultiArg<T>(const MultiArg<T>& rhs);
|
||||
MultiArg<T>& operator=(const MultiArg<T>& rhs);
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
MultiArg<T>::MultiArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
Visitor* v) :
|
||||
Arg( flag, name, desc, req, true, v ),
|
||||
_values(std::vector<T>()),
|
||||
_typeDesc( typeDesc ),
|
||||
_constraint( NULL ),
|
||||
_allowMore(false)
|
||||
{
|
||||
_acceptsMultipleValues = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
MultiArg<T>::MultiArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v)
|
||||
: Arg( flag, name, desc, req, true, v ),
|
||||
_values(std::vector<T>()),
|
||||
_typeDesc( typeDesc ),
|
||||
_constraint( NULL ),
|
||||
_allowMore(false)
|
||||
{
|
||||
parser.add( this );
|
||||
_acceptsMultipleValues = true;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template<class T>
|
||||
MultiArg<T>::MultiArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
Visitor* v)
|
||||
: Arg( flag, name, desc, req, true, v ),
|
||||
_values(std::vector<T>()),
|
||||
_typeDesc( constraint->shortID() ),
|
||||
_constraint( constraint ),
|
||||
_allowMore(false)
|
||||
{
|
||||
_acceptsMultipleValues = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
MultiArg<T>::MultiArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v)
|
||||
: Arg( flag, name, desc, req, true, v ),
|
||||
_values(std::vector<T>()),
|
||||
_typeDesc( constraint->shortID() ),
|
||||
_constraint( constraint ),
|
||||
_allowMore(false)
|
||||
{
|
||||
parser.add( this );
|
||||
_acceptsMultipleValues = true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
const std::vector<T>& MultiArg<T>::getValue() { return _values; }
|
||||
|
||||
template<class T>
|
||||
bool MultiArg<T>::processArg(int *i, std::vector<std::string>& args)
|
||||
{
|
||||
if ( _ignoreable && Arg::ignoreRest() )
|
||||
return false;
|
||||
|
||||
if ( _hasBlanks( args[*i] ) )
|
||||
return false;
|
||||
|
||||
std::string flag = args[*i];
|
||||
std::string value = "";
|
||||
|
||||
trimFlag( flag, value );
|
||||
|
||||
if ( argMatches( flag ) )
|
||||
{
|
||||
if ( Arg::delimiter() != ' ' && value == "" )
|
||||
throw( ArgParseException(
|
||||
"Couldn't find delimiter for this argument!",
|
||||
toString() ) );
|
||||
|
||||
// always take the first one, regardless of start string
|
||||
if ( value == "" )
|
||||
{
|
||||
(*i)++;
|
||||
if ( static_cast<unsigned int>(*i) < args.size() )
|
||||
_extractValue( args[*i] );
|
||||
else
|
||||
throw( ArgParseException("Missing a value for this argument!",
|
||||
toString() ) );
|
||||
}
|
||||
else
|
||||
_extractValue( value );
|
||||
|
||||
/*
|
||||
// continuing taking the args until we hit one with a start string
|
||||
while ( (unsigned int)(*i)+1 < args.size() &&
|
||||
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
|
||||
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
|
||||
_extractValue( args[++(*i)] );
|
||||
*/
|
||||
|
||||
_alreadySet = true;
|
||||
_checkWithVisitor();
|
||||
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template<class T>
|
||||
std::string MultiArg<T>::shortID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return Arg::shortID(_typeDesc) + " ... ";
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
template<class T>
|
||||
std::string MultiArg<T>::longID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return Arg::longID(_typeDesc) + " (accepted multiple times)";
|
||||
}
|
||||
|
||||
/**
|
||||
* Once we've matched the first value, then the arg is no longer
|
||||
* required.
|
||||
*/
|
||||
template<class T>
|
||||
bool MultiArg<T>::isRequired() const
|
||||
{
|
||||
if ( _required )
|
||||
{
|
||||
if ( _values.size() > 1 )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void MultiArg<T>::_extractValue( const std::string& val )
|
||||
{
|
||||
try {
|
||||
T tmp;
|
||||
ExtractValue(tmp, val, typename ArgTraits<T>::ValueCategory());
|
||||
_values.push_back(tmp);
|
||||
} catch( ArgParseException &e) {
|
||||
throw ArgParseException(e.error(), toString());
|
||||
}
|
||||
|
||||
if ( _constraint != NULL )
|
||||
if ( ! _constraint->check( _values.back() ) )
|
||||
throw( CmdLineParseException( "Value '" + val +
|
||||
"' does not meet constraint: " +
|
||||
_constraint->description(),
|
||||
toString() ) );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool MultiArg<T>::allowMore()
|
||||
{
|
||||
bool am = _allowMore;
|
||||
_allowMore = true;
|
||||
return am;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void MultiArg<T>::reset()
|
||||
{
|
||||
Arg::reset();
|
||||
_values.clear();
|
||||
}
|
||||
|
||||
} // namespace TCLAP
|
||||
|
||||
#endif
|
216
components/mkspiffs/src/tclap/MultiSwitchArg.h
Normal file
216
components/mkspiffs/src/tclap/MultiSwitchArg.h
Normal file
@ -0,0 +1,216 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: MultiSwitchArg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* Copyright (c) 2005, Michael E. Smoot, Daniel Aarno, Erik Zeek.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_MULTI_SWITCH_ARG_H
|
||||
#define TCLAP_MULTI_SWITCH_ARG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "SwitchArg.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A multiple switch argument. If the switch is set on the command line, then
|
||||
* the getValue method will return the number of times the switch appears.
|
||||
*/
|
||||
class MultiSwitchArg : public SwitchArg
|
||||
{
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The value of the switch.
|
||||
*/
|
||||
int _value;
|
||||
|
||||
/**
|
||||
* Used to support the reset() method so that ValueArg can be
|
||||
* reset to their constructed value.
|
||||
*/
|
||||
int _default;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* MultiSwitchArg constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param init - Optional. The initial/default value of this Arg.
|
||||
* Defaults to 0.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiSwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
int init = 0,
|
||||
Visitor* v = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* MultiSwitchArg constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param init - Optional. The initial/default value of this Arg.
|
||||
* Defaults to 0.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
MultiSwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
CmdLineInterface& parser,
|
||||
int init = 0,
|
||||
Visitor* v = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the SwitchArg version of this method to set the
|
||||
* _value of the argument appropriately.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed
|
||||
* in from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Returns int, the number of times the switch has been set.
|
||||
*/
|
||||
int getValue();
|
||||
|
||||
/**
|
||||
* Returns the shortID for this Arg.
|
||||
*/
|
||||
std::string shortID(const std::string& val) const;
|
||||
|
||||
/**
|
||||
* Returns the longID for this Arg.
|
||||
*/
|
||||
std::string longID(const std::string& val) const;
|
||||
|
||||
void reset();
|
||||
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//BEGIN MultiSwitchArg.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
int init,
|
||||
Visitor* v )
|
||||
: SwitchArg(flag, name, desc, false, v),
|
||||
_value( init ),
|
||||
_default( init )
|
||||
{ }
|
||||
|
||||
inline MultiSwitchArg::MultiSwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
CmdLineInterface& parser,
|
||||
int init,
|
||||
Visitor* v )
|
||||
: SwitchArg(flag, name, desc, false, v),
|
||||
_value( init ),
|
||||
_default( init )
|
||||
{
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
inline int MultiSwitchArg::getValue() { return _value; }
|
||||
|
||||
inline bool MultiSwitchArg::processArg(int *i, std::vector<std::string>& args)
|
||||
{
|
||||
if ( _ignoreable && Arg::ignoreRest() )
|
||||
return false;
|
||||
|
||||
if ( argMatches( args[*i] ))
|
||||
{
|
||||
// so the isSet() method will work
|
||||
_alreadySet = true;
|
||||
|
||||
// Matched argument: increment value.
|
||||
++_value;
|
||||
|
||||
_checkWithVisitor();
|
||||
|
||||
return true;
|
||||
}
|
||||
else if ( combinedSwitchesMatch( args[*i] ) )
|
||||
{
|
||||
// so the isSet() method will work
|
||||
_alreadySet = true;
|
||||
|
||||
// Matched argument: increment value.
|
||||
++_value;
|
||||
|
||||
// Check for more in argument and increment value.
|
||||
while ( combinedSwitchesMatch( args[*i] ) )
|
||||
++_value;
|
||||
|
||||
_checkWithVisitor();
|
||||
|
||||
return false;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::string
|
||||
MultiSwitchArg::shortID(const std::string& val) const
|
||||
{
|
||||
return Arg::shortID(val) + " ... ";
|
||||
}
|
||||
|
||||
inline std::string
|
||||
MultiSwitchArg::longID(const std::string& val) const
|
||||
{
|
||||
return Arg::longID(val) + " (accepted multiple times)";
|
||||
}
|
||||
|
||||
inline void
|
||||
MultiSwitchArg::reset()
|
||||
{
|
||||
MultiSwitchArg::_value = MultiSwitchArg::_default;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//END MultiSwitchArg.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} //namespace TCLAP
|
||||
|
||||
#endif
|
62
components/mkspiffs/src/tclap/OptionalUnlabeledTracker.h
Normal file
62
components/mkspiffs/src/tclap/OptionalUnlabeledTracker.h
Normal file
@ -0,0 +1,62 @@
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: OptionalUnlabeledTracker.h
|
||||
*
|
||||
* Copyright (c) 2005, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_OPTIONAL_UNLABELED_TRACKER_H
|
||||
#define TCLAP_OPTIONAL_UNLABELED_TRACKER_H
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
class OptionalUnlabeledTracker
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
static void check( bool req, const std::string& argName );
|
||||
|
||||
static void gotOptional() { alreadyOptionalRef() = true; }
|
||||
|
||||
static bool& alreadyOptional() { return alreadyOptionalRef(); }
|
||||
|
||||
private:
|
||||
|
||||
static bool& alreadyOptionalRef() { static bool ct = false; return ct; }
|
||||
};
|
||||
|
||||
|
||||
inline void OptionalUnlabeledTracker::check( bool req, const std::string& argName )
|
||||
{
|
||||
if ( OptionalUnlabeledTracker::alreadyOptional() )
|
||||
throw( SpecificationException(
|
||||
"You can't specify ANY Unlabeled Arg following an optional Unlabeled Arg",
|
||||
argName ) );
|
||||
|
||||
if ( !req )
|
||||
OptionalUnlabeledTracker::gotOptional();
|
||||
}
|
||||
|
||||
|
||||
} // namespace TCLAP
|
||||
|
||||
#endif
|
208
components/mkspiffs/src/tclap/StandardTraits.h
Normal file
208
components/mkspiffs/src/tclap/StandardTraits.h
Normal file
@ -0,0 +1,208 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: StandardTraits.h
|
||||
*
|
||||
* Copyright (c) 2007, Daniel Aarno, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
// This is an internal tclap file, you should probably not have to
|
||||
// include this directly
|
||||
|
||||
#ifndef TCLAP_STANDARD_TRAITS_H
|
||||
#define TCLAP_STANDARD_TRAITS_H
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h> // To check for long long
|
||||
#endif
|
||||
|
||||
// If Microsoft has already typedef'd wchar_t as an unsigned
|
||||
// short, then compiles will break because it's as if we're
|
||||
// creating ArgTraits twice for unsigned short. Thus...
|
||||
#ifdef _MSC_VER
|
||||
#ifndef _NATIVE_WCHAR_T_DEFINED
|
||||
#define TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
// ======================================================================
|
||||
// Integer types
|
||||
// ======================================================================
|
||||
|
||||
/**
|
||||
* longs have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<long> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* ints have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<int> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* shorts have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<short> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* chars have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<char> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
/**
|
||||
* long longs have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<long long> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
// Unsigned integer types
|
||||
// ======================================================================
|
||||
|
||||
/**
|
||||
* unsigned longs have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<unsigned long> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* unsigned ints have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<unsigned int> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* unsigned shorts have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<unsigned short> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* unsigned chars have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<unsigned char> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
// Microsoft implements size_t awkwardly.
|
||||
#if defined(_MSC_VER) && defined(_M_X64)
|
||||
/**
|
||||
* size_ts have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<size_t> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef HAVE_LONG_LONG
|
||||
/**
|
||||
* unsigned long longs have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<unsigned long long> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
#endif
|
||||
|
||||
// ======================================================================
|
||||
// Float types
|
||||
// ======================================================================
|
||||
|
||||
/**
|
||||
* floats have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<float> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
/**
|
||||
* doubles have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<double> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
// ======================================================================
|
||||
// Other types
|
||||
// ======================================================================
|
||||
|
||||
/**
|
||||
* bools have value-like semantics.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<bool> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* wchar_ts have value-like semantics.
|
||||
*/
|
||||
#ifndef TCLAP_DONT_DECLARE_WCHAR_T_ARGTRAITS
|
||||
template<>
|
||||
struct ArgTraits<wchar_t> {
|
||||
typedef ValueLike ValueCategory;
|
||||
};
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Strings have string like argument traits.
|
||||
*/
|
||||
template<>
|
||||
struct ArgTraits<std::string> {
|
||||
typedef StringLike ValueCategory;
|
||||
};
|
||||
|
||||
template<typename T>
|
||||
void SetString(T &dst, const std::string &src)
|
||||
{
|
||||
dst = src;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
#endif
|
||||
|
298
components/mkspiffs/src/tclap/StdOutput.h
Normal file
298
components/mkspiffs/src/tclap/StdOutput.h
Normal file
@ -0,0 +1,298 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: StdOutput.h
|
||||
*
|
||||
* Copyright (c) 2004, Michael E. Smoot
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_STDCMDLINEOUTPUT_H
|
||||
#define TCLAP_STDCMDLINEOUTPUT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
|
||||
#include "CmdLineInterface.h"
|
||||
#include "CmdLineOutput.h"
|
||||
#include "XorHandler.h"
|
||||
#include "Arg.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A class that isolates any output from the CmdLine object so that it
|
||||
* may be easily modified.
|
||||
*/
|
||||
class StdOutput : public CmdLineOutput
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Prints the usage to stdout. Can be overridden to
|
||||
* produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void usage(CmdLineInterface& c);
|
||||
|
||||
/**
|
||||
* Prints the version to stdout. Can be overridden
|
||||
* to produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void version(CmdLineInterface& c);
|
||||
|
||||
/**
|
||||
* Prints (to stderr) an error message, short usage
|
||||
* Can be overridden to produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
* \param e - The ArgException that caused the failure.
|
||||
*/
|
||||
virtual void failure(CmdLineInterface& c,
|
||||
ArgException& e );
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* Writes a brief usage message with short args.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
* \param os - The stream to write the message to.
|
||||
*/
|
||||
void _shortUsage( CmdLineInterface& c, std::ostream& os ) const;
|
||||
|
||||
/**
|
||||
* Writes a longer usage message with long and short args,
|
||||
* provides descriptions and prints message.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
* \param os - The stream to write the message to.
|
||||
*/
|
||||
void _longUsage( CmdLineInterface& c, std::ostream& os ) const;
|
||||
|
||||
/**
|
||||
* This function inserts line breaks and indents long strings
|
||||
* according the params input. It will only break lines at spaces,
|
||||
* commas and pipes.
|
||||
* \param os - The stream to be printed to.
|
||||
* \param s - The string to be printed.
|
||||
* \param maxWidth - The maxWidth allowed for the output line.
|
||||
* \param indentSpaces - The number of spaces to indent the first line.
|
||||
* \param secondLineOffset - The number of spaces to indent the second
|
||||
* and all subsequent lines in addition to indentSpaces.
|
||||
*/
|
||||
void spacePrint( std::ostream& os,
|
||||
const std::string& s,
|
||||
int maxWidth,
|
||||
int indentSpaces,
|
||||
int secondLineOffset ) const;
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline void StdOutput::version(CmdLineInterface& _cmd)
|
||||
{
|
||||
std::string progName = _cmd.getProgramName();
|
||||
std::string xversion = _cmd.getVersion();
|
||||
|
||||
std::cout << std::endl << progName << " version: "
|
||||
<< xversion << std::endl << std::endl;
|
||||
}
|
||||
|
||||
inline void StdOutput::usage(CmdLineInterface& _cmd )
|
||||
{
|
||||
std::cout << std::endl << "USAGE: " << std::endl << std::endl;
|
||||
|
||||
_shortUsage( _cmd, std::cout );
|
||||
|
||||
std::cout << std::endl << std::endl << "Where: " << std::endl << std::endl;
|
||||
|
||||
_longUsage( _cmd, std::cout );
|
||||
|
||||
std::cout << std::endl;
|
||||
|
||||
}
|
||||
|
||||
inline void StdOutput::failure( CmdLineInterface& _cmd,
|
||||
ArgException& e )
|
||||
{
|
||||
std::string progName = _cmd.getProgramName();
|
||||
|
||||
std::cerr << "PARSE ERROR: " << e.argId() << std::endl
|
||||
<< " " << e.error() << std::endl << std::endl;
|
||||
|
||||
if ( _cmd.hasHelpAndVersion() )
|
||||
{
|
||||
std::cerr << "Brief USAGE: " << std::endl;
|
||||
|
||||
_shortUsage( _cmd, std::cerr );
|
||||
|
||||
std::cerr << std::endl << "For complete USAGE and HELP type: "
|
||||
<< std::endl << " " << progName << " --help"
|
||||
<< std::endl << std::endl;
|
||||
}
|
||||
else
|
||||
usage(_cmd);
|
||||
|
||||
throw ExitException(1);
|
||||
}
|
||||
|
||||
inline void
|
||||
StdOutput::_shortUsage( CmdLineInterface& _cmd,
|
||||
std::ostream& os ) const
|
||||
{
|
||||
std::list<Arg*> argList = _cmd.getArgList();
|
||||
std::string progName = _cmd.getProgramName();
|
||||
XorHandler xorHandler = _cmd.getXorHandler();
|
||||
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
|
||||
|
||||
std::string s = progName + " ";
|
||||
|
||||
// first the xor
|
||||
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
|
||||
{
|
||||
s += " {";
|
||||
for ( ArgVectorIterator it = xorList[i].begin();
|
||||
it != xorList[i].end(); it++ )
|
||||
s += (*it)->shortID() + "|";
|
||||
|
||||
s[s.length()-1] = '}';
|
||||
}
|
||||
|
||||
// then the rest
|
||||
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
|
||||
if ( !xorHandler.contains( (*it) ) )
|
||||
s += " " + (*it)->shortID();
|
||||
|
||||
// if the program name is too long, then adjust the second line offset
|
||||
int secondLineOffset = static_cast<int>(progName.length()) + 2;
|
||||
if ( secondLineOffset > 75/2 )
|
||||
secondLineOffset = static_cast<int>(75/2);
|
||||
|
||||
spacePrint( os, s, 75, 3, secondLineOffset );
|
||||
}
|
||||
|
||||
inline void
|
||||
StdOutput::_longUsage( CmdLineInterface& _cmd,
|
||||
std::ostream& os ) const
|
||||
{
|
||||
std::list<Arg*> argList = _cmd.getArgList();
|
||||
std::string message = _cmd.getMessage();
|
||||
XorHandler xorHandler = _cmd.getXorHandler();
|
||||
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
|
||||
|
||||
// first the xor
|
||||
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
|
||||
{
|
||||
for ( ArgVectorIterator it = xorList[i].begin();
|
||||
it != xorList[i].end();
|
||||
it++ )
|
||||
{
|
||||
spacePrint( os, (*it)->longID(), 75, 3, 3 );
|
||||
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
|
||||
|
||||
if ( it+1 != xorList[i].end() )
|
||||
spacePrint(os, "-- OR --", 75, 9, 0);
|
||||
}
|
||||
os << std::endl << std::endl;
|
||||
}
|
||||
|
||||
// then the rest
|
||||
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
|
||||
if ( !xorHandler.contains( (*it) ) )
|
||||
{
|
||||
spacePrint( os, (*it)->longID(), 75, 3, 3 );
|
||||
spacePrint( os, (*it)->getDescription(), 75, 5, 0 );
|
||||
os << std::endl;
|
||||
}
|
||||
|
||||
os << std::endl;
|
||||
|
||||
spacePrint( os, message, 75, 3, 0 );
|
||||
}
|
||||
|
||||
inline void StdOutput::spacePrint( std::ostream& os,
|
||||
const std::string& s,
|
||||
int maxWidth,
|
||||
int indentSpaces,
|
||||
int secondLineOffset ) const
|
||||
{
|
||||
int len = static_cast<int>(s.length());
|
||||
|
||||
if ( (len + indentSpaces > maxWidth) && maxWidth > 0 )
|
||||
{
|
||||
int allowedLen = maxWidth - indentSpaces;
|
||||
int start = 0;
|
||||
while ( start < len )
|
||||
{
|
||||
// find the substring length
|
||||
// int stringLen = std::min<int>( len - start, allowedLen );
|
||||
// doing it this way to support a VisualC++ 2005 bug
|
||||
using namespace std;
|
||||
int stringLen = min<int>( len - start, allowedLen );
|
||||
|
||||
// trim the length so it doesn't end in middle of a word
|
||||
if ( stringLen == allowedLen )
|
||||
while ( stringLen >= 0 &&
|
||||
s[stringLen+start] != ' ' &&
|
||||
s[stringLen+start] != ',' &&
|
||||
s[stringLen+start] != '|' )
|
||||
stringLen--;
|
||||
|
||||
// ok, the word is longer than the line, so just split
|
||||
// wherever the line ends
|
||||
if ( stringLen <= 0 )
|
||||
stringLen = allowedLen;
|
||||
|
||||
// check for newlines
|
||||
for ( int i = 0; i < stringLen; i++ )
|
||||
if ( s[start+i] == '\n' )
|
||||
stringLen = i+1;
|
||||
|
||||
// print the indent
|
||||
for ( int i = 0; i < indentSpaces; i++ )
|
||||
os << " ";
|
||||
|
||||
if ( start == 0 )
|
||||
{
|
||||
// handle second line offsets
|
||||
indentSpaces += secondLineOffset;
|
||||
|
||||
// adjust allowed len
|
||||
allowedLen -= secondLineOffset;
|
||||
}
|
||||
|
||||
os << s.substr(start,stringLen) << std::endl;
|
||||
|
||||
// so we don't start a line with a space
|
||||
while ( s[stringLen+start] == ' ' && start < len )
|
||||
start++;
|
||||
|
||||
start += stringLen;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for ( int i = 0; i < indentSpaces; i++ )
|
||||
os << " ";
|
||||
os << s << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
266
components/mkspiffs/src/tclap/SwitchArg.h
Normal file
266
components/mkspiffs/src/tclap/SwitchArg.h
Normal file
@ -0,0 +1,266 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: SwitchArg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_SWITCH_ARG_H
|
||||
#define TCLAP_SWITCH_ARG_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Arg.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A simple switch argument. If the switch is set on the command line, then
|
||||
* the getValue method will return the opposite of the default value for the
|
||||
* switch.
|
||||
*/
|
||||
class SwitchArg : public Arg
|
||||
{
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The value of the switch.
|
||||
*/
|
||||
bool _value;
|
||||
|
||||
/**
|
||||
* Used to support the reset() method so that ValueArg can be
|
||||
* reset to their constructed value.
|
||||
*/
|
||||
bool _default;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* SwitchArg constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param def - The default value for this Switch.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
SwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool def = false,
|
||||
Visitor* v = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* SwitchArg constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param def - The default value for this Switch.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
SwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
CmdLineInterface& parser,
|
||||
bool def = false,
|
||||
Visitor* v = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed
|
||||
* in from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Checks a string to see if any of the chars in the string
|
||||
* match the flag for this Switch.
|
||||
*/
|
||||
bool combinedSwitchesMatch(std::string& combined);
|
||||
|
||||
/**
|
||||
* Returns bool, whether or not the switch has been set.
|
||||
*/
|
||||
bool getValue();
|
||||
|
||||
virtual void reset();
|
||||
|
||||
private:
|
||||
/**
|
||||
* Checks to see if we've found the last match in
|
||||
* a combined string.
|
||||
*/
|
||||
bool lastCombined(std::string& combined);
|
||||
|
||||
/**
|
||||
* Does the common processing of processArg.
|
||||
*/
|
||||
void commonProcessing();
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//BEGIN SwitchArg.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
inline SwitchArg::SwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool default_val,
|
||||
Visitor* v )
|
||||
: Arg(flag, name, desc, false, false, v),
|
||||
_value( default_val ),
|
||||
_default( default_val )
|
||||
{ }
|
||||
|
||||
inline SwitchArg::SwitchArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
CmdLineInterface& parser,
|
||||
bool default_val,
|
||||
Visitor* v )
|
||||
: Arg(flag, name, desc, false, false, v),
|
||||
_value( default_val ),
|
||||
_default(default_val)
|
||||
{
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
inline bool SwitchArg::getValue() { return _value; }
|
||||
|
||||
inline bool SwitchArg::lastCombined(std::string& combinedSwitches )
|
||||
{
|
||||
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
|
||||
if ( combinedSwitches[i] != Arg::blankChar() )
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline bool SwitchArg::combinedSwitchesMatch(std::string& combinedSwitches )
|
||||
{
|
||||
// make sure this is actually a combined switch
|
||||
if ( combinedSwitches.length() > 0 &&
|
||||
combinedSwitches[0] != Arg::flagStartString()[0] )
|
||||
return false;
|
||||
|
||||
// make sure it isn't a long name
|
||||
if ( combinedSwitches.substr( 0, Arg::nameStartString().length() ) ==
|
||||
Arg::nameStartString() )
|
||||
return false;
|
||||
|
||||
// make sure the delimiter isn't in the string
|
||||
if ( combinedSwitches.find_first_of( Arg::delimiter() ) != std::string::npos )
|
||||
return false;
|
||||
|
||||
// ok, we're not specifying a ValueArg, so we know that we have
|
||||
// a combined switch list.
|
||||
for ( unsigned int i = 1; i < combinedSwitches.length(); i++ )
|
||||
if ( _flag.length() > 0 &&
|
||||
combinedSwitches[i] == _flag[0] &&
|
||||
_flag[0] != Arg::flagStartString()[0] )
|
||||
{
|
||||
// update the combined switches so this one is no longer present
|
||||
// this is necessary so that no unlabeled args are matched
|
||||
// later in the processing.
|
||||
//combinedSwitches.erase(i,1);
|
||||
combinedSwitches[i] = Arg::blankChar();
|
||||
return true;
|
||||
}
|
||||
|
||||
// none of the switches passed in the list match.
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void SwitchArg::commonProcessing()
|
||||
{
|
||||
if ( _xorSet )
|
||||
throw(CmdLineParseException(
|
||||
"Mutually exclusive argument already set!", toString()));
|
||||
|
||||
if ( _alreadySet )
|
||||
throw(CmdLineParseException("Argument already set!", toString()));
|
||||
|
||||
_alreadySet = true;
|
||||
|
||||
if ( _value == true )
|
||||
_value = false;
|
||||
else
|
||||
_value = true;
|
||||
|
||||
_checkWithVisitor();
|
||||
}
|
||||
|
||||
inline bool SwitchArg::processArg(int *i, std::vector<std::string>& args)
|
||||
{
|
||||
if ( _ignoreable && Arg::ignoreRest() )
|
||||
return false;
|
||||
|
||||
// if the whole string matches the flag or name string
|
||||
if ( argMatches( args[*i] ) )
|
||||
{
|
||||
commonProcessing();
|
||||
|
||||
return true;
|
||||
}
|
||||
// if a substring matches the flag as part of a combination
|
||||
else if ( combinedSwitchesMatch( args[*i] ) )
|
||||
{
|
||||
// check again to ensure we don't misinterpret
|
||||
// this as a MultiSwitchArg
|
||||
if ( combinedSwitchesMatch( args[*i] ) )
|
||||
throw(CmdLineParseException("Argument already set!",
|
||||
toString()));
|
||||
|
||||
commonProcessing();
|
||||
|
||||
// We only want to return true if we've found the last combined
|
||||
// match in the string, otherwise we return true so that other
|
||||
// switches in the combination will have a chance to match.
|
||||
return lastCombined( args[*i] );
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline void SwitchArg::reset()
|
||||
{
|
||||
Arg::reset();
|
||||
_value = _default;
|
||||
}
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//End SwitchArg.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} //namespace TCLAP
|
||||
|
||||
#endif
|
301
components/mkspiffs/src/tclap/UnlabeledMultiArg.h
Normal file
301
components/mkspiffs/src/tclap/UnlabeledMultiArg.h
Normal file
@ -0,0 +1,301 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: UnlabeledMultiArg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H
|
||||
#define TCLAP_MULTIPLE_UNLABELED_ARGUMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "MultiArg.h"
|
||||
#include "OptionalUnlabeledTracker.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* Just like a MultiArg, except that the arguments are unlabeled. Basically,
|
||||
* this Arg will slurp up everything that hasn't been matched to another
|
||||
* Arg.
|
||||
*/
|
||||
template<class T>
|
||||
class UnlabeledMultiArg : public MultiArg<T>
|
||||
{
|
||||
|
||||
// If compiler has two stage name lookup (as gcc >= 3.4 does)
|
||||
// this is requried to prevent undef. symbols
|
||||
using MultiArg<T>::_ignoreable;
|
||||
using MultiArg<T>::_hasBlanks;
|
||||
using MultiArg<T>::_extractValue;
|
||||
using MultiArg<T>::_typeDesc;
|
||||
using MultiArg<T>::_name;
|
||||
using MultiArg<T>::_description;
|
||||
using MultiArg<T>::_alreadySet;
|
||||
using MultiArg<T>::toString;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param name - The name of the Arg. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param ignoreable - Whether or not this argument can be ignored
|
||||
* using the "--" flag.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
UnlabeledMultiArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL );
|
||||
/**
|
||||
* Constructor.
|
||||
* \param name - The name of the Arg. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param ignoreable - Whether or not this argument can be ignored
|
||||
* using the "--" flag.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
UnlabeledMultiArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param name - The name of the Arg. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param ignoreable - Whether or not this argument can be ignored
|
||||
* using the "--" flag.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
UnlabeledMultiArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param name - The name of the Arg. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param ignoreable - Whether or not this argument can be ignored
|
||||
* using the "--" flag.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
UnlabeledMultiArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately. It knows the difference
|
||||
* between labeled and unlabeled.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Returns the a short id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string shortID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Returns the a long id string. Used in the usage.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string longID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Opertor ==.
|
||||
* \param a - The Arg to be compared to this.
|
||||
*/
|
||||
virtual bool operator==(const Arg& a) const;
|
||||
|
||||
/**
|
||||
* Pushes this to back of list rather than front.
|
||||
* \param argList - The list this should be added to.
|
||||
*/
|
||||
virtual void addToList( std::list<Arg*>& argList ) const;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: MultiArg<T>("", name, desc, req, typeDesc, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(true, toString());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: MultiArg<T>("", name, desc, req, typeDesc, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(true, toString());
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: MultiArg<T>("", name, desc, req, constraint, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(true, toString());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UnlabeledMultiArg<T>::UnlabeledMultiArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: MultiArg<T>("", name, desc, req, constraint, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(true, toString());
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
|
||||
template<class T>
|
||||
bool UnlabeledMultiArg<T>::processArg(int *i, std::vector<std::string>& args)
|
||||
{
|
||||
|
||||
if ( _hasBlanks( args[*i] ) )
|
||||
return false;
|
||||
|
||||
// never ignore an unlabeled multi arg
|
||||
|
||||
|
||||
// always take the first value, regardless of the start string
|
||||
_extractValue( args[(*i)] );
|
||||
|
||||
/*
|
||||
// continue taking args until we hit the end or a start string
|
||||
while ( (unsigned int)(*i)+1 < args.size() &&
|
||||
args[(*i)+1].find_first_of( Arg::flagStartString() ) != 0 &&
|
||||
args[(*i)+1].find_first_of( Arg::nameStartString() ) != 0 )
|
||||
_extractValue( args[++(*i)] );
|
||||
*/
|
||||
|
||||
_alreadySet = true;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string UnlabeledMultiArg<T>::shortID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return std::string("<") + _typeDesc + "> ...";
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string UnlabeledMultiArg<T>::longID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return std::string("<") + _typeDesc + "> (accepted multiple times)";
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool UnlabeledMultiArg<T>::operator==(const Arg& a) const
|
||||
{
|
||||
if ( _name == a.getName() || _description == a.getDescription() )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void UnlabeledMultiArg<T>::addToList( std::list<Arg*>& argList ) const
|
||||
{
|
||||
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif
|
340
components/mkspiffs/src/tclap/UnlabeledValueArg.h
Normal file
340
components/mkspiffs/src/tclap/UnlabeledValueArg.h
Normal file
@ -0,0 +1,340 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: UnlabeledValueArg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_UNLABELED_VALUE_ARGUMENT_H
|
||||
#define TCLAP_UNLABELED_VALUE_ARGUMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "ValueArg.h"
|
||||
#include "OptionalUnlabeledTracker.h"
|
||||
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* The basic unlabeled argument that parses a value.
|
||||
* This is a template class, which means the type T defines the type
|
||||
* that a given object will attempt to parse when an UnlabeledValueArg
|
||||
* is reached in the list of args that the CmdLine iterates over.
|
||||
*/
|
||||
template<class T>
|
||||
class UnlabeledValueArg : public ValueArg<T>
|
||||
{
|
||||
|
||||
// If compiler has two stage name lookup (as gcc >= 3.4 does)
|
||||
// this is requried to prevent undef. symbols
|
||||
using ValueArg<T>::_ignoreable;
|
||||
using ValueArg<T>::_hasBlanks;
|
||||
using ValueArg<T>::_extractValue;
|
||||
using ValueArg<T>::_typeDesc;
|
||||
using ValueArg<T>::_name;
|
||||
using ValueArg<T>::_description;
|
||||
using ValueArg<T>::_alreadySet;
|
||||
using ValueArg<T>::toString;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* UnlabeledValueArg constructor.
|
||||
* \param name - A one word name for the argument. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param ignoreable - Allows you to specify that this argument can be
|
||||
* ignored if the '--' flag is set. This defaults to false (cannot
|
||||
* be ignored) and should generally stay that way unless you have
|
||||
* some special need for certain arguments to be ignored.
|
||||
* \param v - Optional Vistor. You should leave this blank unless
|
||||
* you have a very good reason.
|
||||
*/
|
||||
UnlabeledValueArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
const std::string& typeDesc,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL);
|
||||
|
||||
/**
|
||||
* UnlabeledValueArg constructor.
|
||||
* \param name - A one word name for the argument. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param ignoreable - Allows you to specify that this argument can be
|
||||
* ignored if the '--' flag is set. This defaults to false (cannot
|
||||
* be ignored) and should generally stay that way unless you have
|
||||
* some special need for certain arguments to be ignored.
|
||||
* \param v - Optional Vistor. You should leave this blank unless
|
||||
* you have a very good reason.
|
||||
*/
|
||||
UnlabeledValueArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* UnlabeledValueArg constructor.
|
||||
* \param name - A one word name for the argument. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param ignoreable - Allows you to specify that this argument can be
|
||||
* ignored if the '--' flag is set. This defaults to false (cannot
|
||||
* be ignored) and should generally stay that way unless you have
|
||||
* some special need for certain arguments to be ignored.
|
||||
* \param v - Optional Vistor. You should leave this blank unless
|
||||
* you have a very good reason.
|
||||
*/
|
||||
UnlabeledValueArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
Constraint<T>* constraint,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL );
|
||||
|
||||
|
||||
/**
|
||||
* UnlabeledValueArg constructor.
|
||||
* \param name - A one word name for the argument. Note that this is used for
|
||||
* identification, not as a long flag.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param ignoreable - Allows you to specify that this argument can be
|
||||
* ignored if the '--' flag is set. This defaults to false (cannot
|
||||
* be ignored) and should generally stay that way unless you have
|
||||
* some special need for certain arguments to be ignored.
|
||||
* \param v - Optional Vistor. You should leave this blank unless
|
||||
* you have a very good reason.
|
||||
*/
|
||||
UnlabeledValueArg( const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable = false,
|
||||
Visitor* v = NULL);
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately. Handling specific to
|
||||
* unlabled arguments.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings.
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Overrides shortID for specific behavior.
|
||||
*/
|
||||
virtual std::string shortID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Overrides longID for specific behavior.
|
||||
*/
|
||||
virtual std::string longID(const std::string& val="val") const;
|
||||
|
||||
/**
|
||||
* Overrides operator== for specific behavior.
|
||||
*/
|
||||
virtual bool operator==(const Arg& a ) const;
|
||||
|
||||
/**
|
||||
* Instead of pushing to the front of list, push to the back.
|
||||
* \param argList - The list to add this to.
|
||||
*/
|
||||
virtual void addToList( std::list<Arg*>& argList ) const;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
* Constructor implemenation.
|
||||
*/
|
||||
template<class T>
|
||||
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
const std::string& typeDesc,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
|
||||
OptionalUnlabeledTracker::check(req, toString());
|
||||
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: ValueArg<T>("", name, desc, req, val, typeDesc, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(req, toString());
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor implemenation.
|
||||
*/
|
||||
template<class T>
|
||||
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
Constraint<T>* constraint,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: ValueArg<T>("", name, desc, req, val, constraint, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(req, toString());
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UnlabeledValueArg<T>::UnlabeledValueArg(const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
bool ignoreable,
|
||||
Visitor* v)
|
||||
: ValueArg<T>("", name, desc, req, val, constraint, v)
|
||||
{
|
||||
_ignoreable = ignoreable;
|
||||
OptionalUnlabeledTracker::check(req, toString());
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of processArg().
|
||||
*/
|
||||
template<class T>
|
||||
bool UnlabeledValueArg<T>::processArg(int *i, std::vector<std::string>& args)
|
||||
{
|
||||
|
||||
if ( _alreadySet )
|
||||
return false;
|
||||
|
||||
if ( _hasBlanks( args[*i] ) )
|
||||
return false;
|
||||
|
||||
// never ignore an unlabeled arg
|
||||
|
||||
_extractValue( args[*i] );
|
||||
_alreadySet = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding shortID for specific output.
|
||||
*/
|
||||
template<class T>
|
||||
std::string UnlabeledValueArg<T>::shortID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return std::string("<") + _typeDesc + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding longID for specific output.
|
||||
*/
|
||||
template<class T>
|
||||
std::string UnlabeledValueArg<T>::longID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
|
||||
// Ideally we would like to be able to use RTTI to return the name
|
||||
// of the type required for this argument. However, g++ at least,
|
||||
// doesn't appear to return terribly useful "names" of the types.
|
||||
return std::string("<") + _typeDesc + ">";
|
||||
}
|
||||
|
||||
/**
|
||||
* Overriding operator== for specific behavior.
|
||||
*/
|
||||
template<class T>
|
||||
bool UnlabeledValueArg<T>::operator==(const Arg& a ) const
|
||||
{
|
||||
if ( _name == a.getName() || _description == a.getDescription() )
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void UnlabeledValueArg<T>::addToList( std::list<Arg*>& argList ) const
|
||||
{
|
||||
argList.push_back( const_cast<Arg*>(static_cast<const Arg* const>(this)) );
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
425
components/mkspiffs/src/tclap/ValueArg.h
Normal file
425
components/mkspiffs/src/tclap/ValueArg.h
Normal file
@ -0,0 +1,425 @@
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: ValueArg.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_VALUE_ARGUMENT_H
|
||||
#define TCLAP_VALUE_ARGUMENT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "Arg.h"
|
||||
#include "Constraint.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* The basic labeled argument that parses a value.
|
||||
* This is a template class, which means the type T defines the type
|
||||
* that a given object will attempt to parse when the flag/name is matched
|
||||
* on the command line. While there is nothing stopping you from creating
|
||||
* an unflagged ValueArg, it is unwise and would cause significant problems.
|
||||
* Instead use an UnlabeledValueArg.
|
||||
*/
|
||||
template<class T>
|
||||
class ValueArg : public Arg
|
||||
{
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The value parsed from the command line.
|
||||
* Can be of any type, as long as the >> operator for the type
|
||||
* is defined.
|
||||
*/
|
||||
T _value;
|
||||
|
||||
/**
|
||||
* Used to support the reset() method so that ValueArg can be
|
||||
* reset to their constructed value.
|
||||
*/
|
||||
T _default;
|
||||
|
||||
/**
|
||||
* A human readable description of the type to be parsed.
|
||||
* This is a hack, plain and simple. Ideally we would use RTTI to
|
||||
* return the name of type T, but until there is some sort of
|
||||
* consistent support for human readable names, we are left to our
|
||||
* own devices.
|
||||
*/
|
||||
std::string _typeDesc;
|
||||
|
||||
/**
|
||||
* A Constraint this Arg must conform to.
|
||||
*/
|
||||
Constraint<T>* _constraint;
|
||||
|
||||
/**
|
||||
* Extracts the value from the string.
|
||||
* Attempts to parse string as type T, if this fails an exception
|
||||
* is thrown.
|
||||
* \param val - value to be parsed.
|
||||
*/
|
||||
void _extractValue( const std::string& val );
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Labeled ValueArg constructor.
|
||||
* You could conceivably call this constructor with a blank flag,
|
||||
* but that would make you a bad person. It would also cause
|
||||
* an exception to be thrown. If you want an unlabeled argument,
|
||||
* use the other constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
ValueArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
const std::string& typeDesc,
|
||||
Visitor* v = NULL);
|
||||
|
||||
|
||||
/**
|
||||
* Labeled ValueArg constructor.
|
||||
* You could conceivably call this constructor with a blank flag,
|
||||
* but that would make you a bad person. It would also cause
|
||||
* an exception to be thrown. If you want an unlabeled argument,
|
||||
* use the other constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param typeDesc - A short, human readable description of the
|
||||
* type that this object expects. This is used in the generation
|
||||
* of the USAGE statement. The goal is to be helpful to the end user
|
||||
* of the program.
|
||||
* \param parser - A CmdLine parser object to add this Arg to
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
ValueArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Labeled ValueArg constructor.
|
||||
* You could conceivably call this constructor with a blank flag,
|
||||
* but that would make you a bad person. It would also cause
|
||||
* an exception to be thrown. If you want an unlabeled argument,
|
||||
* use the other constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param parser - A CmdLine parser object to add this Arg to.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
ValueArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Labeled ValueArg constructor.
|
||||
* You could conceivably call this constructor with a blank flag,
|
||||
* but that would make you a bad person. It would also cause
|
||||
* an exception to be thrown. If you want an unlabeled argument,
|
||||
* use the other constructor.
|
||||
* \param flag - The one character flag that identifies this
|
||||
* argument on the command line.
|
||||
* \param name - A one word name for the argument. Can be
|
||||
* used as a long flag on the command line.
|
||||
* \param desc - A description of what the argument is for or
|
||||
* does.
|
||||
* \param req - Whether the argument is required on the command
|
||||
* line.
|
||||
* \param value - The default value assigned to this argument if it
|
||||
* is not present on the command line.
|
||||
* \param constraint - A pointer to a Constraint object used
|
||||
* to constrain this Arg.
|
||||
* \param v - An optional visitor. You probably should not
|
||||
* use this unless you have a very good reason.
|
||||
*/
|
||||
ValueArg( const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T value,
|
||||
Constraint<T>* constraint,
|
||||
Visitor* v = NULL );
|
||||
|
||||
/**
|
||||
* Handles the processing of the argument.
|
||||
* This re-implements the Arg version of this method to set the
|
||||
* _value of the argument appropriately. It knows the difference
|
||||
* between labeled and unlabeled.
|
||||
* \param i - Pointer the the current argument in the list.
|
||||
* \param args - Mutable list of strings. Passed
|
||||
* in from main().
|
||||
*/
|
||||
virtual bool processArg(int* i, std::vector<std::string>& args);
|
||||
|
||||
/**
|
||||
* Returns the value of the argument.
|
||||
*/
|
||||
T& getValue() ;
|
||||
|
||||
/**
|
||||
* Specialization of shortID.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string shortID(const std::string& val = "val") const;
|
||||
|
||||
/**
|
||||
* Specialization of longID.
|
||||
* \param val - value to be used.
|
||||
*/
|
||||
virtual std::string longID(const std::string& val = "val") const;
|
||||
|
||||
virtual void reset() ;
|
||||
|
||||
private:
|
||||
/**
|
||||
* Prevent accidental copying
|
||||
*/
|
||||
ValueArg<T>(const ValueArg<T>& rhs);
|
||||
ValueArg<T>& operator=(const ValueArg<T>& rhs);
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Constructor implementation.
|
||||
*/
|
||||
template<class T>
|
||||
ValueArg<T>::ValueArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
const std::string& typeDesc,
|
||||
Visitor* v)
|
||||
: Arg(flag, name, desc, req, true, v),
|
||||
_value( val ),
|
||||
_default( val ),
|
||||
_typeDesc( typeDesc ),
|
||||
_constraint( NULL )
|
||||
{ }
|
||||
|
||||
template<class T>
|
||||
ValueArg<T>::ValueArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
const std::string& typeDesc,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v)
|
||||
: Arg(flag, name, desc, req, true, v),
|
||||
_value( val ),
|
||||
_default( val ),
|
||||
_typeDesc( typeDesc ),
|
||||
_constraint( NULL )
|
||||
{
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
ValueArg<T>::ValueArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
Constraint<T>* constraint,
|
||||
Visitor* v)
|
||||
: Arg(flag, name, desc, req, true, v),
|
||||
_value( val ),
|
||||
_default( val ),
|
||||
_typeDesc( constraint->shortID() ),
|
||||
_constraint( constraint )
|
||||
{ }
|
||||
|
||||
template<class T>
|
||||
ValueArg<T>::ValueArg(const std::string& flag,
|
||||
const std::string& name,
|
||||
const std::string& desc,
|
||||
bool req,
|
||||
T val,
|
||||
Constraint<T>* constraint,
|
||||
CmdLineInterface& parser,
|
||||
Visitor* v)
|
||||
: Arg(flag, name, desc, req, true, v),
|
||||
_value( val ),
|
||||
_default( val ),
|
||||
_typeDesc( constraint->shortID() ),
|
||||
_constraint( constraint )
|
||||
{
|
||||
parser.add( this );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Implementation of getValue().
|
||||
*/
|
||||
template<class T>
|
||||
T& ValueArg<T>::getValue() { return _value; }
|
||||
|
||||
/**
|
||||
* Implementation of processArg().
|
||||
*/
|
||||
template<class T>
|
||||
bool ValueArg<T>::processArg(int *i, std::vector<std::string>& args)
|
||||
{
|
||||
if ( _ignoreable && Arg::ignoreRest() )
|
||||
return false;
|
||||
|
||||
if ( _hasBlanks( args[*i] ) )
|
||||
return false;
|
||||
|
||||
std::string flag = args[*i];
|
||||
|
||||
std::string value = "";
|
||||
trimFlag( flag, value );
|
||||
|
||||
if ( argMatches( flag ) )
|
||||
{
|
||||
if ( _alreadySet )
|
||||
{
|
||||
if ( _xorSet )
|
||||
throw( CmdLineParseException(
|
||||
"Mutually exclusive argument already set!",
|
||||
toString()) );
|
||||
else
|
||||
throw( CmdLineParseException("Argument already set!",
|
||||
toString()) );
|
||||
}
|
||||
|
||||
if ( Arg::delimiter() != ' ' && value == "" )
|
||||
throw( ArgParseException(
|
||||
"Couldn't find delimiter for this argument!",
|
||||
toString() ) );
|
||||
|
||||
if ( value == "" )
|
||||
{
|
||||
(*i)++;
|
||||
if ( static_cast<unsigned int>(*i) < args.size() )
|
||||
_extractValue( args[*i] );
|
||||
else
|
||||
throw( ArgParseException("Missing a value for this argument!",
|
||||
toString() ) );
|
||||
}
|
||||
else
|
||||
_extractValue( value );
|
||||
|
||||
_alreadySet = true;
|
||||
_checkWithVisitor();
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of shortID.
|
||||
*/
|
||||
template<class T>
|
||||
std::string ValueArg<T>::shortID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return Arg::shortID( _typeDesc );
|
||||
}
|
||||
|
||||
/**
|
||||
* Implementation of longID.
|
||||
*/
|
||||
template<class T>
|
||||
std::string ValueArg<T>::longID(const std::string& val) const
|
||||
{
|
||||
static_cast<void>(val); // Ignore input, don't warn
|
||||
return Arg::longID( _typeDesc );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ValueArg<T>::_extractValue( const std::string& val )
|
||||
{
|
||||
try {
|
||||
ExtractValue(_value, val, typename ArgTraits<T>::ValueCategory());
|
||||
} catch( ArgParseException &e) {
|
||||
throw ArgParseException(e.error(), toString());
|
||||
}
|
||||
|
||||
if ( _constraint != NULL )
|
||||
if ( ! _constraint->check( _value ) )
|
||||
throw( CmdLineParseException( "Value '" + val +
|
||||
+ "' does not meet constraint: "
|
||||
+ _constraint->description(),
|
||||
toString() ) );
|
||||
}
|
||||
|
||||
template<class T>
|
||||
void ValueArg<T>::reset()
|
||||
{
|
||||
Arg::reset();
|
||||
_value = _default;
|
||||
}
|
||||
|
||||
} // namespace TCLAP
|
||||
|
||||
#endif
|
148
components/mkspiffs/src/tclap/ValuesConstraint.h
Normal file
148
components/mkspiffs/src/tclap/ValuesConstraint.h
Normal file
@ -0,0 +1,148 @@
|
||||
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: ValuesConstraint.h
|
||||
*
|
||||
* Copyright (c) 2005, Michael E. Smoot
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_VALUESCONSTRAINT_H
|
||||
#define TCLAP_VALUESCONSTRAINT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "Constraint.h"
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#else
|
||||
#define HAVE_SSTREAM
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
#include <sstream>
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
#include <strstream>
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A Constraint that constrains the Arg to only those values specified
|
||||
* in the constraint.
|
||||
*/
|
||||
template<class T>
|
||||
class ValuesConstraint : public Constraint<T>
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param allowed - vector of allowed values.
|
||||
*/
|
||||
ValuesConstraint(std::vector<T>& allowed);
|
||||
|
||||
/**
|
||||
* Virtual destructor.
|
||||
*/
|
||||
virtual ~ValuesConstraint() {}
|
||||
|
||||
/**
|
||||
* Returns a description of the Constraint.
|
||||
*/
|
||||
virtual std::string description() const;
|
||||
|
||||
/**
|
||||
* Returns the short ID for the Constraint.
|
||||
*/
|
||||
virtual std::string shortID() const;
|
||||
|
||||
/**
|
||||
* The method used to verify that the value parsed from the command
|
||||
* line meets the constraint.
|
||||
* \param value - The value that will be checked.
|
||||
*/
|
||||
virtual bool check(const T& value) const;
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The list of valid values.
|
||||
*/
|
||||
std::vector<T> _allowed;
|
||||
|
||||
/**
|
||||
* The string used to describe the allowed values of this constraint.
|
||||
*/
|
||||
std::string _typeDesc;
|
||||
|
||||
};
|
||||
|
||||
template<class T>
|
||||
ValuesConstraint<T>::ValuesConstraint(std::vector<T>& allowed)
|
||||
: _allowed(allowed),
|
||||
_typeDesc("")
|
||||
{
|
||||
for ( unsigned int i = 0; i < _allowed.size(); i++ )
|
||||
{
|
||||
|
||||
#if defined(HAVE_SSTREAM)
|
||||
std::ostringstream os;
|
||||
#elif defined(HAVE_STRSTREAM)
|
||||
std::ostrstream os;
|
||||
#else
|
||||
#error "Need a stringstream (sstream or strstream) to compile!"
|
||||
#endif
|
||||
|
||||
os << _allowed[i];
|
||||
|
||||
std::string temp( os.str() );
|
||||
|
||||
if ( i > 0 )
|
||||
_typeDesc += "|";
|
||||
_typeDesc += temp;
|
||||
}
|
||||
}
|
||||
|
||||
template<class T>
|
||||
bool ValuesConstraint<T>::check( const T& val ) const
|
||||
{
|
||||
if ( std::find(_allowed.begin(),_allowed.end(),val) == _allowed.end() )
|
||||
return false;
|
||||
else
|
||||
return true;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string ValuesConstraint<T>::shortID() const
|
||||
{
|
||||
return _typeDesc;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
std::string ValuesConstraint<T>::description() const
|
||||
{
|
||||
return _typeDesc;
|
||||
}
|
||||
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
||||
|
81
components/mkspiffs/src/tclap/VersionVisitor.h
Normal file
81
components/mkspiffs/src/tclap/VersionVisitor.h
Normal file
@ -0,0 +1,81 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: VersionVisitor.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_VERSION_VISITOR_H
|
||||
#define TCLAP_VERSION_VISITOR_H
|
||||
|
||||
#include "CmdLineInterface.h"
|
||||
#include "CmdLineOutput.h"
|
||||
#include "Visitor.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A Vistor that will call the version method of the given CmdLineOutput
|
||||
* for the specified CmdLine object and then exit.
|
||||
*/
|
||||
class VersionVisitor: public Visitor
|
||||
{
|
||||
private:
|
||||
/**
|
||||
* Prevent accidental copying
|
||||
*/
|
||||
VersionVisitor(const VersionVisitor& rhs);
|
||||
VersionVisitor& operator=(const VersionVisitor& rhs);
|
||||
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The CmdLine of interest.
|
||||
*/
|
||||
CmdLineInterface* _cmd;
|
||||
|
||||
/**
|
||||
* The output object.
|
||||
*/
|
||||
CmdLineOutput** _out;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
* \param cmd - The CmdLine the output is generated for.
|
||||
* \param out - The type of output.
|
||||
*/
|
||||
VersionVisitor( CmdLineInterface* cmd, CmdLineOutput** out )
|
||||
: Visitor(), _cmd( cmd ), _out( out ) { }
|
||||
|
||||
/**
|
||||
* Calls the version method of the output object using the
|
||||
* specified CmdLine.
|
||||
*/
|
||||
void visit() {
|
||||
(*_out)->version(*_cmd);
|
||||
throw ExitException(0);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
53
components/mkspiffs/src/tclap/Visitor.h
Normal file
53
components/mkspiffs/src/tclap/Visitor.h
Normal file
@ -0,0 +1,53 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: Visitor.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
|
||||
#ifndef TCLAP_VISITOR_H
|
||||
#define TCLAP_VISITOR_H
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A base class that defines the interface for visitors.
|
||||
*/
|
||||
class Visitor
|
||||
{
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor. Does nothing.
|
||||
*/
|
||||
Visitor() { }
|
||||
|
||||
/**
|
||||
* Destructor. Does nothing.
|
||||
*/
|
||||
virtual ~Visitor() { }
|
||||
|
||||
/**
|
||||
* Does nothing. Should be overridden by child.
|
||||
*/
|
||||
virtual void visit() { }
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
166
components/mkspiffs/src/tclap/XorHandler.h
Normal file
166
components/mkspiffs/src/tclap/XorHandler.h
Normal file
@ -0,0 +1,166 @@
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: XorHandler.h
|
||||
*
|
||||
* Copyright (c) 2003, Michael E. Smoot .
|
||||
* Copyright (c) 2004, Michael E. Smoot, Daniel Aarno.
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_XORHANDLER_H
|
||||
#define TCLAP_XORHANDLER_H
|
||||
|
||||
#include "Arg.h"
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <iostream>
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* This class handles lists of Arg's that are to be XOR'd on the command
|
||||
* line. This is used by CmdLine and you shouldn't ever use it.
|
||||
*/
|
||||
class XorHandler
|
||||
{
|
||||
protected:
|
||||
|
||||
/**
|
||||
* The list of of lists of Arg's to be or'd together.
|
||||
*/
|
||||
std::vector< std::vector<Arg*> > _orList;
|
||||
|
||||
public:
|
||||
|
||||
/**
|
||||
* Constructor. Does nothing.
|
||||
*/
|
||||
XorHandler( ) : _orList(std::vector< std::vector<Arg*> >()) {}
|
||||
|
||||
/**
|
||||
* Add a list of Arg*'s that will be orred together.
|
||||
* \param ors - list of Arg* that will be xor'd.
|
||||
*/
|
||||
void add( std::vector<Arg*>& ors );
|
||||
|
||||
/**
|
||||
* Checks whether the specified Arg is in one of the xor lists and
|
||||
* if it does match one, returns the size of the xor list that the
|
||||
* Arg matched. If the Arg matches, then it also sets the rest of
|
||||
* the Arg's in the list. You shouldn't use this.
|
||||
* \param a - The Arg to be checked.
|
||||
*/
|
||||
int check( const Arg* a );
|
||||
|
||||
/**
|
||||
* Returns the XOR specific short usage.
|
||||
*/
|
||||
std::string shortUsage();
|
||||
|
||||
/**
|
||||
* Prints the XOR specific long usage.
|
||||
* \param os - Stream to print to.
|
||||
*/
|
||||
void printLongUsage(std::ostream& os);
|
||||
|
||||
/**
|
||||
* Simply checks whether the Arg is contained in one of the arg
|
||||
* lists.
|
||||
* \param a - The Arg to be checked.
|
||||
*/
|
||||
bool contains( const Arg* a );
|
||||
|
||||
std::vector< std::vector<Arg*> >& getXorList();
|
||||
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//BEGIN XOR.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
inline void XorHandler::add( std::vector<Arg*>& ors )
|
||||
{
|
||||
_orList.push_back( ors );
|
||||
}
|
||||
|
||||
inline int XorHandler::check( const Arg* a )
|
||||
{
|
||||
// iterate over each XOR list
|
||||
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
|
||||
{
|
||||
// if the XOR list contains the arg..
|
||||
ArgVectorIterator ait = std::find( _orList[i].begin(),
|
||||
_orList[i].end(), a );
|
||||
if ( ait != _orList[i].end() )
|
||||
{
|
||||
// first check to see if a mutually exclusive switch
|
||||
// has not already been set
|
||||
for ( ArgVectorIterator it = _orList[i].begin();
|
||||
it != _orList[i].end();
|
||||
it++ )
|
||||
if ( a != (*it) && (*it)->isSet() )
|
||||
throw(CmdLineParseException(
|
||||
"Mutually exclusive argument already set!",
|
||||
(*it)->toString()));
|
||||
|
||||
// go through and set each arg that is not a
|
||||
for ( ArgVectorIterator it = _orList[i].begin();
|
||||
it != _orList[i].end();
|
||||
it++ )
|
||||
if ( a != (*it) )
|
||||
(*it)->xorSet();
|
||||
|
||||
// return the number of required args that have now been set
|
||||
if ( (*ait)->allowMore() )
|
||||
return 0;
|
||||
else
|
||||
return static_cast<int>(_orList[i].size());
|
||||
}
|
||||
}
|
||||
|
||||
if ( a->isRequired() )
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
inline bool XorHandler::contains( const Arg* a )
|
||||
{
|
||||
for ( int i = 0; static_cast<unsigned int>(i) < _orList.size(); i++ )
|
||||
for ( ArgVectorIterator it = _orList[i].begin();
|
||||
it != _orList[i].end();
|
||||
it++ )
|
||||
if ( a == (*it) )
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
inline std::vector< std::vector<Arg*> >& XorHandler::getXorList()
|
||||
{
|
||||
return _orList;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
//END XOR.cpp
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
} //namespace TCLAP
|
||||
|
||||
#endif
|
323
components/mkspiffs/src/tclap/ZshCompletionOutput.h
Normal file
323
components/mkspiffs/src/tclap/ZshCompletionOutput.h
Normal file
@ -0,0 +1,323 @@
|
||||
// -*- Mode: c++; c-basic-offset: 4; tab-width: 4; -*-
|
||||
|
||||
/******************************************************************************
|
||||
*
|
||||
* file: ZshCompletionOutput.h
|
||||
*
|
||||
* Copyright (c) 2006, Oliver Kiddle
|
||||
* All rights reverved.
|
||||
*
|
||||
* See the file COPYING in the top directory of this distribution for
|
||||
* more information.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED _AS IS_, WITHOUT WARRANTY OF ANY KIND, EXPRESS
|
||||
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||
* DEALINGS IN THE SOFTWARE.
|
||||
*
|
||||
*****************************************************************************/
|
||||
|
||||
#ifndef TCLAP_ZSHCOMPLETIONOUTPUT_H
|
||||
#define TCLAP_ZSHCOMPLETIONOUTPUT_H
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <list>
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
|
||||
#include "CmdLineInterface.h"
|
||||
#include "CmdLineOutput.h"
|
||||
#include "XorHandler.h"
|
||||
#include "Arg.h"
|
||||
|
||||
namespace TCLAP {
|
||||
|
||||
/**
|
||||
* A class that generates a Zsh completion function as output from the usage()
|
||||
* method for the given CmdLine and its Args.
|
||||
*/
|
||||
class ZshCompletionOutput : public CmdLineOutput
|
||||
{
|
||||
|
||||
public:
|
||||
|
||||
ZshCompletionOutput();
|
||||
|
||||
/**
|
||||
* Prints the usage to stdout. Can be overridden to
|
||||
* produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void usage(CmdLineInterface& c);
|
||||
|
||||
/**
|
||||
* Prints the version to stdout. Can be overridden
|
||||
* to produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
*/
|
||||
virtual void version(CmdLineInterface& c);
|
||||
|
||||
/**
|
||||
* Prints (to stderr) an error message, short usage
|
||||
* Can be overridden to produce alternative behavior.
|
||||
* \param c - The CmdLine object the output is generated for.
|
||||
* \param e - The ArgException that caused the failure.
|
||||
*/
|
||||
virtual void failure(CmdLineInterface& c,
|
||||
ArgException& e );
|
||||
|
||||
protected:
|
||||
|
||||
void basename( std::string& s );
|
||||
void quoteSpecialChars( std::string& s );
|
||||
|
||||
std::string getMutexList( CmdLineInterface& _cmd, Arg* a );
|
||||
void printOption( Arg* it, std::string mutex );
|
||||
void printArg( Arg* it );
|
||||
|
||||
std::map<std::string, std::string> common;
|
||||
char theDelimiter;
|
||||
};
|
||||
|
||||
ZshCompletionOutput::ZshCompletionOutput()
|
||||
: common(std::map<std::string, std::string>()),
|
||||
theDelimiter('=')
|
||||
{
|
||||
common["host"] = "_hosts";
|
||||
common["hostname"] = "_hosts";
|
||||
common["file"] = "_files";
|
||||
common["filename"] = "_files";
|
||||
common["user"] = "_users";
|
||||
common["username"] = "_users";
|
||||
common["directory"] = "_directories";
|
||||
common["path"] = "_directories";
|
||||
common["url"] = "_urls";
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::version(CmdLineInterface& _cmd)
|
||||
{
|
||||
std::cout << _cmd.getVersion() << std::endl;
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::usage(CmdLineInterface& _cmd )
|
||||
{
|
||||
std::list<Arg*> argList = _cmd.getArgList();
|
||||
std::string progName = _cmd.getProgramName();
|
||||
std::string xversion = _cmd.getVersion();
|
||||
theDelimiter = _cmd.getDelimiter();
|
||||
basename(progName);
|
||||
|
||||
std::cout << "#compdef " << progName << std::endl << std::endl <<
|
||||
"# " << progName << " version " << _cmd.getVersion() << std::endl << std::endl <<
|
||||
"_arguments -s -S";
|
||||
|
||||
for (ArgListIterator it = argList.begin(); it != argList.end(); it++)
|
||||
{
|
||||
if ( (*it)->shortID().at(0) == '<' )
|
||||
printArg((*it));
|
||||
else if ( (*it)->getFlag() != "-" )
|
||||
printOption((*it), getMutexList(_cmd, *it));
|
||||
}
|
||||
|
||||
std::cout << std::endl;
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::failure( CmdLineInterface& _cmd,
|
||||
ArgException& e )
|
||||
{
|
||||
static_cast<void>(_cmd); // unused
|
||||
std::cout << e.what() << std::endl;
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::quoteSpecialChars( std::string& s )
|
||||
{
|
||||
size_t idx = s.find_last_of(':');
|
||||
while ( idx != std::string::npos )
|
||||
{
|
||||
s.insert(idx, 1, '\\');
|
||||
idx = s.find_last_of(':', idx);
|
||||
}
|
||||
idx = s.find_last_of('\'');
|
||||
while ( idx != std::string::npos )
|
||||
{
|
||||
s.insert(idx, "'\\'");
|
||||
if (idx == 0)
|
||||
idx = std::string::npos;
|
||||
else
|
||||
idx = s.find_last_of('\'', --idx);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::basename( std::string& s )
|
||||
{
|
||||
size_t p = s.find_last_of('/');
|
||||
if ( p != std::string::npos )
|
||||
{
|
||||
s.erase(0, p + 1);
|
||||
}
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::printArg(Arg* a)
|
||||
{
|
||||
static int count = 1;
|
||||
|
||||
std::cout << " \\" << std::endl << " '";
|
||||
if ( a->acceptsMultipleValues() )
|
||||
std::cout << '*';
|
||||
else
|
||||
std::cout << count++;
|
||||
std::cout << ':';
|
||||
if ( !a->isRequired() )
|
||||
std::cout << ':';
|
||||
|
||||
std::cout << a->getName() << ':';
|
||||
std::map<std::string, std::string>::iterator compArg = common.find(a->getName());
|
||||
if ( compArg != common.end() )
|
||||
{
|
||||
std::cout << compArg->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "_guard \"^-*\" " << a->getName();
|
||||
}
|
||||
std::cout << '\'';
|
||||
}
|
||||
|
||||
inline void ZshCompletionOutput::printOption(Arg* a, std::string mutex)
|
||||
{
|
||||
std::string flag = a->flagStartChar() + a->getFlag();
|
||||
std::string name = a->nameStartString() + a->getName();
|
||||
std::string desc = a->getDescription();
|
||||
|
||||
// remove full stop and capitalisation from description as
|
||||
// this is the convention for zsh function
|
||||
if (!desc.compare(0, 12, "(required) "))
|
||||
{
|
||||
desc.erase(0, 12);
|
||||
}
|
||||
if (!desc.compare(0, 15, "(OR required) "))
|
||||
{
|
||||
desc.erase(0, 15);
|
||||
}
|
||||
size_t len = desc.length();
|
||||
if (len && desc.at(--len) == '.')
|
||||
{
|
||||
desc.erase(len);
|
||||
}
|
||||
if (len)
|
||||
{
|
||||
desc.replace(0, 1, 1, tolower(desc.at(0)));
|
||||
}
|
||||
|
||||
std::cout << " \\" << std::endl << " '" << mutex;
|
||||
|
||||
if ( a->getFlag().empty() )
|
||||
{
|
||||
std::cout << name;
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << "'{" << flag << ',' << name << "}'";
|
||||
}
|
||||
if ( theDelimiter == '=' && a->isValueRequired() )
|
||||
std::cout << "=-";
|
||||
quoteSpecialChars(desc);
|
||||
std::cout << '[' << desc << ']';
|
||||
|
||||
if ( a->isValueRequired() )
|
||||
{
|
||||
std::string arg = a->shortID();
|
||||
arg.erase(0, arg.find_last_of(theDelimiter) + 1);
|
||||
if ( arg.at(arg.length()-1) == ']' )
|
||||
arg.erase(arg.length()-1);
|
||||
if ( arg.at(arg.length()-1) == ']' )
|
||||
{
|
||||
arg.erase(arg.length()-1);
|
||||
}
|
||||
if ( arg.at(0) == '<' )
|
||||
{
|
||||
arg.erase(arg.length()-1);
|
||||
arg.erase(0, 1);
|
||||
}
|
||||
size_t p = arg.find('|');
|
||||
if ( p != std::string::npos )
|
||||
{
|
||||
do
|
||||
{
|
||||
arg.replace(p, 1, 1, ' ');
|
||||
}
|
||||
while ( (p = arg.find_first_of('|', p)) != std::string::npos );
|
||||
quoteSpecialChars(arg);
|
||||
std::cout << ": :(" << arg << ')';
|
||||
}
|
||||
else
|
||||
{
|
||||
std::cout << ':' << arg;
|
||||
std::map<std::string, std::string>::iterator compArg = common.find(arg);
|
||||
if ( compArg != common.end() )
|
||||
{
|
||||
std::cout << ':' << compArg->second;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::cout << '\'';
|
||||
}
|
||||
|
||||
inline std::string ZshCompletionOutput::getMutexList( CmdLineInterface& _cmd, Arg* a)
|
||||
{
|
||||
XorHandler xorHandler = _cmd.getXorHandler();
|
||||
std::vector< std::vector<Arg*> > xorList = xorHandler.getXorList();
|
||||
|
||||
if (a->getName() == "help" || a->getName() == "version")
|
||||
{
|
||||
return "(-)";
|
||||
}
|
||||
|
||||
std::ostringstream list;
|
||||
if ( a->acceptsMultipleValues() )
|
||||
{
|
||||
list << '*';
|
||||
}
|
||||
|
||||
for ( int i = 0; static_cast<unsigned int>(i) < xorList.size(); i++ )
|
||||
{
|
||||
for ( ArgVectorIterator it = xorList[i].begin();
|
||||
it != xorList[i].end();
|
||||
it++)
|
||||
if ( a == (*it) )
|
||||
{
|
||||
list << '(';
|
||||
for ( ArgVectorIterator iu = xorList[i].begin();
|
||||
iu != xorList[i].end();
|
||||
iu++ )
|
||||
{
|
||||
bool notCur = (*iu) != a;
|
||||
bool hasFlag = !(*iu)->getFlag().empty();
|
||||
if ( iu != xorList[i].begin() && (notCur || hasFlag) )
|
||||
list << ' ';
|
||||
if (hasFlag)
|
||||
list << (*iu)->flagStartChar() << (*iu)->getFlag() << ' ';
|
||||
if ( notCur || hasFlag )
|
||||
list << (*iu)->nameStartString() << (*iu)->getName();
|
||||
}
|
||||
list << ')';
|
||||
return list.str();
|
||||
}
|
||||
}
|
||||
|
||||
// wasn't found in xor list
|
||||
if (!a->getFlag().empty()) {
|
||||
list << "(" << a->flagStartChar() << a->getFlag() << ' ' <<
|
||||
a->nameStartString() << a->getName() << ')';
|
||||
}
|
||||
|
||||
return list.str();
|
||||
}
|
||||
|
||||
} //namespace TCLAP
|
||||
#endif
|
7
components/spidriver/component.mk
Normal file
7
components/spidriver/component.mk
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Main Makefile. This is basically the same as a component makefile.
|
||||
#
|
||||
# (Uses default behaviour of compiling all source files in directory, adding 'include' to include path.)
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
1153
components/spidriver/spi_master_lobo.c
Normal file
1153
components/spidriver/spi_master_lobo.c
Normal file
File diff suppressed because it is too large
Load Diff
355
components/spidriver/spi_master_lobo.h
Normal file
355
components/spidriver/spi_master_lobo.h
Normal file
@ -0,0 +1,355 @@
|
||||
// Copyright 2010-2016 Espressif Systems (Shanghai) PTE LTD
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
#ifndef _DRIVER_SPI_MASTER_LOBO_H_
|
||||
#define _DRIVER_SPI_MASTER_LOBO_H_
|
||||
|
||||
#include "esp_err.h"
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
#include "soc/spi_struct.h"
|
||||
|
||||
#include "esp_intr.h"
|
||||
#include "esp_intr_alloc.h"
|
||||
#include "rom/lldesc.h"
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C"
|
||||
{
|
||||
#endif
|
||||
|
||||
|
||||
//Maximum amount of bytes that can be put in one DMA descriptor
|
||||
#define SPI_MAX_DMA_LEN (4096-4)
|
||||
|
||||
/**
|
||||
* @brief Enum with the three SPI peripherals that are software-accessible in it
|
||||
*/
|
||||
typedef enum {
|
||||
SPI_HOST=0, ///< SPI1, SPI; Cannot be used in this driver!
|
||||
HSPI_HOST=1, ///< SPI2, HSPI
|
||||
VSPI_HOST=2 ///< SPI3, VSPI
|
||||
} spi_lobo_host_device_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief This is a configuration structure for a SPI bus.
|
||||
*
|
||||
* You can use this structure to specify the GPIO pins of the bus. Normally, the driver will use the
|
||||
* GPIO matrix to route the signals. An exception is made when all signals either can be routed through
|
||||
* the IO_MUX or are -1. In that case, the IO_MUX is used, allowing for >40MHz speeds.
|
||||
*/
|
||||
typedef struct {
|
||||
int mosi_io_num; ///< GPIO pin for Master Out Slave In (=spi_d) signal, or -1 if not used.
|
||||
int miso_io_num; ///< GPIO pin for Master In Slave Out (=spi_q) signal, or -1 if not used.
|
||||
int sclk_io_num; ///< GPIO pin for Spi CLocK signal, or -1 if not used.
|
||||
int quadwp_io_num; ///< GPIO pin for WP (Write Protect) signal which is used as D2 in 4-bit communication modes, or -1 if not used.
|
||||
int quadhd_io_num; ///< GPIO pin for HD (HolD) signal which is used as D3 in 4-bit communication modes, or -1 if not used.
|
||||
int max_transfer_sz; ///< Maximum transfer size, in bytes. Defaults to 4094 if 0.
|
||||
} spi_lobo_bus_config_t;
|
||||
|
||||
|
||||
#define SPI_DEVICE_TXBIT_LSBFIRST (1<<0) ///< Transmit command/address/data LSB first instead of the default MSB first
|
||||
#define SPI_DEVICE_RXBIT_LSBFIRST (1<<1) ///< Receive data LSB first instead of the default MSB first
|
||||
#define SPI_DEVICE_BIT_LSBFIRST (SPI_TXBIT_LSBFIRST|SPI_RXBIT_LSBFIRST); ///< Transmit and receive LSB first
|
||||
#define SPI_DEVICE_3WIRE (1<<2) ///< Use spiq for both sending and receiving data
|
||||
#define SPI_DEVICE_POSITIVE_CS (1<<3) ///< Make CS positive during a transaction instead of negative
|
||||
#define SPI_DEVICE_HALFDUPLEX (1<<4) ///< Transmit data before receiving it, instead of simultaneously
|
||||
#define SPI_DEVICE_CLK_AS_CS (1<<5) ///< Output clock on CS line if CS is active
|
||||
|
||||
#define SPI_ERR_OTHER_CONFIG 7001
|
||||
|
||||
typedef struct spi_lobo_transaction_t spi_lobo_transaction_t;
|
||||
typedef void(*transaction_cb_t)(spi_lobo_transaction_t *trans);
|
||||
|
||||
/**
|
||||
* @brief This is a configuration for a SPI slave device that is connected to one of the SPI buses.
|
||||
*/
|
||||
typedef struct {
|
||||
uint8_t command_bits; ///< Amount of bits in command phase (0-16)
|
||||
uint8_t address_bits; ///< Amount of bits in address phase (0-64)
|
||||
uint8_t dummy_bits; ///< Amount of dummy bits to insert between address and data phase
|
||||
uint8_t mode; ///< SPI mode (0-3)
|
||||
uint8_t duty_cycle_pos; ///< Duty cycle of positive clock, in 1/256th increments (128 = 50%/50% duty). Setting this to 0 (=not setting it) is equivalent to setting this to 128.
|
||||
uint8_t cs_ena_pretrans; ///< Amount of SPI bit-cycles the cs should be activated before the transmission (0-16). This only works on half-duplex transactions.
|
||||
uint8_t cs_ena_posttrans; ///< Amount of SPI bit-cycles the cs should stay active after the transmission (0-16)
|
||||
int clock_speed_hz; ///< Clock speed, in Hz
|
||||
int spics_io_num; ///< CS GPIO pin for this device, handled by hardware; set to -1 if not used
|
||||
int spics_ext_io_num; ///< CS GPIO pin for this device, handled by software (spi_lobo_device_select/spi_lobo_device_deselect); only used if spics_io_num=-1
|
||||
uint32_t flags; ///< Bitwise OR of SPI_DEVICE_* flags
|
||||
transaction_cb_t pre_cb; ///< Callback to be called before a transmission is started. This callback from 'spi_lobo_transfer_data' function.
|
||||
transaction_cb_t post_cb; ///< Callback to be called after a transmission has completed. This callback from 'spi_lobo_transfer_data' function.
|
||||
uint8_t selected; ///< **INTERNAL** 1 if the device's CS pin is active
|
||||
} spi_lobo_device_interface_config_t;
|
||||
|
||||
|
||||
#define SPI_TRANS_MODE_DIO (1<<0) ///< Transmit/receive data in 2-bit mode
|
||||
#define SPI_TRANS_MODE_QIO (1<<1) ///< Transmit/receive data in 4-bit mode
|
||||
#define SPI_TRANS_MODE_DIOQIO_ADDR (1<<2) ///< Also transmit address in mode selected by SPI_MODE_DIO/SPI_MODE_QIO
|
||||
#define SPI_TRANS_USE_RXDATA (1<<3) ///< Receive into rx_data member of spi_lobo_transaction_t instead into memory at rx_buffer.
|
||||
#define SPI_TRANS_USE_TXDATA (1<<4) ///< Transmit tx_data member of spi_lobo_transaction_t instead of data at tx_buffer. Do not set tx_buffer when using this.
|
||||
|
||||
/**
|
||||
* This structure describes one SPI transmission
|
||||
*/
|
||||
struct spi_lobo_transaction_t {
|
||||
uint32_t flags; ///< Bitwise OR of SPI_TRANS_* flags
|
||||
uint16_t command; ///< Command data. Specific length was given when device was added to the bus.
|
||||
uint64_t address; ///< Address. Specific length was given when device was added to the bus.
|
||||
size_t length; ///< Total data length to be transmitted to the device, in bits; if 0, no data is transmitted
|
||||
size_t rxlength; ///< Total data length to be received from the device, in bits; if 0, no data is received
|
||||
void *user; ///< User-defined variable. Can be used to store eg transaction ID or data to be used by pre_cb and/or post_cb callbacks.
|
||||
union {
|
||||
const void *tx_buffer; ///< Pointer to transmit buffer, or NULL for no MOSI phase
|
||||
uint8_t tx_data[4]; ///< If SPI_USE_TXDATA is set, data set here is sent directly from this variable.
|
||||
};
|
||||
union {
|
||||
void *rx_buffer; ///< Pointer to receive buffer, or NULL for no MISO phase
|
||||
uint8_t rx_data[4]; ///< If SPI_USE_RXDATA is set, data is received directly to this variable
|
||||
};
|
||||
};
|
||||
|
||||
#define NO_CS 3 // Number of CS pins per SPI host
|
||||
#define NO_DEV 6 // Number of spi devices per SPI host; more than 3 devices can be attached to the same bus if using software CS's
|
||||
#define SPI_SEMAPHORE_WAIT 2000 // Time in ms to wait for SPI mutex
|
||||
|
||||
typedef struct spi_lobo_device_t spi_lobo_device_t;
|
||||
|
||||
typedef struct {
|
||||
spi_lobo_device_t *device[NO_DEV];
|
||||
intr_handle_t intr;
|
||||
spi_dev_t *hw;
|
||||
//spi_lobo_transaction_t *cur_trans;
|
||||
int cur_device;
|
||||
lldesc_t *dmadesc_tx;
|
||||
lldesc_t *dmadesc_rx;
|
||||
bool no_gpio_matrix;
|
||||
int dma_chan;
|
||||
int max_transfer_sz;
|
||||
QueueHandle_t spi_lobo_bus_mutex;
|
||||
spi_lobo_bus_config_t cur_bus_config;
|
||||
} spi_lobo_host_t;
|
||||
|
||||
struct spi_lobo_device_t {
|
||||
spi_lobo_device_interface_config_t cfg;
|
||||
spi_lobo_host_t *host;
|
||||
spi_lobo_bus_config_t bus_config;
|
||||
spi_lobo_host_device_t host_dev;
|
||||
};
|
||||
|
||||
typedef spi_lobo_device_t* spi_lobo_device_handle_t; ///< Handle for a device on a SPI bus
|
||||
typedef spi_lobo_host_t* spi_lobo_host_handle_t;
|
||||
typedef spi_lobo_device_interface_config_t* spi_lobo_device_interface_config_handle_t;
|
||||
|
||||
|
||||
/**
|
||||
* @brief Add a device. This allocates a CS line for the device, allocates memory for the device structure and hooks
|
||||
* up the CS pin to whatever is specified.
|
||||
*
|
||||
* This initializes the internal structures for a device, plus allocates a CS pin on the indicated SPI master
|
||||
* peripheral and routes it to the indicated GPIO. All SPI master devices have three hw CS pins and can thus control
|
||||
* up to three devices. Software handled CS pin can also be used for additional devices on the same SPI bus.
|
||||
*
|
||||
* ### If selected SPI host device bus is not yet initialized, it is initialized first with 'bus_config' function ###
|
||||
*
|
||||
* @note While in general, speeds up to 80MHz on the dedicated SPI pins and 40MHz on GPIO-matrix-routed pins are
|
||||
* supported, full-duplex transfers routed over the GPIO matrix only support speeds up to 26MHz.
|
||||
*
|
||||
* @param host SPI peripheral to allocate device on (HSPI or VSPI)
|
||||
* @param dev_config SPI interface protocol config for the device
|
||||
* @param bus_config Pointer to a spi_lobo_bus_config_t struct specifying how the host device bus should be initialized
|
||||
* @param handle Pointer to variable to hold the device handle
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_NOT_FOUND if host doesn't have any free CS slots
|
||||
* - ESP_ERR_NO_MEM if out of memory
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spi_lobo_bus_add_device(spi_lobo_host_device_t host, spi_lobo_bus_config_t *bus_config, spi_lobo_device_interface_config_t *dev_config, spi_lobo_device_handle_t *handle);
|
||||
|
||||
/**
|
||||
* @brief Remove a device from the SPI bus. If after removal no other device is attached to the spi bus device, it is freed.
|
||||
*
|
||||
* @param handle Device handle to free
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_ERR_INVALID_STATE if device already is freed
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spi_lobo_bus_remove_device(spi_lobo_device_handle_t handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Return the actuall SPI bus speed for the spi device in Hz
|
||||
*
|
||||
* Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
*
|
||||
* @return
|
||||
* - actuall SPI clock
|
||||
*/
|
||||
uint32_t spi_lobo_get_speed(spi_lobo_device_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Set the new clock speed for the device, return the actuall SPI bus speed set, in Hz
|
||||
* This function can be used after the device is initialized
|
||||
*
|
||||
* Some frequencies cannot be set, for example 30000000 will actually set SPI clock to 26666666 Hz
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
* @param speed New device spi clock to be set in Hz
|
||||
*
|
||||
* @return
|
||||
* - actuall SPI clock
|
||||
* - 0 if speed cannot be set
|
||||
*/
|
||||
uint32_t spi_lobo_set_speed(spi_lobo_device_handle_t handle, uint32_t speed);
|
||||
|
||||
/**
|
||||
* @brief Select spi device for transmission
|
||||
*
|
||||
* It configures spi bus with selected spi device parameters if previously selected device was different than the current
|
||||
* If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to active state (low)
|
||||
*
|
||||
* spi bus device's semaphore is taken before selecting the device
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
* @param force configure spi bus even if the previous device was the same
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spi_lobo_device_select(spi_lobo_device_handle_t handle, int force);
|
||||
|
||||
/**
|
||||
* @brief De-select spi device
|
||||
*
|
||||
* If device's spics_io_num=-1 and spics_ext_io_num > 0 'spics_ext_io_num' pin is set to inactive state (high)
|
||||
*
|
||||
* spi bus device's semaphore is given after selecting the device
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP_OK on success
|
||||
*/
|
||||
esp_err_t spi_lobo_device_deselect(spi_lobo_device_handle_t handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Check if spi bus uses native spi pins
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
*
|
||||
* @return
|
||||
* - true if native spi pins are used
|
||||
* - false if spi pins are routed through gpio matrix
|
||||
*/
|
||||
bool spi_lobo_uses_native_pins(spi_lobo_device_handle_t handle);
|
||||
|
||||
/**
|
||||
* @brief Get spi bus native spi pins
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
*
|
||||
* @return
|
||||
* places spi bus native pins in provided pointers
|
||||
*/
|
||||
void spi_lobo_get_native_pins(int host, int *sdi, int *sdo, int *sck);
|
||||
|
||||
/**
|
||||
* @brief Transimit and receive data to/from spi device based on transaction data
|
||||
*
|
||||
* TRANSMIT 8-bit data to spi device from 'trans->tx_buffer' or 'trans->tx_data' (trans->lenght/8 bytes)
|
||||
* and RECEIVE data to 'trans->rx_buffer' or 'trans->rx_data' (trans->rx_length/8 bytes)
|
||||
* Lengths must be 8-bit multiples!
|
||||
* If trans->rx_buffer is NULL or trans->rx_length is 0, only transmits data
|
||||
* If trans->tx_buffer is NULL or trans->length is 0, only receives data
|
||||
* If the device is in duplex mode (SPI_DEVICE_HALFDUPLEX flag NOT set), data are transmitted and received simultaneously.
|
||||
* If the device is in half duplex mode (SPI_DEVICE_HALFDUPLEX flag IS set), data are received after transmission
|
||||
* 'address', 'command' and 'dummy bits' are transmitted before data phase IF set in device's configuration
|
||||
* and IF 'trans->length' and 'trans->rx_length' are NOT both 0
|
||||
* If device was not previously selected, it will be selected before transmission and deselected after transmission.
|
||||
*
|
||||
* @param handle Device handle obtained using spi_lobo_bus_add_device
|
||||
*
|
||||
* @param trans Pointer to variable containing the description of the transaction that is executed
|
||||
*
|
||||
* @return
|
||||
* - ESP_ERR_INVALID_ARG if parameter is invalid
|
||||
* - ESP error code if device cannot be selected
|
||||
* - ESP_OK on success
|
||||
*
|
||||
*/
|
||||
esp_err_t spi_lobo_transfer_data(spi_lobo_device_handle_t handle, spi_lobo_transaction_t *trans);
|
||||
|
||||
|
||||
/*
|
||||
* SPI transactions uses the semaphore (taken in select function) to protect the transfer
|
||||
*/
|
||||
esp_err_t spi_lobo_device_TakeSemaphore(spi_lobo_device_handle_t handle);
|
||||
void spi_lobo_device_GiveSemaphore(spi_lobo_device_handle_t handle);
|
||||
|
||||
|
||||
/**
|
||||
* @brief Setup a DMA link chain
|
||||
*
|
||||
* This routine will set up a chain of linked DMA descriptors in the array pointed to by
|
||||
* ``dmadesc``. Enough DMA descriptors will be used to fit the buffer of ``len`` bytes in, and the
|
||||
* descriptors will point to the corresponding positions in ``buffer`` and linked together. The
|
||||
* end result is that feeding ``dmadesc[0]`` into DMA hardware results in the entirety ``len`` bytes
|
||||
* of ``data`` being read or written.
|
||||
*
|
||||
* @param dmadesc Pointer to array of DMA descriptors big enough to be able to convey ``len`` bytes
|
||||
* @param len Length of buffer
|
||||
* @param data Data buffer to use for DMA transfer
|
||||
* @param isrx True if data is to be written into ``data``, false if it's to be read from ``data``.
|
||||
*/
|
||||
void spi_lobo_setup_dma_desc_links(lldesc_t *dmadesc, int len, const uint8_t *data, bool isrx);
|
||||
|
||||
/**
|
||||
* @brief Check if a DMA reset is requested but has not completed yet
|
||||
*
|
||||
* @return True when a DMA reset is requested but hasn't completed yet. False otherwise.
|
||||
*/
|
||||
bool spi_lobo_dmaworkaround_reset_in_progress();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Mark a DMA channel as idle.
|
||||
*
|
||||
* A call to this function tells the workaround logic that this channel will
|
||||
* not be affected by a global SPI DMA reset.
|
||||
*/
|
||||
void spi_lobo_dmaworkaround_idle(int dmachan);
|
||||
|
||||
/**
|
||||
* @brief Mark a DMA channel as active.
|
||||
*
|
||||
* A call to this function tells the workaround logic that this channel will
|
||||
* be affected by a global SPI DMA reset, and a reset like that should not be attempted.
|
||||
*/
|
||||
void spi_lobo_dmaworkaround_transfer_active(int dmachan);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif
|
7
components/spiffs/component.mk
Normal file
7
components/spiffs/component.mk
Normal file
@ -0,0 +1,7 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS := .
|
||||
COMPONENT_ADD_INCLUDEDIRS := .
|
||||
COMPONENT_PRIV_INCLUDEDIRS :=
|
138
components/spiffs/esp_spiffs.c
Normal file
138
components/spiffs/esp_spiffs.c
Normal file
@ -0,0 +1,138 @@
|
||||
/*
|
||||
* Lua RTOS, SPIFFS low access
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "esp_spiffs.h"
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include "spiffs.h"
|
||||
|
||||
#include <esp_spi_flash.h>
|
||||
|
||||
s32_t IRAM_ATTR esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst) {
|
||||
u32_t aaddr;
|
||||
u8_t *buff = NULL;
|
||||
u8_t *abuff = NULL;
|
||||
u32_t asize;
|
||||
|
||||
asize = size;
|
||||
|
||||
// Align address to 4 byte
|
||||
aaddr = (addr + (4 - 1)) & (u32_t)-4;
|
||||
if (aaddr != addr) {
|
||||
aaddr -= 4;
|
||||
asize += (addr - aaddr);
|
||||
}
|
||||
|
||||
// Align size to 4 byte
|
||||
asize = (asize + (4 - 1)) & (u32_t)-4;
|
||||
|
||||
if ((aaddr != addr) || (asize != size)) {
|
||||
// Align buffer
|
||||
buff = malloc(asize + 4);
|
||||
if (!buff) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
abuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & (u32_t)-4);
|
||||
|
||||
if (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {
|
||||
free(buff);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(dst, abuff + (addr - aaddr), size);
|
||||
|
||||
free(buff);
|
||||
} else {
|
||||
if (spi_flash_read(addr, (void *)dst, size) != 0) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
s32_t IRAM_ATTR esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src) {
|
||||
u32_t aaddr;
|
||||
u8_t *buff = NULL;
|
||||
u8_t *abuff = NULL;
|
||||
u32_t asize;
|
||||
|
||||
asize = size;
|
||||
|
||||
// Align address to 4 byte
|
||||
aaddr = (addr + (4 - 1)) & -4;
|
||||
if (aaddr != addr) {
|
||||
aaddr -= 4;
|
||||
asize += (addr - aaddr);
|
||||
}
|
||||
|
||||
// Align size to 4 byte
|
||||
asize = (asize + (4 - 1)) & -4;
|
||||
|
||||
if ((aaddr != addr) || (asize != size)) {
|
||||
// Align buffer
|
||||
buff = malloc(asize + 4);
|
||||
if (!buff) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
abuff = (u8_t *)(((ptrdiff_t)buff + (4 - 1)) & -4);
|
||||
|
||||
if (spi_flash_read(aaddr, (void *)abuff, asize) != 0) {
|
||||
free(buff);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
memcpy(abuff + (addr - aaddr), src, size);
|
||||
|
||||
if (spi_flash_write(aaddr, (uint32_t *)abuff, asize) != 0) {
|
||||
free(buff);
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
free(buff);
|
||||
} else {
|
||||
if (spi_flash_write(addr, (uint32_t *)src, size) != 0) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
}
|
||||
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
s32_t IRAM_ATTR esp32_spi_flash_erase(u32_t addr, u32_t size) {
|
||||
if (spi_flash_erase_sector(addr >> 12) != 0) {
|
||||
return SPIFFS_ERR_INTERNAL;
|
||||
}
|
||||
|
||||
return SPIFFS_OK;
|
||||
}
|
43
components/spiffs/esp_spiffs.h
Normal file
43
components/spiffs/esp_spiffs.h
Normal file
@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Lua RTOS, write syscall implementation
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
|
||||
#ifndef __ESP_SPIFFS_H__
|
||||
#define __ESP_SPIFFS_H__
|
||||
|
||||
#include "spiffs.h"
|
||||
|
||||
s32_t esp32_spi_flash_read(u32_t addr, u32_t size, u8_t *dst);
|
||||
s32_t esp32_spi_flash_write(u32_t addr, u32_t size, const u8_t *src);
|
||||
s32_t esp32_spi_flash_erase(u32_t addr, u32_t size);
|
||||
|
||||
#define low_spiffs_read (spiffs_read *)esp32_spi_flash_read
|
||||
#define low_spiffs_write (spiffs_write *)esp32_spi_flash_write
|
||||
#define low_spiffs_erase (spiffs_erase *)esp32_spi_flash_erase
|
||||
|
||||
#endif // __ESP_SPIFFS_H__
|
251
components/spiffs/list.c
Normal file
251
components/spiffs/list.c
Normal file
@ -0,0 +1,251 @@
|
||||
/*
|
||||
* Lua RTOS, list data structure
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
|
||||
#include "esp_attr.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "list.h"
|
||||
#include "mutex.h"
|
||||
|
||||
void list_init(struct list *list, int first_index) {
|
||||
// Create the mutex
|
||||
mtx_init(&list->mutex, NULL, NULL, 0);
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
list->indexes = 0;
|
||||
list->free = NULL;
|
||||
list->index = NULL;
|
||||
list->first_index = first_index;
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
}
|
||||
|
||||
int list_add(struct list *list, void *item, int *item_index) {
|
||||
struct list_index *index = NULL;
|
||||
struct list_index *indexa = NULL;
|
||||
int grow = 0;
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
// Get an index
|
||||
if (list->free) {
|
||||
// Get first free element
|
||||
index = list->free;
|
||||
list->free = index->next;
|
||||
} else {
|
||||
// Must grow index array
|
||||
grow = 1;
|
||||
}
|
||||
|
||||
if (grow) {
|
||||
// Increment index count
|
||||
list->indexes++;
|
||||
|
||||
// Create a new index array for allocate new index
|
||||
indexa = (struct list_index *)malloc(sizeof(struct list_index) * list->indexes);
|
||||
if (!indexa) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
if (list->index) {
|
||||
// Copy current index array to new created
|
||||
bcopy(list->index, indexa, sizeof(struct list_index) * (list->indexes - 1));
|
||||
|
||||
// Free current index array
|
||||
free(list->index);
|
||||
}
|
||||
|
||||
// Store new index array
|
||||
list->index = indexa;
|
||||
|
||||
// Current index
|
||||
index = list->index + list->indexes - 1;
|
||||
|
||||
// Initialize new index
|
||||
index->index = list->indexes - 1;
|
||||
|
||||
}
|
||||
|
||||
index->next = NULL;
|
||||
index->item = item;
|
||||
index->deleted = 0;
|
||||
|
||||
// Return index
|
||||
*item_index = index->index + list->first_index;
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR list_get(struct list *list, int index, void **item) {
|
||||
struct list_index *cindex = NULL;
|
||||
int iindex;
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
if (!list->indexes) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
// Check index
|
||||
if (index < list->first_index) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
// Get new internal index
|
||||
iindex = index - list->first_index;
|
||||
|
||||
// Test for a valid index
|
||||
if (iindex > list->indexes) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
cindex = list->index + iindex;
|
||||
|
||||
if (cindex->deleted) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
*item = cindex->item;
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int list_remove(struct list *list, int index, int destroy) {
|
||||
struct list_index *cindex = NULL;
|
||||
int iindex;
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
// Check index
|
||||
if (index < list->first_index) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
// Get new internal index
|
||||
iindex = index - list->first_index;
|
||||
|
||||
// Test for a valid index
|
||||
if ((iindex < 0) || (iindex > list->indexes)) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return EINVAL;
|
||||
}
|
||||
|
||||
cindex = &list->index[iindex];
|
||||
|
||||
if (destroy) {
|
||||
free(cindex->item);
|
||||
}
|
||||
|
||||
cindex->next = list->free;
|
||||
cindex->deleted = 1;
|
||||
list->free = cindex;
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int IRAM_ATTR list_first(struct list *list) {
|
||||
int index;
|
||||
int res = -1;
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
for(index=0;index < list->indexes;index++) {
|
||||
if (!list->index[index].deleted) {
|
||||
res = index + list->first_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
int IRAM_ATTR list_next(struct list *list, int index) {
|
||||
int res = -1;
|
||||
int iindex;
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
// Check index
|
||||
if (index < list->first_index) {
|
||||
mtx_unlock(&list->mutex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Get new internal index
|
||||
iindex = index - list->first_index + 1;
|
||||
|
||||
// Get next non deleted item on list
|
||||
for(;iindex < list->indexes;iindex++) {
|
||||
if (!list->index[iindex].deleted) {
|
||||
res = iindex + list->first_index;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void list_destroy(struct list *list, int items) {
|
||||
int index;
|
||||
|
||||
mtx_lock(&list->mutex);
|
||||
|
||||
if (items) {
|
||||
for(index=0;index < list->indexes;index++) {
|
||||
if (!list->index[index].deleted) {
|
||||
free(list->index[index].item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
free(list->index);
|
||||
|
||||
mtx_unlock(&list->mutex);
|
||||
mtx_destroy(&list->mutex);
|
||||
}
|
60
components/spiffs/list.h
Normal file
60
components/spiffs/list.h
Normal file
@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Lua RTOS, list data structure
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*/
|
||||
|
||||
#ifndef _LIST_H
|
||||
#define _LIST_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include "mutex.h"
|
||||
|
||||
struct list {
|
||||
struct mtx mutex;
|
||||
struct list_index *index;
|
||||
struct list_index *free;
|
||||
uint8_t indexes;
|
||||
uint8_t first_index;
|
||||
};
|
||||
|
||||
struct list_index {
|
||||
void *item;
|
||||
uint8_t index;
|
||||
uint8_t deleted;
|
||||
struct list_index *next;
|
||||
};
|
||||
|
||||
void list_init(struct list *list, int first_index);
|
||||
int list_add(struct list *list, void *item, int *item_index);
|
||||
int list_get(struct list *list, int index, void **item);
|
||||
int list_remove(struct list *list, int index, int destroy);
|
||||
int list_first(struct list *list);
|
||||
int list_next(struct list *list, int index);
|
||||
void list_destroy(struct list *list, int items);
|
||||
|
||||
#endif /* LIST_H */
|
||||
|
102
components/spiffs/mutex.c
Normal file
102
components/spiffs/mutex.c
Normal file
@ -0,0 +1,102 @@
|
||||
/*
|
||||
* Lua RTOS, mutex api implementation over FreeRTOS
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*
|
||||
* Modified by: LoBo (loboris@gmail.com / https://github.com/loboris)
|
||||
*
|
||||
*/
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "esp_attr.h"
|
||||
#include "mutex.h"
|
||||
|
||||
|
||||
#define portEND_SWITCHING_ISR(xSwitchRequired) \
|
||||
if (xSwitchRequired) { \
|
||||
_frxt_setup_switch(); \
|
||||
}
|
||||
|
||||
extern unsigned port_interruptNesting[portNUM_PROCESSORS];
|
||||
|
||||
void _mtx_init() {
|
||||
}
|
||||
|
||||
void mtx_init(struct mtx *mutex, const char *name, const char *type, int opts) {
|
||||
mutex->sem = xSemaphoreCreateBinary();
|
||||
|
||||
if (mutex->sem) {
|
||||
if (port_interruptNesting[xPortGetCoreID()] != 0) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xSemaphoreGiveFromISR( mutex->sem, &xHigherPriorityTaskWoken);
|
||||
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
||||
} else {
|
||||
xSemaphoreGive( mutex->sem );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR mtx_lock(struct mtx *mutex) {
|
||||
if (port_interruptNesting[xPortGetCoreID()] != 0) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xSemaphoreTakeFromISR( mutex->sem, &xHigherPriorityTaskWoken );
|
||||
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
||||
} else {
|
||||
xSemaphoreTake( mutex->sem, portMAX_DELAY );
|
||||
}
|
||||
}
|
||||
|
||||
int mtx_trylock(struct mtx *mutex) {
|
||||
if (xSemaphoreTake( mutex->sem, 0 ) == pdTRUE) {
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void IRAM_ATTR mtx_unlock(struct mtx *mutex) {
|
||||
if (port_interruptNesting[xPortGetCoreID()] != 0) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xSemaphoreGiveFromISR( mutex->sem, &xHigherPriorityTaskWoken );
|
||||
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
||||
} else {
|
||||
xSemaphoreGive( mutex->sem );
|
||||
}
|
||||
}
|
||||
|
||||
void mtx_destroy(struct mtx *mutex) {
|
||||
if (port_interruptNesting[xPortGetCoreID()] != 0) {
|
||||
BaseType_t xHigherPriorityTaskWoken = pdFALSE;
|
||||
xSemaphoreGiveFromISR( mutex->sem, &xHigherPriorityTaskWoken );
|
||||
portEND_SWITCHING_ISR( xHigherPriorityTaskWoken );
|
||||
} else {
|
||||
xSemaphoreGive( mutex->sem );
|
||||
}
|
||||
|
||||
vSemaphoreDelete( mutex->sem );
|
||||
|
||||
mutex->sem = 0;
|
||||
}
|
53
components/spiffs/mutex.h
Normal file
53
components/spiffs/mutex.h
Normal file
@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Lua RTOS, mutex api implementation over FreeRTOS
|
||||
*
|
||||
* Copyright (C) 2015 - 2017
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
*
|
||||
* Author: Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
* All rights reserved.
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software
|
||||
* and its documentation for any purpose and without fee is hereby
|
||||
* granted, provided that the above copyright notice appear in all
|
||||
* copies and that both that the copyright notice and this
|
||||
* permission notice and warranty disclaimer appear in supporting
|
||||
* documentation, and that the name of the author not be used in
|
||||
* advertising or publicity pertaining to distribution of the
|
||||
* software without specific, written prior permission.
|
||||
*
|
||||
* The author disclaim all warranties with regard to this
|
||||
* software, including all implied warranties of merchantability
|
||||
* and fitness. In no event shall the author be liable for any
|
||||
* special, indirect or consequential damages or any damages
|
||||
* whatsoever resulting from loss of use, data or profits, whether
|
||||
* in an action of contract, negligence or other tortious action,
|
||||
* arising out of or in connection with the use or performance of
|
||||
* this software.
|
||||
*
|
||||
* Modified by: LoBo (loboris@gmail.com / https://github.com/loboris)
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef MUTEX_H_H
|
||||
#define MUTEX_H_H
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
#define MUTEX_INITIALIZER {.sem = 0}
|
||||
|
||||
struct mtx {
|
||||
SemaphoreHandle_t sem;
|
||||
};
|
||||
|
||||
|
||||
void mtx_init(struct mtx *mutex, const char *name, const char *type, int opts);
|
||||
void mtx_lock(struct mtx *mutex);
|
||||
int mtx_trylock(struct mtx *mutex);
|
||||
void mtx_unlock(struct mtx *mutex);
|
||||
void mtx_destroy(struct mtx *mutex);
|
||||
|
||||
#endif /* MUTEX_H_H */
|
||||
|
813
components/spiffs/spiffs.h
Normal file
813
components/spiffs/spiffs.h
Normal file
@ -0,0 +1,813 @@
|
||||
/*
|
||||
* spiffs.h
|
||||
*
|
||||
* Created on: May 26, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_H_
|
||||
#define SPIFFS_H_
|
||||
#if defined(__cplusplus)
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include "spiffs_config.h"
|
||||
|
||||
#define SPIFFS_OK 0
|
||||
#define SPIFFS_ERR_NOT_MOUNTED -10000
|
||||
#define SPIFFS_ERR_FULL -10001
|
||||
#define SPIFFS_ERR_NOT_FOUND -10002
|
||||
#define SPIFFS_ERR_END_OF_OBJECT -10003
|
||||
#define SPIFFS_ERR_DELETED -10004
|
||||
#define SPIFFS_ERR_NOT_FINALIZED -10005
|
||||
#define SPIFFS_ERR_NOT_INDEX -10006
|
||||
#define SPIFFS_ERR_OUT_OF_FILE_DESCS -10007
|
||||
#define SPIFFS_ERR_FILE_CLOSED -10008
|
||||
#define SPIFFS_ERR_FILE_DELETED -10009
|
||||
#define SPIFFS_ERR_BAD_DESCRIPTOR -10010
|
||||
#define SPIFFS_ERR_IS_INDEX -10011
|
||||
#define SPIFFS_ERR_IS_FREE -10012
|
||||
#define SPIFFS_ERR_INDEX_SPAN_MISMATCH -10013
|
||||
#define SPIFFS_ERR_DATA_SPAN_MISMATCH -10014
|
||||
#define SPIFFS_ERR_INDEX_REF_FREE -10015
|
||||
#define SPIFFS_ERR_INDEX_REF_LU -10016
|
||||
#define SPIFFS_ERR_INDEX_REF_INVALID -10017
|
||||
#define SPIFFS_ERR_INDEX_FREE -10018
|
||||
#define SPIFFS_ERR_INDEX_LU -10019
|
||||
#define SPIFFS_ERR_INDEX_INVALID -10020
|
||||
#define SPIFFS_ERR_NOT_WRITABLE -10021
|
||||
#define SPIFFS_ERR_NOT_READABLE -10022
|
||||
#define SPIFFS_ERR_CONFLICTING_NAME -10023
|
||||
#define SPIFFS_ERR_NOT_CONFIGURED -10024
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FS -10025
|
||||
#define SPIFFS_ERR_MOUNTED -10026
|
||||
#define SPIFFS_ERR_ERASE_FAIL -10027
|
||||
#define SPIFFS_ERR_MAGIC_NOT_POSSIBLE -10028
|
||||
|
||||
#define SPIFFS_ERR_NO_DELETED_BLOCKS -10029
|
||||
|
||||
#define SPIFFS_ERR_FILE_EXISTS -10030
|
||||
|
||||
#define SPIFFS_ERR_NOT_A_FILE -10031
|
||||
#define SPIFFS_ERR_RO_NOT_IMPL -10032
|
||||
#define SPIFFS_ERR_RO_ABORTED_OPERATION -10033
|
||||
#define SPIFFS_ERR_PROBE_TOO_FEW_BLOCKS -10034
|
||||
#define SPIFFS_ERR_PROBE_NOT_A_FS -10035
|
||||
#define SPIFFS_ERR_NAME_TOO_LONG -10036
|
||||
|
||||
#define SPIFFS_ERR_IX_MAP_UNMAPPED -10037
|
||||
#define SPIFFS_ERR_IX_MAP_MAPPED -10038
|
||||
#define SPIFFS_ERR_IX_MAP_BAD_RANGE -10039
|
||||
|
||||
#define SPIFFS_ERR_INTERNAL -10050
|
||||
|
||||
#define SPIFFS_ERR_TEST -10100
|
||||
|
||||
|
||||
// spiffs file descriptor index type. must be signed
|
||||
typedef s16_t spiffs_file;
|
||||
// spiffs file descriptor flags
|
||||
typedef u16_t spiffs_flags;
|
||||
// spiffs file mode
|
||||
typedef u16_t spiffs_mode;
|
||||
// object type
|
||||
typedef u8_t spiffs_obj_type;
|
||||
|
||||
struct spiffs_t;
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(struct spiffs_t *fs, u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(struct spiffs_t *fs, u32_t addr, u32_t size);
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* spi read call function type */
|
||||
typedef s32_t (*spiffs_read)(u32_t addr, u32_t size, u8_t *dst);
|
||||
/* spi write call function type */
|
||||
typedef s32_t (*spiffs_write)(u32_t addr, u32_t size, u8_t *src);
|
||||
/* spi erase call function type */
|
||||
typedef s32_t (*spiffs_erase)(u32_t addr, u32_t size);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system check callback report operation */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_LOOKUP = 0,
|
||||
SPIFFS_CHECK_INDEX,
|
||||
SPIFFS_CHECK_PAGE
|
||||
} spiffs_check_type;
|
||||
|
||||
/* file system check callback report type */
|
||||
typedef enum {
|
||||
SPIFFS_CHECK_PROGRESS = 0,
|
||||
SPIFFS_CHECK_ERROR,
|
||||
SPIFFS_CHECK_FIX_INDEX,
|
||||
SPIFFS_CHECK_FIX_LOOKUP,
|
||||
SPIFFS_CHECK_DELETE_ORPHANED_INDEX,
|
||||
SPIFFS_CHECK_DELETE_PAGE,
|
||||
SPIFFS_CHECK_DELETE_BAD_FILE
|
||||
} spiffs_check_report;
|
||||
|
||||
/* file system check callback function */
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(struct spiffs_t *fs, spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
typedef void (*spiffs_check_callback)(spiffs_check_type type, spiffs_check_report report,
|
||||
u32_t arg1, u32_t arg2);
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
/* file system listener callback operation */
|
||||
typedef enum {
|
||||
/* the file has been created */
|
||||
SPIFFS_CB_CREATED = 0,
|
||||
/* the file has been updated or moved to another page */
|
||||
SPIFFS_CB_UPDATED,
|
||||
/* the file has been deleted */
|
||||
SPIFFS_CB_DELETED
|
||||
} spiffs_fileop_type;
|
||||
|
||||
/* file system listener callback function */
|
||||
typedef void (*spiffs_file_callback)(struct spiffs_t *fs, spiffs_fileop_type op, spiffs_obj_id obj_id, spiffs_page_ix pix);
|
||||
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) \
|
||||
printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
/* Any write to the filehandle is appended to end of the file */
|
||||
#define SPIFFS_APPEND (1<<0)
|
||||
#define SPIFFS_O_APPEND SPIFFS_APPEND
|
||||
/* If the opened file exists, it will be truncated to zero length before opened */
|
||||
#define SPIFFS_TRUNC (1<<1)
|
||||
#define SPIFFS_O_TRUNC SPIFFS_TRUNC
|
||||
/* If the opened file does not exist, it will be created before opened */
|
||||
#define SPIFFS_CREAT (1<<2)
|
||||
#define SPIFFS_O_CREAT SPIFFS_CREAT
|
||||
/* The opened file may only be read */
|
||||
#define SPIFFS_RDONLY (1<<3)
|
||||
#define SPIFFS_O_RDONLY SPIFFS_RDONLY
|
||||
/* The opened file may only be written */
|
||||
#define SPIFFS_WRONLY (1<<4)
|
||||
#define SPIFFS_O_WRONLY SPIFFS_WRONLY
|
||||
/* The opened file may be both read and written */
|
||||
#define SPIFFS_RDWR (SPIFFS_RDONLY | SPIFFS_WRONLY)
|
||||
#define SPIFFS_O_RDWR SPIFFS_RDWR
|
||||
/* Any writes to the filehandle will never be cached but flushed directly */
|
||||
#define SPIFFS_DIRECT (1<<5)
|
||||
#define SPIFFS_O_DIRECT SPIFFS_DIRECT
|
||||
/* If SPIFFS_O_CREAT and SPIFFS_O_EXCL are set, SPIFFS_open() shall fail if the file exists */
|
||||
#define SPIFFS_EXCL (1<<6)
|
||||
#define SPIFFS_O_EXCL SPIFFS_EXCL
|
||||
|
||||
#define SPIFFS_SEEK_SET (0)
|
||||
#define SPIFFS_SEEK_CUR (1)
|
||||
#define SPIFFS_SEEK_END (2)
|
||||
|
||||
#define SPIFFS_TYPE_FILE (1)
|
||||
#define SPIFFS_TYPE_DIR (2)
|
||||
#define SPIFFS_TYPE_HARD_LINK (3)
|
||||
#define SPIFFS_TYPE_SOFT_LINK (4)
|
||||
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs)
|
||||
#endif
|
||||
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs)
|
||||
#endif
|
||||
|
||||
// phys structs
|
||||
|
||||
// spiffs spi configuration struct
|
||||
typedef struct {
|
||||
// physical read function
|
||||
spiffs_read hal_read_f;
|
||||
// physical write function
|
||||
spiffs_write hal_write_f;
|
||||
// physical erase function
|
||||
spiffs_erase hal_erase_f;
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
// physical size of the spi flash
|
||||
u32_t phys_size;
|
||||
// physical offset in spi flash used for spiffs,
|
||||
// must be on block boundary
|
||||
u32_t phys_addr;
|
||||
// physical size when erasing a block
|
||||
u32_t phys_erase_block;
|
||||
|
||||
// logical size of a block, must be on physical
|
||||
// block size boundary and must never be less than
|
||||
// a physical block
|
||||
u32_t log_block_size;
|
||||
// logical size of a page, must be at least
|
||||
// log_block_size / 8
|
||||
u32_t log_page_size;
|
||||
|
||||
#endif
|
||||
#if SPIFFS_FILEHDL_OFFSET
|
||||
// an integer offset added to each file handle
|
||||
u16_t fh_ix_offset;
|
||||
#endif
|
||||
} spiffs_config;
|
||||
|
||||
typedef struct spiffs_t {
|
||||
// file system configuration
|
||||
spiffs_config cfg;
|
||||
// number of logical blocks
|
||||
u32_t block_count;
|
||||
|
||||
// cursor for free blocks, block index
|
||||
spiffs_block_ix free_cursor_block_ix;
|
||||
// cursor for free blocks, entry index
|
||||
int free_cursor_obj_lu_entry;
|
||||
// cursor when searching, block index
|
||||
spiffs_block_ix cursor_block_ix;
|
||||
// cursor when searching, entry index
|
||||
int cursor_obj_lu_entry;
|
||||
|
||||
// primary work buffer, size of a logical page
|
||||
u8_t *lu_work;
|
||||
// secondary work buffer, size of a logical page
|
||||
u8_t *work;
|
||||
// file descriptor memory area
|
||||
u8_t *fd_space;
|
||||
// available file descriptors
|
||||
u32_t fd_count;
|
||||
|
||||
// last error
|
||||
s32_t err_code;
|
||||
|
||||
// current number of free blocks
|
||||
u32_t free_blocks;
|
||||
// current number of busy pages
|
||||
u32_t stats_p_allocated;
|
||||
// current number of deleted pages
|
||||
u32_t stats_p_deleted;
|
||||
// flag indicating that garbage collector is cleaning
|
||||
u8_t cleaning;
|
||||
// max erase count amongst all blocks
|
||||
spiffs_obj_id max_erase_count;
|
||||
|
||||
#if SPIFFS_GC_STATS
|
||||
u32_t stats_gc_runs;
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
// cache memory
|
||||
void *cache;
|
||||
// cache size
|
||||
u32_t cache_size;
|
||||
#if SPIFFS_CACHE_STATS
|
||||
u32_t cache_hits;
|
||||
u32_t cache_misses;
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// check callback function
|
||||
spiffs_check_callback check_cb_f;
|
||||
// file callback function
|
||||
spiffs_file_callback file_cb_f;
|
||||
// mounted flag
|
||||
u8_t mounted;
|
||||
// user data
|
||||
void *user_data;
|
||||
// config magic
|
||||
u32_t config_magic;
|
||||
} spiffs;
|
||||
|
||||
/* spiffs file status struct */
|
||||
typedef struct {
|
||||
spiffs_obj_id obj_id;
|
||||
u32_t size;
|
||||
spiffs_obj_type type;
|
||||
spiffs_page_ix pix;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
} spiffs_stat;
|
||||
|
||||
struct spiffs_dirent {
|
||||
spiffs_obj_id obj_id;
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
spiffs_obj_type type;
|
||||
u32_t size;
|
||||
spiffs_page_ix pix;
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
spiffs *fs;
|
||||
spiffs_block_ix block;
|
||||
int entry;
|
||||
} spiffs_DIR;
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
typedef struct {
|
||||
// buffer with looked up data pixes
|
||||
spiffs_page_ix *map_buf;
|
||||
// precise file byte offset
|
||||
u32_t offset;
|
||||
// start data span index of lookup buffer
|
||||
spiffs_span_ix start_spix;
|
||||
// end data span index of lookup buffer
|
||||
spiffs_span_ix end_spix;
|
||||
} spiffs_ix_map;
|
||||
|
||||
#endif
|
||||
|
||||
// functions
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
/**
|
||||
* Special function. This takes a spiffs config struct and returns the number
|
||||
* of blocks this file system was formatted with. This function relies on
|
||||
* that following info is set correctly in given config struct:
|
||||
*
|
||||
* phys_addr, log_page_size, and log_block_size.
|
||||
*
|
||||
* Also, hal_read_f must be set in the config struct.
|
||||
*
|
||||
* One must be sure of the correct page size and that the physical address is
|
||||
* correct in the probed file system when calling this function. It is not
|
||||
* checked if the phys_addr actually points to the start of the file system,
|
||||
* so one might get a false positive if entering a phys_addr somewhere in the
|
||||
* middle of the file system at block boundary. In addition, it is not checked
|
||||
* if the page size is actually correct. If it is not, weird file system sizes
|
||||
* will be returned.
|
||||
*
|
||||
* If this function detects a file system it returns the assumed file system
|
||||
* size, which can be used to set the phys_size.
|
||||
*
|
||||
* Otherwise, it returns an error indicating why it is not regarded as a file
|
||||
* system.
|
||||
*
|
||||
* Note: this function is not protected with SPIFFS_LOCK and SPIFFS_UNLOCK
|
||||
* macros. It returns the error code directly, instead of as read by
|
||||
* SPIFFS_errno.
|
||||
*
|
||||
* @param config essential parts of the physical and logical
|
||||
* configuration of the file system.
|
||||
*/
|
||||
s32_t SPIFFS_probe_fs(spiffs_config *config);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH && SPIFFS_SINGLETON==0
|
||||
|
||||
/**
|
||||
* Initializes the file system dynamic parameters and mounts the filesystem.
|
||||
* If SPIFFS_USE_MAGIC is enabled the mounting may fail with SPIFFS_ERR_NOT_A_FS
|
||||
* if the flash does not contain a recognizable file system.
|
||||
* In this case, SPIFFS_format must be called prior to remounting.
|
||||
* @param fs the file system struct
|
||||
* @param config the physical and logical configuration of the file system
|
||||
* @param work a memory work buffer comprising 2*config->log_page_size
|
||||
* bytes used throughout all file system operations
|
||||
* @param fd_space memory for file descriptors
|
||||
* @param fd_space_size memory size of file descriptors
|
||||
* @param cache memory for cache, may be null
|
||||
* @param cache_size memory size of cache
|
||||
* @param check_cb_f callback function for reporting during consistency checks
|
||||
*/
|
||||
s32_t SPIFFS_mount(spiffs *fs, spiffs_config *config, u8_t *work,
|
||||
u8_t *fd_space, u32_t fd_space_size,
|
||||
void *cache, u32_t cache_size,
|
||||
spiffs_check_callback check_cb_f);
|
||||
|
||||
/**
|
||||
* Unmounts the file system. All file handles will be flushed of any
|
||||
* cached writes and closed.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_unmount(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Creates a new file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
s32_t SPIFFS_creat(spiffs *fs, const char *path, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens/creates a file.
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the new file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_O_APPEND, SPIFFS_O_TRUNC, SPIFFS_O_CREAT, SPIFFS_O_RDONLY,
|
||||
* SPIFFS_O_WRONLY, SPIFFS_O_RDWR, SPIFFS_O_DIRECT, SPIFFS_O_EXCL
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open(spiffs *fs, const char *path, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given dir entry.
|
||||
* Optimization purposes, when traversing a file system with SPIFFS_readdir
|
||||
* a normal SPIFFS_open would need to traverse the filesystem again to find
|
||||
* the file, whilst SPIFFS_open_by_dirent already knows where the file resides.
|
||||
* @param fs the file system struct
|
||||
* @param e the dir entry to the file
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_dirent(spiffs *fs, struct spiffs_dirent *e, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Opens a file by given page index.
|
||||
* Optimization purposes, opens a file by directly pointing to the page
|
||||
* index in the spi flash.
|
||||
* If the page index does not point to a file header SPIFFS_ERR_NOT_A_FILE
|
||||
* is returned.
|
||||
* @param fs the file system struct
|
||||
* @param page_ix the page index
|
||||
* @param flags the flags for the open command, can be combinations of
|
||||
* SPIFFS_APPEND, SPIFFS_TRUNC, SPIFFS_CREAT, SPIFFS_RD_ONLY,
|
||||
* SPIFFS_WR_ONLY, SPIFFS_RDWR, SPIFFS_DIRECT.
|
||||
* SPIFFS_CREAT will have no effect in this case.
|
||||
* @param mode ignored, for posix compliance
|
||||
*/
|
||||
spiffs_file SPIFFS_open_by_page(spiffs *fs, spiffs_page_ix page_ix, spiffs_flags flags, spiffs_mode mode);
|
||||
|
||||
/**
|
||||
* Reads from given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf where to put read data
|
||||
* @param len how much to read
|
||||
* @returns number of bytes read, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_read(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Writes to given filehandle.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param buf the data to write
|
||||
* @param len how much to write
|
||||
* @returns number of bytes written, or -1 if error
|
||||
*/
|
||||
s32_t SPIFFS_write(spiffs *fs, spiffs_file fh, void *buf, s32_t len);
|
||||
|
||||
/**
|
||||
* Moves the read/write file offset. Resulting offset is returned or negative if error.
|
||||
* lseek(fs, fd, 0, SPIFFS_SEEK_CUR) will thus return current offset.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle
|
||||
* @param offs how much/where to move the offset
|
||||
* @param whence if SPIFFS_SEEK_SET, the file offset shall be set to offset bytes
|
||||
* if SPIFFS_SEEK_CUR, the file offset shall be set to its current location plus offset
|
||||
* if SPIFFS_SEEK_END, the file offset shall be set to the size of the file plus offse, which should be negative
|
||||
*/
|
||||
s32_t SPIFFS_lseek(spiffs *fs, spiffs_file fh, s32_t offs, int whence);
|
||||
|
||||
/**
|
||||
* Removes a file by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_remove(spiffs *fs, const char *path);
|
||||
|
||||
/**
|
||||
* Removes a file by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to remove
|
||||
*/
|
||||
s32_t SPIFFS_fremove(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Gets file status by path
|
||||
* @param fs the file system struct
|
||||
* @param path the path of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_stat(spiffs *fs, const char *path, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Gets file status by filehandle
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to stat
|
||||
* @param s the stat struct to populate
|
||||
*/
|
||||
s32_t SPIFFS_fstat(spiffs *fs, spiffs_file fh, spiffs_stat *s);
|
||||
|
||||
/**
|
||||
* Flushes all pending write operations from cache for given file
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to flush
|
||||
*/
|
||||
s32_t SPIFFS_fflush(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Closes a filehandle. If there are pending write operations, these are finalized before closing.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to close
|
||||
*/
|
||||
s32_t SPIFFS_close(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Renames a file
|
||||
* @param fs the file system struct
|
||||
* @param old path of file to rename
|
||||
* @param newPath new path of file
|
||||
*/
|
||||
s32_t SPIFFS_rename(spiffs *fs, const char *old, const char *newPath);
|
||||
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
/**
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param path path to the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_update_meta(spiffs *fs, const char *name, const void *meta);
|
||||
|
||||
/**
|
||||
* Updates file's metadata
|
||||
* @param fs the file system struct
|
||||
* @param fh file handle of the file
|
||||
* @param meta new metadata. must be SPIFFS_OBJ_META_LEN bytes long.
|
||||
*/
|
||||
s32_t SPIFFS_fupdate_meta(spiffs *fs, spiffs_file fh, const void *meta);
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns last error of last file operation.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_errno(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Clears last error.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
void SPIFFS_clearerr(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Opens a directory stream corresponding to the given name.
|
||||
* The stream is positioned at the first entry in the directory.
|
||||
* On hydrogen builds the name argument is ignored as hydrogen builds always correspond
|
||||
* to a flat file structure - no directories.
|
||||
* @param fs the file system struct
|
||||
* @param name the name of the directory
|
||||
* @param d pointer the directory stream to be populated
|
||||
*/
|
||||
spiffs_DIR *SPIFFS_opendir(spiffs *fs, const char *name, spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Closes a directory stream
|
||||
* @param d the directory stream to close
|
||||
*/
|
||||
s32_t SPIFFS_closedir(spiffs_DIR *d);
|
||||
|
||||
/**
|
||||
* Reads a directory into given spifs_dirent struct.
|
||||
* @param d pointer to the directory stream
|
||||
* @param e the dirent struct to be populated
|
||||
* @returns null if error or end of stream, else given dirent is returned
|
||||
*/
|
||||
struct spiffs_dirent *SPIFFS_readdir(spiffs_DIR *d, struct spiffs_dirent *e);
|
||||
|
||||
/**
|
||||
* Runs a consistency check on given filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_check(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns number of total bytes available and number of used bytes.
|
||||
* This is an estimation, and depends on if there a many files with little
|
||||
* data or few files with much data.
|
||||
* NB: If used number of bytes exceeds total bytes, a SPIFFS_check should
|
||||
* run. This indicates a power loss in midst of things. In worst case
|
||||
* (repeated powerlosses in mending or gc) you might have to delete some files.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param total total number of bytes in filesystem
|
||||
* @param used used number of bytes in filesystem
|
||||
*/
|
||||
s32_t SPIFFS_info(spiffs *fs, u32_t *total, u32_t *used);
|
||||
|
||||
/**
|
||||
* Formats the entire file system. All data will be lost.
|
||||
* The filesystem must not be mounted when calling this.
|
||||
*
|
||||
* NB: formatting is awkward. Due to backwards compatibility, SPIFFS_mount
|
||||
* MUST be called prior to formatting in order to configure the filesystem.
|
||||
* If SPIFFS_mount succeeds, SPIFFS_unmount must be called before calling
|
||||
* SPIFFS_format.
|
||||
* If SPIFFS_mount fails, SPIFFS_format can be called directly without calling
|
||||
* SPIFFS_unmount first.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_format(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Returns nonzero if spiffs is mounted, or zero if unmounted.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
u8_t SPIFFS_mounted(spiffs *fs);
|
||||
|
||||
/**
|
||||
* Tries to find a block where most or all pages are deleted, and erase that
|
||||
* block if found. Does not care for wear levelling. Will not move pages
|
||||
* around.
|
||||
* If parameter max_free_pages are set to 0, only blocks with only deleted
|
||||
* pages will be selected.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* Setting max_free_pages to anything larger than zero will eventually wear
|
||||
* flash more as a block containing free pages can be erased.
|
||||
*
|
||||
* Will set err_no to SPIFFS_OK if a block was found and erased,
|
||||
* SPIFFS_ERR_NO_DELETED_BLOCK if no matching block was found,
|
||||
* or other error.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param max_free_pages maximum number allowed free pages in block
|
||||
*/
|
||||
s32_t SPIFFS_gc_quick(spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
/**
|
||||
* Will try to make room for given amount of bytes in the filesystem by moving
|
||||
* pages and erasing blocks.
|
||||
* If it is physically impossible, err_no will be set to SPIFFS_ERR_FULL. If
|
||||
* there already is this amount (or more) of free space, SPIFFS_gc will
|
||||
* silently return. It is recommended to call SPIFFS_info before invoking
|
||||
* this method in order to determine what amount of bytes to give.
|
||||
*
|
||||
* NB: the garbage collector is automatically called when spiffs needs free
|
||||
* pages. The reason for this function is to give possibility to do background
|
||||
* tidying when user knows the system is idle.
|
||||
*
|
||||
* Use with care.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param size amount of bytes that should be freed
|
||||
*/
|
||||
s32_t SPIFFS_gc(spiffs *fs, u32_t size);
|
||||
|
||||
/**
|
||||
* Check if EOF reached.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_eof(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Get position in file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the filehandle of the file to check
|
||||
*/
|
||||
s32_t SPIFFS_tell(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Registers a callback function that keeps track on operations on file
|
||||
* headers. Do note, that this callback is called from within internal spiffs
|
||||
* mechanisms. Any operations on the actual file system being callbacked from
|
||||
* in this callback will mess things up for sure - do not do this.
|
||||
* This can be used to track where files are and move around during garbage
|
||||
* collection, which in turn can be used to build location tables in ram.
|
||||
* Used in conjuction with SPIFFS_open_by_page this may improve performance
|
||||
* when opening a lot of files.
|
||||
* Must be invoked after mount.
|
||||
*
|
||||
* @param fs the file system struct
|
||||
* @param cb_func the callback on file operations
|
||||
*/
|
||||
s32_t SPIFFS_set_file_callback_func(spiffs *fs, spiffs_file_callback cb_func);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
/**
|
||||
* Maps the first level index lookup to a given memory map.
|
||||
* This will make reading big files faster, as the memory map will be used for
|
||||
* looking up data pages instead of searching for the indices on the physical
|
||||
* medium. When mapping, all affected indicies are found and the information is
|
||||
* copied to the array.
|
||||
* Whole file or only parts of it may be mapped. The index map will cover file
|
||||
* contents from argument offset until and including arguments (offset+len).
|
||||
* It is valid to map a longer range than the current file size. The map will
|
||||
* then be populated when the file grows.
|
||||
* On garbage collections and file data page movements, the map array will be
|
||||
* automatically updated. Do not tamper with the map array, as this contains
|
||||
* the references to the data pages. Modifying it from outside will corrupt any
|
||||
* future readings using this file descriptor.
|
||||
* The map will no longer be used when the file descriptor closed or the file
|
||||
* is unmapped.
|
||||
* This can be useful to get faster and more deterministic timing when reading
|
||||
* large files, or when seeking and reading a lot within a file.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to map
|
||||
* @param map a spiffs_ix_map struct, describing the index map
|
||||
* @param offset absolute file offset where to start the index map
|
||||
* @param len length of the mapping in actual file bytes
|
||||
* @param map_buf the array buffer for the look up data - number of required
|
||||
* elements in the array can be derived from function
|
||||
* SPIFFS_bytes_to_ix_map_entries given the length
|
||||
*/
|
||||
s32_t SPIFFS_ix_map(spiffs *fs, spiffs_file fh, spiffs_ix_map *map,
|
||||
u32_t offset, u32_t len, spiffs_page_ix *map_buf);
|
||||
|
||||
/**
|
||||
* Unmaps the index lookup from this filehandle. All future readings will
|
||||
* proceed as normal, requiring reading of the first level indices from
|
||||
* physical media.
|
||||
* The map and map buffer given in function SPIFFS_ix_map will no longer be
|
||||
* referenced by spiffs.
|
||||
* It is not strictly necessary to unmap a file before closing it, as closing
|
||||
* a file will automatically unmap it.
|
||||
* @param fs the file system struct
|
||||
* @param fh the file handle of the file to unmap
|
||||
*/
|
||||
s32_t SPIFFS_ix_unmap(spiffs *fs, spiffs_file fh);
|
||||
|
||||
/**
|
||||
* Moves the offset for the index map given in function SPIFFS_ix_map. Parts or
|
||||
* all of the map buffer will repopulated.
|
||||
* @param fs the file system struct
|
||||
* @param fh the mapped file handle of the file to remap
|
||||
* @param offset new absolute file offset where to start the index map
|
||||
*/
|
||||
s32_t SPIFFS_ix_remap(spiffs *fs, spiffs_file fh, u32_t offs);
|
||||
|
||||
/**
|
||||
* Utility function to get number of spiffs_page_ix entries a map buffer must
|
||||
* contain on order to map given amount of file data in bytes.
|
||||
* See function SPIFFS_ix_map and SPIFFS_ix_map_entries_to_bytes.
|
||||
* @param fs the file system struct
|
||||
* @param bytes number of file data bytes to map
|
||||
* @return needed number of elements in a spiffs_page_ix array needed to
|
||||
* map given amount of bytes in a file
|
||||
*/
|
||||
s32_t SPIFFS_bytes_to_ix_map_entries(spiffs *fs, u32_t bytes);
|
||||
|
||||
/**
|
||||
* Utility function to amount of file data bytes that can be mapped when
|
||||
* mapping a file with buffer having given number of spiffs_page_ix entries.
|
||||
* See function SPIFFS_ix_map and SPIFFS_bytes_to_ix_map_entries.
|
||||
* @param fs the file system struct
|
||||
* @param map_page_ix_entries number of entries in a spiffs_page_ix array
|
||||
* @return amount of file data in bytes that can be mapped given a map
|
||||
* buffer having given amount of spiffs_page_ix entries
|
||||
*/
|
||||
s32_t SPIFFS_ix_map_entries_to_bytes(spiffs *fs, u32_t map_page_ix_entries);
|
||||
|
||||
#endif // SPIFFS_IX_MAP
|
||||
|
||||
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
/**
|
||||
* Prints out a visualization of the filesystem.
|
||||
* @param fs the file system struct
|
||||
*/
|
||||
s32_t SPIFFS_vis(spiffs *fs);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_BUFFER_HELP
|
||||
/**
|
||||
* Returns number of bytes needed for the filedescriptor buffer given
|
||||
* amount of file descriptors.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_filedescs(spiffs *fs, u32_t num_descs);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
/**
|
||||
* Returns number of bytes needed for the cache buffer given
|
||||
* amount of cache pages.
|
||||
*/
|
||||
u32_t SPIFFS_buffer_bytes_for_cache(spiffs *fs, u32_t num_pages);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#endif
|
||||
#if defined(__cplusplus)
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* SPIFFS_H_ */
|
314
components/spiffs/spiffs_cache.c
Normal file
314
components/spiffs/spiffs_cache.c
Normal file
@ -0,0 +1,314 @@
|
||||
/*
|
||||
* spiffs_cache.c
|
||||
*
|
||||
* Created on: Jun 23, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
// returns cached page for give page index, or null if no such cached page
|
||||
static spiffs_cache_page *spiffs_cache_page_get(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) return 0;
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
cp->pix == pix ) {
|
||||
SPIFFS_CACHE_DBG("CACHE_GET: have cache page "_SPIPRIi" for "_SPIPRIpg"\n", i, pix);
|
||||
cp->last_access = cache->last_access;
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
//SPIFFS_CACHE_DBG("CACHE_GET: no cache for "_SPIPRIpg"\n", pix);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// frees cached page
|
||||
static s32_t spiffs_cache_page_free(spiffs *fs, int ix, u8_t write_back) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, ix);
|
||||
if (cache->cpage_use_map & (1<<ix)) {
|
||||
if (write_back &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) == 0 &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_DIRTY)) {
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, ix);
|
||||
res = SPIFFS_HAL_WRITE(fs, SPIFFS_PAGE_TO_PADDR(fs, cp->pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), mem);
|
||||
}
|
||||
|
||||
cp->flags = 0;
|
||||
cache->cpage_use_map &= ~(1 << ix);
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" objid "_SPIPRIid"\n", ix, cp->obj_id);
|
||||
} else {
|
||||
SPIFFS_CACHE_DBG("CACHE_FREE: free cache page "_SPIPRIi" pix "_SPIPRIpg"\n", ix, cp->pix);
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// removes the oldest accessed cached page
|
||||
static s32_t spiffs_cache_page_remove_oldest(spiffs *fs, u8_t flag_mask, u8_t flags) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) != cache->cpage_use_mask) {
|
||||
// at least one free cpage
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
// all busy, scan thru all to find the cpage which has oldest access
|
||||
int i;
|
||||
int cand_ix = -1;
|
||||
u32_t oldest_val = 0;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->last_access - cp->last_access) > oldest_val &&
|
||||
(cp->flags & flag_mask) == flags) {
|
||||
oldest_val = cache->last_access - cp->last_access;
|
||||
cand_ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
if (cand_ix >= 0) {
|
||||
res = spiffs_cache_page_free(fs, cand_ix, 1);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// allocates a new cached page and returns it, or null if all cache pages are busy
|
||||
static spiffs_cache_page *spiffs_cache_page_allocate(spiffs *fs) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
if (cache->cpage_use_map == 0xffffffff) {
|
||||
// out of cache memory
|
||||
return 0;
|
||||
}
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
if ((cache->cpage_use_map & (1<<i)) == 0) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
cache->cpage_use_map |= (1<<i);
|
||||
cp->last_access = cache->last_access;
|
||||
SPIFFS_CACHE_DBG("CACHE_ALLO: allocated cache page "_SPIPRIi"\n", i);
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
// out of cache entries
|
||||
return 0;
|
||||
}
|
||||
|
||||
// drops the cache page for give page index
|
||||
void spiffs_cache_drop_page(spiffs *fs, spiffs_page_ix pix) {
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
if (cp) {
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
}
|
||||
}
|
||||
|
||||
// ------------------------------
|
||||
|
||||
// reads from spi flash or the cache
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst) {
|
||||
(void)fh;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, SPIFFS_PADDR_TO_PAGE(fs, addr));
|
||||
cache->last_access++;
|
||||
if (cp) {
|
||||
// we've already got one, you see
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_hits++;
|
||||
#endif
|
||||
cp->last_access = cache->last_access;
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
} else {
|
||||
if ((op & SPIFFS_OP_TYPE_MASK) == SPIFFS_OP_T_OBJ_LU2) {
|
||||
// for second layer lookup functions, we do not cache in order to prevent shredding
|
||||
return SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
}
|
||||
#if SPIFFS_CACHE_STATS
|
||||
fs->cache_misses++;
|
||||
#endif
|
||||
// this operation will always free one cache page (unless all already free),
|
||||
// the result code stems from the write operation of the possibly freed cache page
|
||||
res = spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
|
||||
cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp) {
|
||||
cp->flags = SPIFFS_CACHE_FLAG_WRTHRU;
|
||||
cp->pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs,
|
||||
addr - SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs),
|
||||
spiffs_get_cache_page(fs, cache, cp->ix));
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(dst, &mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], len);
|
||||
} else {
|
||||
// this will never happen, last resort for sake of symmetry
|
||||
s32_t res2 = SPIFFS_HAL_READ(fs, addr, len, dst);
|
||||
if (res2 != SPIFFS_OK) {
|
||||
// honor read failure before possible write failure (bad idea?)
|
||||
res = res2;
|
||||
}
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// writes to spi flash and/or the cache
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src) {
|
||||
(void)fh;
|
||||
spiffs_page_ix pix = SPIFFS_PADDR_TO_PAGE(fs, addr);
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_get(fs, pix);
|
||||
|
||||
if (cp && (op & SPIFFS_OP_COM_MASK) != SPIFFS_OP_C_WRTHRU) {
|
||||
// have a cache page
|
||||
// copy in data to cache page
|
||||
|
||||
if ((op & SPIFFS_OP_COM_MASK) == SPIFFS_OP_C_DELE &&
|
||||
(op & SPIFFS_OP_TYPE_MASK) != SPIFFS_OP_T_OBJ_LU) {
|
||||
// page is being deleted, wipe from cache - unless it is a lookup page
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
|
||||
u8_t *mem = spiffs_get_cache_page(fs, cache, cp->ix);
|
||||
memcpy(&mem[SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr)], src, len);
|
||||
|
||||
cache->last_access++;
|
||||
cp->last_access = cache->last_access;
|
||||
|
||||
if (cp->flags & SPIFFS_CACHE_FLAG_WRTHRU) {
|
||||
// page is being updated, no write-cache, just pass thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
} else {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
} else {
|
||||
// no cache page, no write cache - just write thru
|
||||
return SPIFFS_HAL_WRITE(fs, addr, len, src);
|
||||
}
|
||||
}
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
// returns the cache page that this fd refers, or null if no cache page
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
spiffs_cache *cache = spiffs_get_cache(fs);
|
||||
|
||||
if ((cache->cpage_use_map & cache->cpage_use_mask) == 0) {
|
||||
// all cpages free, no cpage cannot be assigned to obj_id
|
||||
return 0;
|
||||
}
|
||||
|
||||
int i;
|
||||
for (i = 0; i < cache->cpage_count; i++) {
|
||||
spiffs_cache_page *cp = spiffs_get_cache_page_hdr(fs, cache, i);
|
||||
if ((cache->cpage_use_map & (1<<i)) &&
|
||||
(cp->flags & SPIFFS_CACHE_FLAG_TYPE_WR) &&
|
||||
cp->obj_id == fd->obj_id) {
|
||||
return cp;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
// allocates a new cache page and refers this to given fd - flushes an old cache
|
||||
// page if all cache is busy
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(spiffs *fs, spiffs_fd *fd) {
|
||||
// before this function is called, it is ensured that there is no already existing
|
||||
// cache page with same object id
|
||||
spiffs_cache_page_remove_oldest(fs, SPIFFS_CACHE_FLAG_TYPE_WR, 0);
|
||||
spiffs_cache_page *cp = spiffs_cache_page_allocate(fs);
|
||||
if (cp == 0) {
|
||||
// could not get cache page
|
||||
return 0;
|
||||
}
|
||||
|
||||
cp->flags = SPIFFS_CACHE_FLAG_TYPE_WR;
|
||||
cp->obj_id = fd->obj_id;
|
||||
fd->cache_page = cp;
|
||||
return cp;
|
||||
}
|
||||
|
||||
// unrefers all fds that this cache page refers to and releases the cache page
|
||||
void spiffs_cache_fd_release(spiffs *fs, spiffs_cache_page *cp) {
|
||||
if (cp == 0) return;
|
||||
u32_t i;
|
||||
spiffs_fd *fds = (spiffs_fd *)fs->fd_space;
|
||||
for (i = 0; i < fs->fd_count; i++) {
|
||||
spiffs_fd *cur_fd = &fds[i];
|
||||
if (cur_fd->file_nbr != 0 && cur_fd->cache_page == cp) {
|
||||
cur_fd->cache_page = 0;
|
||||
}
|
||||
}
|
||||
spiffs_cache_page_free(fs, cp->ix, 0);
|
||||
|
||||
cp->obj_id = 0;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// initializes the cache
|
||||
void spiffs_cache_init(spiffs *fs) {
|
||||
if (fs->cache == 0) return;
|
||||
u32_t sz = fs->cache_size;
|
||||
u32_t cache_mask = 0;
|
||||
int i;
|
||||
int cache_entries =
|
||||
(sz - sizeof(spiffs_cache)) / (SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
if (cache_entries <= 0) return;
|
||||
|
||||
for (i = 0; i < cache_entries; i++) {
|
||||
cache_mask <<= 1;
|
||||
cache_mask |= 1;
|
||||
}
|
||||
|
||||
spiffs_cache cache;
|
||||
memset(&cache, 0, sizeof(spiffs_cache));
|
||||
cache.cpage_count = cache_entries;
|
||||
cache.cpages = (u8_t *)((u8_t *)fs->cache + sizeof(spiffs_cache));
|
||||
|
||||
cache.cpage_use_map = 0xffffffff;
|
||||
cache.cpage_use_mask = cache_mask;
|
||||
memcpy(fs->cache, &cache, sizeof(spiffs_cache));
|
||||
|
||||
spiffs_cache *c = spiffs_get_cache(fs);
|
||||
|
||||
memset(c->cpages, 0, c->cpage_count * SPIFFS_CACHE_PAGE_SIZE(fs));
|
||||
|
||||
c->cpage_use_map &= ~(c->cpage_use_mask);
|
||||
for (i = 0; i < cache.cpage_count; i++) {
|
||||
spiffs_get_cache_page_hdr(fs, c, i)->ix = i;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // SPIFFS_CACHE
|
995
components/spiffs/spiffs_check.c
Normal file
995
components/spiffs/spiffs_check.c
Normal file
@ -0,0 +1,995 @@
|
||||
/*
|
||||
* spiffs_check.c
|
||||
*
|
||||
* Contains functionality for checking file system consistency
|
||||
* and mending problems.
|
||||
* Three levels of consistency checks are implemented:
|
||||
*
|
||||
* Look up consistency
|
||||
* Checks if indices in lookup pages are coherent with page headers
|
||||
* Object index consistency
|
||||
* Checks if there are any orphaned object indices (missing object index headers).
|
||||
* If an object index is found but not its header, the object index is deleted.
|
||||
* This is critical for the following page consistency check.
|
||||
* Page consistency
|
||||
* Checks for pages that ought to be indexed, ought not to be indexed, are multiple indexed
|
||||
*
|
||||
*
|
||||
* Created on: Jul 7, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||
do { \
|
||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_fs), (_type), (_rep), (_arg1), (_arg2)); \
|
||||
} while (0)
|
||||
#else
|
||||
#define CHECK_CB(_fs, _type, _rep, _arg1, _arg2) \
|
||||
do { \
|
||||
if ((_fs)->check_cb_f) (_fs)->check_cb_f((_type), (_rep), (_arg1), (_arg2)); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
//---------------------------------------
|
||||
// Look up consistency
|
||||
|
||||
// searches in the object indices and returns the referenced page index given
|
||||
// the object id and the data span index
|
||||
// destroys fs->lu_work
|
||||
static s32_t spiffs_object_get_data_page_index_reference(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix data_spix,
|
||||
spiffs_page_ix *pix,
|
||||
spiffs_page_ix *objix_pix) {
|
||||
s32_t res;
|
||||
|
||||
// calculate object index span index for given data page span index
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
|
||||
// find obj index for obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, objix_spix, 0, objix_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// load obj index entry
|
||||
u32_t addr = SPIFFS_PAGE_TO_PADDR(fs, *objix_pix);
|
||||
if (objix_spix == 0) {
|
||||
// get referenced page from object index header
|
||||
addr += sizeof(spiffs_page_object_ix_header) + data_spix * sizeof(spiffs_page_ix);
|
||||
} else {
|
||||
// get referenced page from object index
|
||||
addr += sizeof(spiffs_page_object_ix) + SPIFFS_OBJ_IX_ENTRY(fs, data_spix) * sizeof(spiffs_page_ix);
|
||||
}
|
||||
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ, 0, addr, sizeof(spiffs_page_ix), (u8_t *)pix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// copies page contents to a new page
|
||||
static s32_t spiffs_rewrite_page(spiffs *fs, spiffs_page_ix cur_pix, spiffs_page_header *p_hdr, spiffs_page_ix *new_pix) {
|
||||
s32_t res;
|
||||
res = spiffs_page_allocate_data(fs, p_hdr->obj_id, p_hdr, 0,0,0,0, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0,
|
||||
SPIFFS_PAGE_TO_PADDR(fs, *new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_DATA_PAGE_SIZE(fs));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
// rewrites the object index for given object id and replaces the
|
||||
// data page index to a new page index
|
||||
static s32_t spiffs_rewrite_index(spiffs *fs, spiffs_obj_id obj_id, spiffs_span_ix data_spix, spiffs_page_ix new_data_pix, spiffs_page_ix objix_pix) {
|
||||
s32_t res;
|
||||
spiffs_block_ix bix;
|
||||
int entry;
|
||||
spiffs_page_ix free_pix;
|
||||
obj_id |= SPIFFS_OBJ_ID_IX_FLAG;
|
||||
|
||||
// find free entry
|
||||
res = spiffs_obj_lu_find_free(fs, fs->free_cursor_block_ix, fs->free_cursor_obj_lu_entry, &bix, &entry);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
free_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, entry);
|
||||
|
||||
// calculate object index span index for given data page span index
|
||||
spiffs_span_ix objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, data_spix);
|
||||
if (objix_spix == 0) {
|
||||
// calc index in index header
|
||||
entry = data_spix;
|
||||
} else {
|
||||
// calc entry in index
|
||||
entry = SPIFFS_OBJ_IX_ENTRY(fs, data_spix);
|
||||
|
||||
}
|
||||
// load index
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
||||
|
||||
// be ultra safe, double check header against provided data
|
||||
if (objix_p_hdr->obj_id != obj_id) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_OBJ_ID_MISM;
|
||||
}
|
||||
if (objix_p_hdr->span_ix != objix_spix) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_SPIX_MISM;
|
||||
}
|
||||
if ((objix_p_hdr->flags & (SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_INDEX |
|
||||
SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET)) !=
|
||||
(SPIFFS_PH_FLAG_IXDELE | SPIFFS_PH_FLAG_DELET)) {
|
||||
spiffs_page_delete(fs, free_pix);
|
||||
return SPIFFS_ERR_CHECK_FLAGS_BAD;
|
||||
}
|
||||
|
||||
// rewrite in mem
|
||||
if (objix_spix == 0) {
|
||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header)))[data_spix] = new_data_pix;
|
||||
} else {
|
||||
((spiffs_page_ix*)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, data_spix)] = new_data_pix;
|
||||
}
|
||||
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, free_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_BLOCK_TO_PADDR(fs, SPIFFS_BLOCK_FOR_PAGE(fs, free_pix)) + SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, free_pix) * sizeof(spiffs_page_ix),
|
||||
sizeof(spiffs_obj_id),
|
||||
(u8_t *)&obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_page_delete(fs, objix_pix);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// deletes an object just by marking object index header as deleted
|
||||
static s32_t spiffs_delete_obj_lazy(spiffs *fs, spiffs_obj_id obj_id) {
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
s32_t res;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id, 0, 0, &objix_hdr_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_IXDELE;
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_hdr_pix) + offsetof(spiffs_page_header, flags),
|
||||
sizeof(u8_t),
|
||||
(u8_t *)&flags);
|
||||
return res;
|
||||
}
|
||||
|
||||
// validates the given look up entry
|
||||
static s32_t spiffs_lookup_check_validate(spiffs *fs, spiffs_obj_id lu_obj_id, spiffs_page_header *p_hdr,
|
||||
spiffs_page_ix cur_pix, spiffs_block_ix cur_block, int cur_entry, int *reload_lu) {
|
||||
(void)cur_block;
|
||||
(void)cur_entry;
|
||||
u8_t delete_page = 0;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_ix objix_pix;
|
||||
spiffs_page_ix ref_pix;
|
||||
// check validity, take actions
|
||||
if (((lu_obj_id == SPIFFS_OBJ_ID_DELETED) && (p_hdr->flags & SPIFFS_PH_FLAG_DELET)) ||
|
||||
((lu_obj_id == SPIFFS_OBJ_ID_FREE) && (p_hdr->flags & SPIFFS_PH_FLAG_USED) == 0)) {
|
||||
// look up entry deleted / free but used in page header
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" deleted/free in lu but not on page\n", cur_pix);
|
||||
*reload_lu = 1;
|
||||
delete_page = 1;
|
||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
||||
// header says data page
|
||||
// data page can be removed if not referenced by some object index
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (ref_pix == cur_pix) {
|
||||
// data page referenced by object index but deleted in lu
|
||||
// copy page to new place and re-write the object index to new place
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: data page not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: "_SPIPRIpg" rewritten to "_SPIPRIpg", affected objix_pix "_SPIPRIpg"\n", cur_pix, new_pix, objix_pix);
|
||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
res = spiffs_page_delete(fs, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, p_hdr->obj_id, p_hdr->span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// header says index page
|
||||
// index page can be removed if other index with same obj_id and spanix is found
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, 0);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no such index page found, check for a data page amongst page headers
|
||||
// lu cannot be trusted
|
||||
res = spiffs_obj_lu_find_id_and_span_by_phdr(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, 0);
|
||||
if (res == SPIFFS_OK) { // ignore other errors
|
||||
// got a data page also, assume lu corruption only, rewrite to new page
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: ix page with data not found elsewhere, rewriting "_SPIPRIpg" to new page "_SPIPRIpg"\n", cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
}
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (lu_obj_id != SPIFFS_OBJ_ID_FREE && lu_obj_id != SPIFFS_OBJ_ID_DELETED) {
|
||||
// look up entry used
|
||||
if ((p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG) != (lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" differ in obj_id lu:"_SPIPRIid" ph:"_SPIPRIid"\n", cur_pix, lu_obj_id, p_hdr->obj_id);
|
||||
delete_page = 1;
|
||||
if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0 ||
|
||||
(p_hdr->flags & SPIFFS_PH_FLAG_FINAL) ||
|
||||
(p_hdr->flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_IXDELE)) == 0) {
|
||||
// page deleted or not finalized, just remove it
|
||||
} else {
|
||||
if (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) {
|
||||
// if data page, check for reference to this page
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr->obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// if found, rewrite page with object id, update index, and delete current
|
||||
if (ref_pix == cur_pix) {
|
||||
spiffs_page_ix new_pix;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, p_hdr, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_rewrite_index(fs, p_hdr->obj_id, p_hdr->span_ix, new_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
res = spiffs_page_delete(fs, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr->obj_id);
|
||||
*reload_lu = 1;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr->obj_id, 0);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// else if index, check for other pages with both obj_id's and spanix
|
||||
spiffs_page_ix objix_pix_lu, objix_pix_ph;
|
||||
// see if other object index page exists for lookup obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_lu);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_lu = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other object index exists for page header obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, 0, &objix_pix_ph);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_ph = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// if both obj_id's found, just delete current
|
||||
if (objix_pix_ph == 0 || objix_pix_lu == 0) {
|
||||
// otherwise try finding first corresponding data pages
|
||||
spiffs_page_ix data_pix_lu, data_pix_ph;
|
||||
// see if other data page exists for look up obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_lu);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_lu = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other data page exists for page header obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &data_pix_ph);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_ph = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_page_header new_ph;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
spiffs_page_ix new_pix;
|
||||
if ((objix_pix_lu && data_pix_lu && data_pix_ph && objix_pix_ph == 0) ||
|
||||
(objix_pix_lu == 0 && data_pix_ph && objix_pix_ph == 0)) {
|
||||
// got a data page for page header obj id
|
||||
// rewrite as obj_id_ph
|
||||
new_ph.obj_id = p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid" to pix "_SPIPRIpg"\n", cur_pix, new_ph.obj_id, new_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
} else if ((objix_pix_ph && data_pix_ph && data_pix_lu && objix_pix_lu == 0) ||
|
||||
(objix_pix_ph == 0 && data_pix_lu && objix_pix_lu == 0)) {
|
||||
// got a data page for look up obj id
|
||||
// rewrite as obj_id_lu
|
||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: rewrite page "_SPIPRIpg" as "_SPIPRIid"\n", cur_pix, new_ph.obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
res = spiffs_rewrite_page(fs, cur_pix, &new_ph, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
*reload_lu = 1;
|
||||
} else {
|
||||
// cannot safely do anything
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: nothing to do, just delete\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX)) ||
|
||||
((lu_obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0 && (p_hdr->flags & SPIFFS_PH_FLAG_INDEX) == 0)) {
|
||||
SPIFFS_CHECK_DBG("LU: "_SPIPRIpg" lu/page index marking differ\n", cur_pix);
|
||||
spiffs_page_ix data_pix, objix_pix_d;
|
||||
// see if other data page exists for given obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// see if other object index exists for given obj id and span index
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG, p_hdr->span_ix, cur_pix, &objix_pix_d);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
objix_pix_d = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
delete_page = 1;
|
||||
// if other data page exists and object index exists, just delete page
|
||||
if (data_pix && objix_pix_d) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index and data page exists, simply remove\n");
|
||||
} else
|
||||
// if only data page exists, make this page index
|
||||
if (data_pix && objix_pix_d == 0) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other data page exists, make this index\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_INDEX, lu_obj_id, p_hdr->span_ix);
|
||||
spiffs_page_header new_ph;
|
||||
spiffs_page_ix new_pix;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_INDEX);
|
||||
new_ph.obj_id = lu_obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else
|
||||
// if only index exists, make data page
|
||||
if (data_pix == 0 && objix_pix_d) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other index page exists, make this data\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, lu_obj_id, p_hdr->span_ix);
|
||||
spiffs_page_header new_ph;
|
||||
spiffs_page_ix new_pix;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.obj_id = lu_obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = p_hdr->span_ix;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_phys_cpy(fs, 0, SPIFFS_PAGE_TO_PADDR(fs, new_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + sizeof(spiffs_page_header),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header));
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// if nothing exists, we cannot safely make a decision - delete
|
||||
}
|
||||
}
|
||||
else if ((p_hdr->flags & SPIFFS_PH_FLAG_DELET) == 0) {
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy in lu but deleted on page\n", cur_pix);
|
||||
delete_page = 1;
|
||||
} else if ((p_hdr->flags & SPIFFS_PH_FLAG_FINAL)) {
|
||||
SPIFFS_CHECK_DBG("LU: pix "_SPIPRIpg" busy but not final\n", cur_pix);
|
||||
// page can be removed if not referenced by object index
|
||||
*reload_lu = 1;
|
||||
res = spiffs_object_get_data_page_index_reference(fs, lu_obj_id, p_hdr->span_ix, &ref_pix, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// no object with this id, so remove page safely
|
||||
res = SPIFFS_OK;
|
||||
delete_page = 1;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (ref_pix != cur_pix) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: other finalized page is referred, just delete\n");
|
||||
delete_page = 1;
|
||||
} else {
|
||||
// page referenced by object index but not final
|
||||
// just finalize
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: unfinalized page is referred, finalizing\n");
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_FIX_LOOKUP, p_hdr->obj_id, p_hdr->span_ix);
|
||||
u8_t flags = 0xff & ~SPIFFS_PH_FLAG_FINAL;
|
||||
res = _spiffs_wr(fs, SPIFFS_OP_T_OBJ_DA | SPIFFS_OP_C_UPDT,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix) + offsetof(spiffs_page_header, flags),
|
||||
sizeof(u8_t), (u8_t*)&flags);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (delete_page) {
|
||||
SPIFFS_CHECK_DBG("LU: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
static s32_t spiffs_lookup_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block, int cur_entry,
|
||||
const void *user_const_p, void *user_var_p) {
|
||||
(void)user_const_p;
|
||||
(void)user_var_p;
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS,
|
||||
(cur_block * 256)/fs->block_count, 0);
|
||||
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
int reload_lu = 0;
|
||||
|
||||
res = spiffs_lookup_check_validate(fs, obj_id, &p_hdr, cur_pix, cur_block, cur_entry, &reload_lu);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
return reload_lu ? SPIFFS_VIS_COUNTINUE_RELOAD : SPIFFS_VIS_COUNTINUE;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
|
||||
// Scans all object look up. For each entry, corresponding page header is checked for validity.
|
||||
// If an object index header page is found, this is also checked
|
||||
s32_t spiffs_lookup_consistency_check(spiffs *fs, u8_t check_all_objects) {
|
||||
(void)check_all_objects;
|
||||
s32_t res = SPIFFS_OK;
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
|
||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_lookup_check_v, 0, 0, 0, 0);
|
||||
|
||||
if (res == SPIFFS_VIS_END) {
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_LOOKUP, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Page consistency
|
||||
|
||||
// Scans all pages (except lu pages), reserves 4 bits in working memory for each page
|
||||
// bit 0: 0 == FREE|DELETED, 1 == USED
|
||||
// bit 1: 0 == UNREFERENCED, 1 == REFERENCED
|
||||
// bit 2: 0 == NOT_INDEX, 1 == INDEX
|
||||
// bit 3: unused
|
||||
// A consistent file system will have only pages being
|
||||
// * x000 free, unreferenced, not index
|
||||
// * x011 used, referenced only once, not index
|
||||
// * x101 used, unreferenced, index
|
||||
// The working memory might not fit all pages so several scans might be needed
|
||||
static s32_t spiffs_page_consistency_check_i(spiffs *fs) {
|
||||
const u32_t bits = 4;
|
||||
const spiffs_page_ix pages_per_scan = SPIFFS_CFG_LOG_PAGE_SZ(fs) * 8 / bits;
|
||||
|
||||
s32_t res = SPIFFS_OK;
|
||||
spiffs_page_ix pix_offset = 0;
|
||||
|
||||
// for each range of pages fitting into work memory
|
||||
while (pix_offset < SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) {
|
||||
// set this flag to abort all checks and rescan the page range
|
||||
u8_t restart = 0;
|
||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
spiffs_block_ix cur_block = 0;
|
||||
// build consistency bitmap for id range traversing all blocks
|
||||
while (!restart && cur_block < fs->block_count) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS,
|
||||
(pix_offset*256)/(SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count) +
|
||||
((((cur_block * pages_per_scan * 256)/ (SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count))) / fs->block_count),
|
||||
0);
|
||||
// traverse each page except for lookup pages
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_PAGES(fs) + SPIFFS_PAGES_PER_BLOCK(fs) * cur_block;
|
||||
while (!restart && cur_pix < SPIFFS_PAGES_PER_BLOCK(fs) * (cur_block+1)) {
|
||||
//if ((cur_pix & 0xff) == 0)
|
||||
// SPIFFS_CHECK_DBG("PA: processing pix "_SPIPRIpg", block "_SPIPRIbl" of pix "_SPIPRIpg", block "_SPIPRIbl"\n",
|
||||
// cur_pix, cur_block, SPIFFS_PAGES_PER_BLOCK(fs) * fs->block_count, fs->block_count);
|
||||
|
||||
// read header
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
u8_t within_range = (cur_pix >= pix_offset && cur_pix < pix_offset + pages_per_scan);
|
||||
const u32_t pix_byte_ix = (cur_pix - pix_offset) / (8/bits);
|
||||
const u8_t pix_bit_ix = (cur_pix & ((8/bits)-1)) * bits;
|
||||
|
||||
if (within_range &&
|
||||
(p_hdr.flags & SPIFFS_PH_FLAG_DELET) && (p_hdr.flags & SPIFFS_PH_FLAG_USED) == 0) {
|
||||
// used
|
||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 0));
|
||||
}
|
||||
if ((p_hdr.flags & SPIFFS_PH_FLAG_DELET) &&
|
||||
(p_hdr.flags & SPIFFS_PH_FLAG_IXDELE) &&
|
||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) == 0) {
|
||||
// found non-deleted index
|
||||
if (within_range) {
|
||||
fs->work[pix_byte_ix] |= (1<<(pix_bit_ix + 2));
|
||||
}
|
||||
|
||||
// load non-deleted index
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// traverse index for referenced pages
|
||||
spiffs_page_ix *object_page_index;
|
||||
spiffs_page_header *objix_p_hdr = (spiffs_page_header *)fs->lu_work;
|
||||
|
||||
int entries;
|
||||
int i;
|
||||
spiffs_span_ix data_spix_offset;
|
||||
if (p_hdr.span_ix == 0) {
|
||||
// object header page index
|
||||
entries = SPIFFS_OBJ_HDR_IX_LEN(fs);
|
||||
data_spix_offset = 0;
|
||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix_header));
|
||||
} else {
|
||||
// object page index
|
||||
entries = SPIFFS_OBJ_IX_LEN(fs);
|
||||
data_spix_offset = SPIFFS_OBJ_HDR_IX_LEN(fs) + SPIFFS_OBJ_IX_LEN(fs) * (p_hdr.span_ix - 1);
|
||||
object_page_index = (spiffs_page_ix *)((u8_t *)fs->lu_work + sizeof(spiffs_page_object_ix));
|
||||
}
|
||||
|
||||
// for all entries in index
|
||||
for (i = 0; !restart && i < entries; i++) {
|
||||
spiffs_page_ix rpix = object_page_index[i];
|
||||
u8_t rpix_within_range = rpix >= pix_offset && rpix < pix_offset + pages_per_scan;
|
||||
|
||||
if ((rpix != (spiffs_page_ix)-1 && rpix > SPIFFS_MAX_PAGES(fs))
|
||||
|| (rpix_within_range && SPIFFS_IS_LOOKUP_PAGE(fs, rpix))) {
|
||||
|
||||
// bad reference
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg"x bad pix / LU referenced from page "_SPIPRIpg"\n",
|
||||
rpix, cur_pix);
|
||||
// check for data page elsewhere
|
||||
spiffs_page_ix data_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, 0, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (data_pix == 0) {
|
||||
// if not, allocate free page
|
||||
spiffs_page_header new_ph;
|
||||
new_ph.flags = 0xff & ~(SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL);
|
||||
new_ph.obj_id = objix_p_hdr->obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
new_ph.span_ix = data_spix_offset + i;
|
||||
res = spiffs_page_allocate_data(fs, new_ph.obj_id, &new_ph, 0, 0, 0, 1, &data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: found no existing data page, created new @ "_SPIPRIpg"\n", data_pix);
|
||||
}
|
||||
// remap index
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewriting index pix "_SPIPRIpg"\n", cur_pix);
|
||||
res = spiffs_rewrite_index(fs, objix_p_hdr->obj_id | SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, data_pix, cur_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend - delete object\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, objix_p_hdr->obj_id, 0);
|
||||
// delete file
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, objix_p_hdr->obj_id, objix_p_hdr->span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
|
||||
} else if (rpix_within_range) {
|
||||
|
||||
// valid reference
|
||||
// read referenced page header
|
||||
spiffs_page_header rp_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
// cross reference page header check
|
||||
if (rp_hdr.obj_id != (p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) ||
|
||||
rp_hdr.span_ix != data_spix_offset + i ||
|
||||
(rp_hdr.flags & (SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_USED)) !=
|
||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_INDEX)) {
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" has inconsistent page header ix id/span:"_SPIPRIid"/"_SPIPRIsp", ref id/span:"_SPIPRIid"/"_SPIPRIsp" flags:"_SPIPRIfl"\n",
|
||||
rpix, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG, data_spix_offset + i,
|
||||
rp_hdr.obj_id, rp_hdr.span_ix, rp_hdr.flags);
|
||||
// try finding correct page
|
||||
spiffs_page_ix data_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG,
|
||||
data_spix_offset + i, rpix, &data_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
res = SPIFFS_OK;
|
||||
data_pix = 0;
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (data_pix == 0) {
|
||||
// not found, this index is badly borked
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad, delete object id "_SPIPRIid"\n", p_hdr.obj_id);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
break;
|
||||
} else {
|
||||
// found it, so rewrite index
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: found correct data pix "_SPIPRIpg", rewrite ix pix "_SPIPRIpg" id "_SPIPRIid"\n",
|
||||
data_pix, cur_pix, p_hdr.obj_id);
|
||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, data_spix_offset + i, data_pix, cur_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// mark rpix as referenced
|
||||
const u32_t rpix_byte_ix = (rpix - pix_offset) / (8/bits);
|
||||
const u8_t rpix_bit_ix = (rpix & ((8/bits)-1)) * bits;
|
||||
if (fs->work[rpix_byte_ix] & (1<<(rpix_bit_ix + 1))) {
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" multiple referenced from page "_SPIPRIpg"\n",
|
||||
rpix, cur_pix);
|
||||
// Here, we should have fixed all broken references - getting this means there
|
||||
// must be multiple files with same object id. Only solution is to delete
|
||||
// the object which is referring to this page
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: removing object "_SPIPRIid" and page "_SPIPRIpg"\n",
|
||||
p_hdr.obj_id, cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// extra precaution, delete this page also
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
}
|
||||
fs->work[rpix_byte_ix] |= (1<<(rpix_bit_ix + 1));
|
||||
}
|
||||
}
|
||||
} // for all index entries
|
||||
} // found index
|
||||
|
||||
// next page
|
||||
cur_pix++;
|
||||
}
|
||||
// next block
|
||||
cur_block++;
|
||||
}
|
||||
// check consistency bitmap
|
||||
if (!restart) {
|
||||
spiffs_page_ix objix_pix;
|
||||
spiffs_page_ix rpix;
|
||||
|
||||
u32_t byte_ix;
|
||||
u8_t bit_ix;
|
||||
for (byte_ix = 0; !restart && byte_ix < SPIFFS_CFG_LOG_PAGE_SZ(fs); byte_ix++) {
|
||||
for (bit_ix = 0; !restart && bit_ix < 8/bits; bit_ix ++) {
|
||||
u8_t bitmask = (fs->work[byte_ix] >> (bit_ix * bits)) & 0x7;
|
||||
spiffs_page_ix cur_pix = pix_offset + byte_ix * (8/bits) + bit_ix;
|
||||
|
||||
// 000 ok - free, unreferenced, not index
|
||||
|
||||
if (bitmask == 0x1) {
|
||||
|
||||
// 001
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, UNREFERENCED, not index\n", cur_pix);
|
||||
|
||||
u8_t rewrite_ix_to_this = 0;
|
||||
u8_t delete_page = 0;
|
||||
// check corresponding object index entry
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_object_get_data_page_index_reference(fs, p_hdr.obj_id, p_hdr.span_ix,
|
||||
&rpix, &objix_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
if (((rpix == (spiffs_page_ix)-1 || rpix > SPIFFS_MAX_PAGES(fs)) || (SPIFFS_IS_LOOKUP_PAGE(fs, rpix)))) {
|
||||
// pointing to a bad page altogether, rewrite index to this
|
||||
rewrite_ix_to_this = 1;
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is bad: "_SPIPRIpg", rewrite to this "_SPIPRIpg"\n", rpix, cur_pix);
|
||||
} else {
|
||||
// pointing to something else, check what
|
||||
spiffs_page_header rp_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, rpix), sizeof(spiffs_page_header), (u8_t*)&rp_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (((p_hdr.obj_id & ~SPIFFS_OBJ_ID_IX_FLAG) == rp_hdr.obj_id) &&
|
||||
((rp_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_USED | SPIFFS_PH_FLAG_FINAL)) ==
|
||||
(SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_DELET))) {
|
||||
// pointing to something else valid, just delete this page then
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is good but different: "_SPIPRIpg", delete this "_SPIPRIpg"\n", rpix, cur_pix);
|
||||
delete_page = 1;
|
||||
} else {
|
||||
// pointing to something weird, update index to point to this page instead
|
||||
if (rpix != cur_pix) {
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref is weird: "_SPIPRIpg" %s%s%s%s, rewrite this "_SPIPRIpg"\n", rpix,
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_INDEX) ? "" : "INDEX ",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_DELET) ? "" : "DELETED ",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_USED) ? "NOTUSED " : "",
|
||||
(rp_hdr.flags & SPIFFS_PH_FLAG_FINAL) ? "NOTFINAL " : "",
|
||||
cur_pix);
|
||||
rewrite_ix_to_this = 1;
|
||||
} else {
|
||||
// should not happen, destined for fubar
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
SPIFFS_CHECK_DBG("PA: corresponding ref not found, delete "_SPIPRIpg"\n", cur_pix);
|
||||
delete_page = 1;
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
|
||||
if (rewrite_ix_to_this) {
|
||||
// if pointing to invalid page, redirect index to this page
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: rewrite index id "_SPIPRIid" data spix "_SPIPRIsp" to point to this pix: "_SPIPRIpg"\n",
|
||||
p_hdr.obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_rewrite_index(fs, p_hdr.obj_id, p_hdr.span_ix, cur_pix, objix_pix);
|
||||
if (res <= _SPIFFS_ERR_CHECK_FIRST && res > _SPIFFS_ERR_CHECK_LAST) {
|
||||
// index bad also, cannot mend this file
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: index bad "_SPIPRIi", cannot mend!\n", res);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_BAD_FILE, p_hdr.obj_id, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
res = spiffs_delete_obj_lazy(fs, p_hdr.obj_id);
|
||||
} else {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_FIX_INDEX, p_hdr.obj_id, p_hdr.span_ix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
restart = 1;
|
||||
continue;
|
||||
} else if (delete_page) {
|
||||
SPIFFS_CHECK_DBG("PA: FIXUP: deleting page "_SPIPRIpg"\n", cur_pix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_DELETE_PAGE, cur_pix, 0);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
if (bitmask == 0x2) {
|
||||
|
||||
// 010
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, not index\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
|
||||
// 011 ok - busy, referenced, not index
|
||||
|
||||
if (bitmask == 0x4) {
|
||||
|
||||
// 100
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, unreferenced, INDEX\n", cur_pix);
|
||||
|
||||
// this should never happen, major fubar
|
||||
}
|
||||
|
||||
// 101 ok - busy, unreferenced, index
|
||||
|
||||
if (bitmask == 0x6) {
|
||||
|
||||
// 110
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" FREE, REFERENCED, INDEX\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
if (bitmask == 0x7) {
|
||||
|
||||
// 111
|
||||
SPIFFS_CHECK_DBG("PA: pix "_SPIPRIpg" USED, REFERENCED, INDEX\n", cur_pix);
|
||||
|
||||
// no op, this should be taken care of when checking valid references
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
SPIFFS_CHECK_DBG("PA: processed "_SPIPRIpg", restart "_SPIPRIi"\n", pix_offset, restart);
|
||||
// next page range
|
||||
if (!restart) {
|
||||
pix_offset += pages_per_scan;
|
||||
}
|
||||
} // while page range not reached end
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks consistency amongst all pages and fixes irregularities
|
||||
s32_t spiffs_page_consistency_check(spiffs *fs) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
s32_t res = spiffs_page_consistency_check_i(fs);
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
CHECK_CB(fs, SPIFFS_CHECK_PAGE, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
//---------------------------------------
|
||||
// Object index consistency
|
||||
|
||||
// searches for given object id in temporary object id index,
|
||||
// returns the index or -1
|
||||
static int spiffs_object_index_search(spiffs *fs, spiffs_obj_id obj_id) {
|
||||
u32_t i;
|
||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||
obj_id &= ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
for (i = 0; i < SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id); i++) {
|
||||
if ((obj_table[i] & ~SPIFFS_OBJ_ID_IX_FLAG) == obj_id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static s32_t spiffs_object_index_consistency_check_v(spiffs *fs, spiffs_obj_id obj_id, spiffs_block_ix cur_block,
|
||||
int cur_entry, const void *user_const_p, void *user_var_p) {
|
||||
(void)user_const_p;
|
||||
s32_t res_c = SPIFFS_VIS_COUNTINUE;
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t *log_ix = (u32_t*)user_var_p;
|
||||
spiffs_obj_id *obj_table = (spiffs_obj_id *)fs->work;
|
||||
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS,
|
||||
(cur_block * 256)/fs->block_count, 0);
|
||||
|
||||
if (obj_id != SPIFFS_OBJ_ID_FREE && obj_id != SPIFFS_OBJ_ID_DELETED && (obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, cur_block, cur_entry);
|
||||
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
if (p_hdr.span_ix == 0 &&
|
||||
(p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
||||
(SPIFFS_PH_FLAG_DELET)) {
|
||||
SPIFFS_CHECK_DBG("IX: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" header not fully deleted - deleting\n",
|
||||
cur_pix, obj_id, p_hdr.span_ix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_PAGE, cur_pix, obj_id);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
return res_c;
|
||||
}
|
||||
|
||||
if ((p_hdr.flags & (SPIFFS_PH_FLAG_INDEX | SPIFFS_PH_FLAG_FINAL | SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) ==
|
||||
(SPIFFS_PH_FLAG_DELET | SPIFFS_PH_FLAG_IXDELE)) {
|
||||
return res_c;
|
||||
}
|
||||
|
||||
if (p_hdr.span_ix == 0) {
|
||||
// objix header page, register objid as reachable
|
||||
int r = spiffs_object_index_search(fs, obj_id);
|
||||
if (r == -1) {
|
||||
// not registered, do it
|
||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
(*log_ix)++;
|
||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
||||
*log_ix = 0;
|
||||
}
|
||||
}
|
||||
} else { // span index
|
||||
// objix page, see if header can be found
|
||||
int r = spiffs_object_index_search(fs, obj_id);
|
||||
u8_t delete = 0;
|
||||
if (r == -1) {
|
||||
// not in temporary index, try finding it
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, 0, &objix_hdr_pix);
|
||||
res_c = SPIFFS_VIS_COUNTINUE_RELOAD;
|
||||
if (res == SPIFFS_OK) {
|
||||
// found, register as reachable
|
||||
obj_table[*log_ix] = obj_id & ~SPIFFS_OBJ_ID_IX_FLAG;
|
||||
} else if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// not found, register as unreachable
|
||||
delete = 1;
|
||||
obj_table[*log_ix] = obj_id | SPIFFS_OBJ_ID_IX_FLAG;
|
||||
} else {
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
(*log_ix)++;
|
||||
if (*log_ix >= SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id)) {
|
||||
*log_ix = 0;
|
||||
}
|
||||
} else {
|
||||
// in temporary index, check reachable flag
|
||||
if ((obj_table[r] & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// registered as unreachable
|
||||
delete = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (delete) {
|
||||
SPIFFS_CHECK_DBG("IX: FIXUP: pix "_SPIPRIpg", obj id:"_SPIPRIid" spix:"_SPIPRIsp" is orphan index - deleting\n",
|
||||
cur_pix, obj_id, p_hdr.span_ix);
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_DELETE_ORPHANED_INDEX, cur_pix, obj_id);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
} // span index
|
||||
} // valid object index id
|
||||
|
||||
return res_c;
|
||||
}
|
||||
|
||||
// Removes orphaned and partially deleted index pages.
|
||||
// Scans for index pages. When an index page is found, corresponding index header is searched for.
|
||||
// If no such page exists, the index page cannot be reached as no index header exists and must be
|
||||
// deleted.
|
||||
s32_t spiffs_object_index_consistency_check(spiffs *fs) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
// impl note:
|
||||
// fs->work is used for a temporary object index memory, listing found object ids and
|
||||
// indicating whether they can be reached or not. Acting as a fifo if object ids cannot fit.
|
||||
// In the temporary object index memory, SPIFFS_OBJ_ID_IX_FLAG bit is used to indicate
|
||||
// a reachable/unreachable object id.
|
||||
memset(fs->work, 0, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
u32_t obj_id_log_ix = 0;
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 0, 0);
|
||||
res = spiffs_obj_lu_find_entry_visitor(fs, 0, 0, 0, 0, spiffs_object_index_consistency_check_v, 0, &obj_id_log_ix,
|
||||
0, 0);
|
||||
if (res == SPIFFS_VIS_END) {
|
||||
res = SPIFFS_OK;
|
||||
}
|
||||
if (res != SPIFFS_OK) {
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_ERROR, res, 0);
|
||||
}
|
||||
CHECK_CB(fs, SPIFFS_CHECK_INDEX, SPIFFS_CHECK_PROGRESS, 256, 0);
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
367
components/spiffs/spiffs_config.h
Normal file
367
components/spiffs/spiffs_config.h
Normal file
@ -0,0 +1,367 @@
|
||||
/*
|
||||
* spiffs_config.h
|
||||
*
|
||||
* Created on: Jul 3, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
#ifndef SPIFFS_CONFIG_H_
|
||||
#define SPIFFS_CONFIG_H_
|
||||
|
||||
// ----------- 8< ------------
|
||||
// Following includes are for the linux test build of spiffs
|
||||
// These may/should/must be removed/altered/replaced in your target
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stddef.h>
|
||||
#include <unistd.h>
|
||||
#include <stdint.h>
|
||||
#include <ctype.h>
|
||||
// ----------- >8 ------------
|
||||
|
||||
#include "freertos/FreeRTOS.h"
|
||||
#include "freertos/queue.h"
|
||||
#include "freertos/semphr.h"
|
||||
|
||||
typedef signed int s32_t;
|
||||
typedef unsigned int u32_t;
|
||||
typedef signed short s16_t;
|
||||
typedef unsigned short u16_t;
|
||||
typedef signed char s8_t;
|
||||
typedef unsigned char u8_t;
|
||||
|
||||
QueueHandle_t spiffs_mutex;
|
||||
|
||||
// compile time switches
|
||||
|
||||
// Set generic spiffs debug output call.
|
||||
#ifndef SPIFFS_DBG
|
||||
#define SPIFFS_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for garbage collecting.
|
||||
#ifndef SPIFFS_GC_DBG
|
||||
#define SPIFFS_GC_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for caching.
|
||||
#ifndef SPIFFS_CACHE_DBG
|
||||
#define SPIFFS_CACHE_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
// Set spiffs debug output call for system consistency checks.
|
||||
#ifndef SPIFFS_CHECK_DBG
|
||||
#define SPIFFS_CHECK_DBG(...) //printf(__VA_ARGS__)
|
||||
#endif
|
||||
|
||||
|
||||
// Defines spiffs debug print formatters
|
||||
// some general signed number
|
||||
#ifndef _SPIPRIi
|
||||
#define _SPIPRIi "%d"
|
||||
#endif
|
||||
// address
|
||||
#ifndef _SPIPRIad
|
||||
#define _SPIPRIad "%08x"
|
||||
#endif
|
||||
// block
|
||||
#ifndef _SPIPRIbl
|
||||
#define _SPIPRIbl "%04x"
|
||||
#endif
|
||||
// page
|
||||
#ifndef _SPIPRIpg
|
||||
#define _SPIPRIpg "%04x"
|
||||
#endif
|
||||
// span index
|
||||
#ifndef _SPIPRIsp
|
||||
#define _SPIPRIsp "%04x"
|
||||
#endif
|
||||
// file descriptor
|
||||
#ifndef _SPIPRIfd
|
||||
#define _SPIPRIfd "%d"
|
||||
#endif
|
||||
// file object id
|
||||
#ifndef _SPIPRIid
|
||||
#define _SPIPRIid "%04x"
|
||||
#endif
|
||||
// file flags
|
||||
#ifndef _SPIPRIfl
|
||||
#define _SPIPRIfl "%02x"
|
||||
#endif
|
||||
|
||||
// Enable/disable API functions to determine exact number of bytes
|
||||
// for filedescriptor and cache buffers. Once decided for a configuration,
|
||||
// this can be disabled to reduce flash.
|
||||
#ifndef SPIFFS_BUFFER_HELP
|
||||
#define SPIFFS_BUFFER_HELP 0
|
||||
#endif
|
||||
|
||||
// Enables/disable memory read caching of nucleus file system operations.
|
||||
// If enabled, memory area must be provided for cache in SPIFFS_mount.
|
||||
#ifndef SPIFFS_CACHE
|
||||
#define SPIFFS_CACHE 1
|
||||
#endif
|
||||
#if SPIFFS_CACHE
|
||||
// Enables memory write caching for file descriptors in hydrogen
|
||||
#ifndef SPIFFS_CACHE_WR
|
||||
#define SPIFFS_CACHE_WR 1
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on caching. Debug/test purpose only.
|
||||
#ifndef SPIFFS_CACHE_STATS
|
||||
#define SPIFFS_CACHE_STATS 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Always check header of each accessed page to ensure consistent state.
|
||||
// If enabled it will increase number of reads, will increase flash.
|
||||
#ifndef SPIFFS_PAGE_CHECK
|
||||
#define SPIFFS_PAGE_CHECK 0
|
||||
#endif
|
||||
|
||||
// Define maximum number of gc runs to perform to reach desired free pages.
|
||||
#ifndef SPIFFS_GC_MAX_RUNS
|
||||
#define SPIFFS_GC_MAX_RUNS 5
|
||||
#endif
|
||||
|
||||
// Enable/disable statistics on gc. Debug/test purpose only.
|
||||
#ifndef SPIFFS_GC_STATS
|
||||
#define SPIFFS_GC_STATS 0
|
||||
#endif
|
||||
|
||||
// Garbage collecting examines all pages in a block which and sums up
|
||||
// to a block score. Deleted pages normally gives positive score and
|
||||
// used pages normally gives a negative score (as these must be moved).
|
||||
// To have a fair wear-leveling, the erase age is also included in score,
|
||||
// whose factor normally is the most positive.
|
||||
// The larger the score, the more likely it is that the block will
|
||||
// picked for garbage collection.
|
||||
|
||||
// Garbage collecting heuristics - weight used for deleted pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_DELET
|
||||
#define SPIFFS_GC_HEUR_W_DELET (5)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for used pages.
|
||||
#ifndef SPIFFS_GC_HEUR_W_USED
|
||||
#define SPIFFS_GC_HEUR_W_USED (-1)
|
||||
#endif
|
||||
// Garbage collecting heuristics - weight used for time between
|
||||
// last erased and erase of this block.
|
||||
#ifndef SPIFFS_GC_HEUR_W_ERASE_AGE
|
||||
#define SPIFFS_GC_HEUR_W_ERASE_AGE (50)
|
||||
#endif
|
||||
|
||||
// Object name maximum length. Note that this length include the
|
||||
// zero-termination character, meaning maximum string of characters
|
||||
// can at most be SPIFFS_OBJ_NAME_LEN - 1.
|
||||
#ifndef SPIFFS_OBJ_NAME_LEN
|
||||
#define SPIFFS_OBJ_NAME_LEN (64)
|
||||
#endif
|
||||
|
||||
// Maximum length of the metadata associated with an object.
|
||||
// Setting to non-zero value enables metadata-related API but also
|
||||
// changes the on-disk format, so the change is not backward-compatible.
|
||||
//
|
||||
// Do note: the meta length must never exceed
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + 64)
|
||||
//
|
||||
// This is derived from following:
|
||||
// logical_page_size - (SPIFFS_OBJ_NAME_LEN + sizeof(spiffs_page_header) +
|
||||
// spiffs_object_ix_header fields + at least some LUT entries)
|
||||
#ifndef SPIFFS_OBJ_META_LEN
|
||||
#define SPIFFS_OBJ_META_LEN (64)
|
||||
#endif
|
||||
|
||||
// Size of buffer allocated on stack used when copying data.
|
||||
// Lower value generates more read/writes. No meaning having it bigger
|
||||
// than logical page size.
|
||||
#ifndef SPIFFS_COPY_BUFFER_STACK
|
||||
#define SPIFFS_COPY_BUFFER_STACK (256)
|
||||
#endif
|
||||
|
||||
// Enable this to have an identifiable spiffs filesystem. This will look for
|
||||
// a magic in all sectors to determine if this is a valid spiffs system or
|
||||
// not on mount point. If not, SPIFFS_format must be called prior to mounting
|
||||
// again.
|
||||
#ifndef SPIFFS_USE_MAGIC
|
||||
#define SPIFFS_USE_MAGIC (1)
|
||||
#endif
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
// Only valid when SPIFFS_USE_MAGIC is enabled. If SPIFFS_USE_MAGIC_LENGTH is
|
||||
// enabled, the magic will also be dependent on the length of the filesystem.
|
||||
// For example, a filesystem configured and formatted for 4 megabytes will not
|
||||
// be accepted for mounting with a configuration defining the filesystem as 2
|
||||
// megabytes.
|
||||
#ifndef SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_USE_MAGIC_LENGTH (1)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// SPIFFS_LOCK and SPIFFS_UNLOCK protects spiffs from reentrancy on api level
|
||||
// These should be defined on a multithreaded system
|
||||
|
||||
// define this to enter a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_LOCK
|
||||
#define SPIFFS_LOCK(fs) xSemaphoreTake(spiffs_mutex, portMAX_DELAY)
|
||||
#endif
|
||||
// define this to exit a mutex if you're running on a multithreaded system
|
||||
#ifndef SPIFFS_UNLOCK
|
||||
#define SPIFFS_UNLOCK(fs) xSemaphoreGive(spiffs_mutex)
|
||||
#endif
|
||||
|
||||
// Enable if only one spiffs instance with constant configuration will exist
|
||||
// on the target. This will reduce calculations, flash and memory accesses.
|
||||
// Parts of configuration must be defined below instead of at time of mount.
|
||||
#ifndef SPIFFS_SINGLETON
|
||||
#define SPIFFS_SINGLETON 0
|
||||
#endif
|
||||
|
||||
#if SPIFFS_SINGLETON
|
||||
// Instead of giving parameters in config struct, singleton build must
|
||||
// give parameters in defines below.
|
||||
#ifndef SPIFFS_CFG_PHYS_SZ
|
||||
#define SPIFFS_CFG_PHYS_SZ(ignore) (1024*1024*2)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ERASE_SZ
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(ignore) (65536)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_PHYS_ADDR
|
||||
#define SPIFFS_CFG_PHYS_ADDR(ignore) (0)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_PAGE_SZ
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(ignore) (256)
|
||||
#endif
|
||||
#ifndef SPIFFS_CFG_LOG_BLOCK_SZ
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(ignore) (65536)
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Enable this if your target needs aligned data for index tables
|
||||
#ifndef SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
#define SPIFFS_ALIGNED_OBJECT_INDEX_TABLES 1
|
||||
#endif
|
||||
|
||||
// Enable this if you want the HAL callbacks to be called with the spiffs struct
|
||||
#ifndef SPIFFS_HAL_CALLBACK_EXTRA
|
||||
#define SPIFFS_HAL_CALLBACK_EXTRA 0
|
||||
#endif
|
||||
|
||||
// Enable this if you want to add an integer offset to all file handles
|
||||
// (spiffs_file). This is useful if running multiple instances of spiffs on
|
||||
// same target, in order to recognise to what spiffs instance a file handle
|
||||
// belongs.
|
||||
// NB: This adds config field fh_ix_offset in the configuration struct when
|
||||
// mounting, which must be defined.
|
||||
#ifndef SPIFFS_FILEHDL_OFFSET
|
||||
#define SPIFFS_FILEHDL_OFFSET 0
|
||||
#endif
|
||||
|
||||
// Enable this to compile a read only version of spiffs.
|
||||
// This will reduce binary size of spiffs. All code comprising modification
|
||||
// of the file system will not be compiled. Some config will be ignored.
|
||||
// HAL functions for erasing and writing to spi-flash may be null. Cache
|
||||
// can be disabled for even further binary size reduction (and ram savings).
|
||||
// Functions modifying the fs will return SPIFFS_ERR_RO_NOT_IMPL.
|
||||
// If the file system cannot be mounted due to aborted erase operation and
|
||||
// SPIFFS_USE_MAGIC is enabled, SPIFFS_ERR_RO_ABORTED_OPERATION will be
|
||||
// returned.
|
||||
// Might be useful for e.g. bootloaders and such.
|
||||
#ifndef SPIFFS_READ_ONLY
|
||||
#define SPIFFS_READ_ONLY 0
|
||||
#endif
|
||||
|
||||
// Enable this to add a temporal file cache using the fd buffer.
|
||||
// The effects of the cache is that SPIFFS_open will find the file faster in
|
||||
// certain cases. It will make it a lot easier for spiffs to find files
|
||||
// opened frequently, reducing number of readings from the spi flash for
|
||||
// finding those files.
|
||||
// This will grow each fd by 6 bytes. If your files are opened in patterns
|
||||
// with a degree of temporal locality, the system is optimized.
|
||||
// Examples can be letting spiffs serve web content, where one file is the css.
|
||||
// The css is accessed for each html file that is opened, meaning it is
|
||||
// accessed almost every second time a file is opened. Another example could be
|
||||
// a log file that is often opened, written, and closed.
|
||||
// The size of the cache is number of given file descriptors, as it piggybacks
|
||||
// on the fd update mechanism. The cache lives in the closed file descriptors.
|
||||
// When closed, the fd know the whereabouts of the file. Instead of forgetting
|
||||
// this, the temporal cache will keep handling updates to that file even if the
|
||||
// fd is closed. If the file is opened again, the location of the file is found
|
||||
// directly. If all available descriptors become opened, all cache memory is
|
||||
// lost.
|
||||
#ifndef SPIFFS_TEMPORAL_FD_CACHE
|
||||
#define SPIFFS_TEMPORAL_FD_CACHE 1
|
||||
#endif
|
||||
|
||||
// Temporal file cache hit score. Each time a file is opened, all cached files
|
||||
// will lose one point. If the opened file is found in cache, that entry will
|
||||
// gain SPIFFS_TEMPORAL_CACHE_HIT_SCORE points. One can experiment with this
|
||||
// value for the specific access patterns of the application. However, it must
|
||||
// be between 1 (no gain for hitting a cached entry often) and 255.
|
||||
#ifndef SPIFFS_TEMPORAL_CACHE_HIT_SCORE
|
||||
#define SPIFFS_TEMPORAL_CACHE_HIT_SCORE 8
|
||||
#endif
|
||||
|
||||
// Enable to be able to map object indices to memory.
|
||||
// This allows for faster and more deterministic reading if cases of reading
|
||||
// large files and when changing file offset by seeking around a lot.
|
||||
// When mapping a file's index, the file system will be scanned for index pages
|
||||
// and the info will be put in memory provided by user. When reading, the
|
||||
// memory map can be looked up instead of searching for index pages on the
|
||||
// medium. This way, user can trade memory against performance.
|
||||
// Whole, parts of, or future parts not being written yet can be mapped. The
|
||||
// memory array will be owned by spiffs and updated accordingly during garbage
|
||||
// collecting or when modifying the indices. The latter is invoked by when the
|
||||
// file is modified in some way. The index buffer is tied to the file
|
||||
// descriptor.
|
||||
#ifndef SPIFFS_IX_MAP
|
||||
#define SPIFFS_IX_MAP 1
|
||||
#endif
|
||||
|
||||
// Set SPIFFS_TEST_VISUALISATION to non-zero to enable SPIFFS_vis function
|
||||
// in the api. This function will visualize all filesystem using given printf
|
||||
// function.
|
||||
#ifndef SPIFFS_TEST_VISUALISATION
|
||||
#define SPIFFS_TEST_VISUALISATION 0
|
||||
#endif
|
||||
#if SPIFFS_TEST_VISUALISATION
|
||||
#ifndef spiffs_printf
|
||||
#define spiffs_printf(...) printf(__VA_ARGS__)
|
||||
#endif
|
||||
// spiffs_printf argument for a free page
|
||||
#ifndef SPIFFS_TEST_VIS_FREE_STR
|
||||
#define SPIFFS_TEST_VIS_FREE_STR "_"
|
||||
#endif
|
||||
// spiffs_printf argument for a deleted page
|
||||
#ifndef SPIFFS_TEST_VIS_DELE_STR
|
||||
#define SPIFFS_TEST_VIS_DELE_STR "/"
|
||||
#endif
|
||||
// spiffs_printf argument for an index page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_INDX_STR
|
||||
#define SPIFFS_TEST_VIS_INDX_STR(id) "i"
|
||||
#endif
|
||||
// spiffs_printf argument for a data page for given object id
|
||||
#ifndef SPIFFS_TEST_VIS_DATA_STR
|
||||
#define SPIFFS_TEST_VIS_DATA_STR(id) "d"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
// Types depending on configuration such as the amount of flash bytes
|
||||
// given to spiffs file system in total (spiffs_file_system_size),
|
||||
// the logical block size (log_block_size), and the logical page size
|
||||
// (log_page_size)
|
||||
|
||||
// Block index type. Make sure the size of this type can hold
|
||||
// the highest number of all blocks - i.e. spiffs_file_system_size / log_block_size
|
||||
typedef u16_t spiffs_block_ix;
|
||||
// Page index type. Make sure the size of this type can hold
|
||||
// the highest page number of all pages - i.e. spiffs_file_system_size / log_page_size
|
||||
typedef u16_t spiffs_page_ix;
|
||||
// Object id type - most significant bit is reserved for index flag. Make sure the
|
||||
// size of this type can hold the highest object id on a full system,
|
||||
// i.e. 2 + (spiffs_file_system_size / (2*log_page_size))*2
|
||||
typedef u16_t spiffs_obj_id;
|
||||
// Object span index type. Make sure the size of this type can
|
||||
// hold the largest possible span index on the system -
|
||||
// i.e. (spiffs_file_system_size / log_page_size) - 1
|
||||
typedef u16_t spiffs_span_ix;
|
||||
|
||||
#endif /* SPIFFS_CONFIG_H_ */
|
606
components/spiffs/spiffs_gc.c
Normal file
606
components/spiffs/spiffs_gc.c
Normal file
@ -0,0 +1,606 @@
|
||||
#include "spiffs.h"
|
||||
#include "spiffs_nucleus.h"
|
||||
|
||||
#if !SPIFFS_READ_ONLY
|
||||
|
||||
// Erases a logical block and updates the erase counter.
|
||||
// If cache is enabled, all pages that might be cached in this block
|
||||
// is dropped.
|
||||
static s32_t spiffs_gc_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res;
|
||||
|
||||
SPIFFS_GC_DBG("gc: erase block "_SPIPRIbl"\n", bix);
|
||||
res = spiffs_erase_block(fs, bix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
{
|
||||
u32_t i;
|
||||
for (i = 0; i < SPIFFS_PAGES_PER_BLOCK(fs); i++) {
|
||||
spiffs_cache_drop_page(fs, SPIFFS_PAGE_FOR_BLOCK(fs, bix) + i);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
return res;
|
||||
}
|
||||
|
||||
// Searches for blocks where all entries are deleted - if one is found,
|
||||
// the block is erased. Compared to the non-quick gc, the quick one ensures
|
||||
// that no updates are needed on existing objects on pages that are erased.
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_quick: running\n");
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// find fully deleted blocks
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t free_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// kill scan, go for next block
|
||||
free_pages_in_block++;
|
||||
if (free_pages_in_block > max_free_pages) {
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// kill scan, go for next block
|
||||
obj_lookup_page = SPIFFS_OBJ_LOOKUP_PAGES(fs);
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
if (res == SPIFFS_OK &&
|
||||
deleted_pages_in_block + free_pages_in_block == SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs) &&
|
||||
free_pages_in_block <= max_free_pages) {
|
||||
// found a fully deleted block
|
||||
fs->stats_p_deleted -= deleted_pages_in_block;
|
||||
res = spiffs_gc_erase_block(fs, cur_block);
|
||||
return res;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
if (res == SPIFFS_OK) {
|
||||
res = SPIFFS_ERR_NO_DELETED_BLOCKS;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Checks if garbage collecting is necessary. If so a candidate block is found,
|
||||
// cleansed and erased
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len) {
|
||||
s32_t res;
|
||||
s32_t free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count-2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
int tries = 0;
|
||||
|
||||
if (fs->free_blocks > 3 &&
|
||||
(s32_t)len < free_pages * (s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
return SPIFFS_OK;
|
||||
}
|
||||
|
||||
u32_t needed_pages = (len + SPIFFS_DATA_PAGE_SIZE(fs) - 1) / SPIFFS_DATA_PAGE_SIZE(fs);
|
||||
// if (fs->free_blocks <= 2 && (s32_t)needed_pages > free_pages) {
|
||||
// SPIFFS_GC_DBG("gc: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
// return SPIFFS_ERR_FULL;
|
||||
// }
|
||||
if ((s32_t)needed_pages > (s32_t)(free_pages + fs->stats_p_deleted)) {
|
||||
SPIFFS_GC_DBG("gc_check: full freeblk:"_SPIPRIi" needed:"_SPIPRIi" free:"_SPIPRIi" dele:"_SPIPRIi"\n", fs->free_blocks, needed_pages, free_pages, fs->stats_p_deleted);
|
||||
return SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
do {
|
||||
SPIFFS_GC_DBG("\ngc_check #"_SPIPRIi": run gc free_blocks:"_SPIPRIi" pfree:"_SPIPRIi" pallo:"_SPIPRIi" pdele:"_SPIPRIi" ["_SPIPRIi"] len:"_SPIPRIi" of "_SPIPRIi"\n",
|
||||
tries,
|
||||
fs->free_blocks, free_pages, fs->stats_p_allocated, fs->stats_p_deleted, (free_pages+fs->stats_p_allocated+fs->stats_p_deleted),
|
||||
len, (u32_t)(free_pages*SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
spiffs_block_ix *cands;
|
||||
int count;
|
||||
spiffs_block_ix cand;
|
||||
s32_t prev_free_pages = free_pages;
|
||||
// if the fs is crammed, ignore block age when selecting candidate - kind of a bad state
|
||||
res = spiffs_gc_find_candidate(fs, &cands, &count, free_pages <= 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (count == 0) {
|
||||
SPIFFS_GC_DBG("gc_check: no candidates, return\n");
|
||||
return (s32_t)needed_pages < free_pages ? SPIFFS_OK : SPIFFS_ERR_FULL;
|
||||
}
|
||||
#if SPIFFS_GC_STATS
|
||||
fs->stats_gc_runs++;
|
||||
#endif
|
||||
cand = cands[0];
|
||||
fs->cleaning = 1;
|
||||
//SPIFFS_GC_DBG("gcing: cleaning block "_SPIPRIi"\n", cand);
|
||||
res = spiffs_gc_clean(fs, cand);
|
||||
fs->cleaning = 0;
|
||||
if (res < 0) {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res);
|
||||
} else {
|
||||
SPIFFS_GC_DBG("gc_check: cleaning block "_SPIPRIi", result "_SPIPRIi"\n", cand, res);
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_page_stats(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
res = spiffs_gc_erase_block(fs, cand);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
|
||||
if (prev_free_pages <= 0 && prev_free_pages == free_pages) {
|
||||
// abort early to reduce wear, at least tried once
|
||||
SPIFFS_GC_DBG("gc_check: early abort, no result on gc when fs crammed\n");
|
||||
break;
|
||||
}
|
||||
|
||||
} while (++tries < SPIFFS_GC_MAX_RUNS && (fs->free_blocks <= 2 ||
|
||||
(s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)));
|
||||
|
||||
free_pages =
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs)) * (fs->block_count - 2)
|
||||
- fs->stats_p_allocated - fs->stats_p_deleted;
|
||||
if ((s32_t)len > free_pages*(s32_t)SPIFFS_DATA_PAGE_SIZE(fs)) {
|
||||
res = SPIFFS_ERR_FULL;
|
||||
}
|
||||
|
||||
SPIFFS_GC_DBG("gc_check: finished, "_SPIPRIi" dirty, blocks "_SPIPRIi" free, "_SPIPRIi" pages free, "_SPIPRIi" tries, res "_SPIPRIi"\n",
|
||||
fs->stats_p_allocated + fs->stats_p_deleted,
|
||||
fs->free_blocks, free_pages, tries, res);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
// Updates page statistics for a block that is about to be erased
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
int obj_lookup_page = 0;
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
u32_t dele = 0;
|
||||
u32_t allo = 0;
|
||||
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
dele++;
|
||||
} else {
|
||||
allo++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
SPIFFS_GC_DBG("gc_check: wipe pallo:"_SPIPRIi" pdele:"_SPIPRIi"\n", allo, dele);
|
||||
fs->stats_p_allocated -= allo;
|
||||
fs->stats_p_deleted -= dele;
|
||||
return res;
|
||||
}
|
||||
|
||||
// Finds block candidates to erase
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidates,
|
||||
int *candidate_count,
|
||||
char fs_crammed) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
u32_t blocks = fs->block_count;
|
||||
spiffs_block_ix cur_block = 0;
|
||||
u32_t cur_block_addr = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
int cur_entry = 0;
|
||||
|
||||
// using fs->work area as sorted candidate memory, (spiffs_block_ix)cand_bix/(s32_t)score
|
||||
int max_candidates = MIN(fs->block_count, (SPIFFS_CFG_LOG_PAGE_SZ(fs)-8)/(sizeof(spiffs_block_ix) + sizeof(s32_t)));
|
||||
*candidate_count = 0;
|
||||
memset(fs->work, 0xff, SPIFFS_CFG_LOG_PAGE_SZ(fs));
|
||||
|
||||
// divide up work area into block indices and scores
|
||||
spiffs_block_ix *cand_blocks = (spiffs_block_ix *)fs->work;
|
||||
s32_t *cand_scores = (s32_t *)(fs->work + max_candidates * sizeof(spiffs_block_ix));
|
||||
|
||||
// align cand_scores on s32_t boundary
|
||||
cand_scores = (s32_t*)(((intptr_t)cand_scores + sizeof(intptr_t) - 1) & ~(sizeof(intptr_t) - 1));
|
||||
|
||||
*block_candidates = cand_blocks;
|
||||
|
||||
int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
|
||||
// check each block
|
||||
while (res == SPIFFS_OK && blocks--) {
|
||||
u16_t deleted_pages_in_block = 0;
|
||||
u16_t used_pages_in_block = 0;
|
||||
|
||||
int obj_lookup_page = 0;
|
||||
// check each object lookup page
|
||||
while (res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, cur_block_addr + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each entry
|
||||
while (res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page &&
|
||||
cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
if (obj_id == SPIFFS_OBJ_ID_FREE) {
|
||||
// when a free entry is encountered, scan logic ensures that all following entries are free also
|
||||
res = 1; // kill object lu loop
|
||||
break;
|
||||
} else if (obj_id == SPIFFS_OBJ_ID_DELETED) {
|
||||
deleted_pages_in_block++;
|
||||
} else {
|
||||
used_pages_in_block++;
|
||||
}
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++;
|
||||
} // per object lookup page
|
||||
if (res == 1) res = SPIFFS_OK;
|
||||
|
||||
// calculate score and insert into candidate table
|
||||
// stoneage sort, but probably not so many blocks
|
||||
if (res == SPIFFS_OK /*&& deleted_pages_in_block > 0*/) {
|
||||
// read erase count
|
||||
spiffs_obj_id erase_count;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_C_READ | SPIFFS_OP_T_OBJ_LU2, 0,
|
||||
SPIFFS_ERASE_COUNT_PADDR(fs, cur_block),
|
||||
sizeof(spiffs_obj_id), (u8_t *)&erase_count);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
|
||||
spiffs_obj_id erase_age;
|
||||
if (fs->max_erase_count > erase_count) {
|
||||
erase_age = fs->max_erase_count - erase_count;
|
||||
} else {
|
||||
erase_age = SPIFFS_OBJ_ID_FREE - (erase_count - fs->max_erase_count);
|
||||
}
|
||||
|
||||
s32_t score =
|
||||
deleted_pages_in_block * SPIFFS_GC_HEUR_W_DELET +
|
||||
used_pages_in_block * SPIFFS_GC_HEUR_W_USED +
|
||||
erase_age * (fs_crammed ? 0 : SPIFFS_GC_HEUR_W_ERASE_AGE);
|
||||
int cand_ix = 0;
|
||||
SPIFFS_GC_DBG("gc_check: bix:"_SPIPRIbl" del:"_SPIPRIi" use:"_SPIPRIi" score:"_SPIPRIi"\n", cur_block, deleted_pages_in_block, used_pages_in_block, score);
|
||||
while (cand_ix < max_candidates) {
|
||||
if (cand_blocks[cand_ix] == (spiffs_block_ix)-1) {
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
} else if (cand_scores[cand_ix] < score) {
|
||||
int reorder_cand_ix = max_candidates - 2;
|
||||
while (reorder_cand_ix >= cand_ix) {
|
||||
cand_blocks[reorder_cand_ix + 1] = cand_blocks[reorder_cand_ix];
|
||||
cand_scores[reorder_cand_ix + 1] = cand_scores[reorder_cand_ix];
|
||||
reorder_cand_ix--;
|
||||
}
|
||||
cand_blocks[cand_ix] = cur_block;
|
||||
cand_scores[cand_ix] = score;
|
||||
break;
|
||||
}
|
||||
cand_ix++;
|
||||
}
|
||||
(*candidate_count)++;
|
||||
}
|
||||
|
||||
cur_entry = 0;
|
||||
cur_block++;
|
||||
cur_block_addr += SPIFFS_CFG_LOG_BLOCK_SZ(fs);
|
||||
} // per block
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
typedef enum {
|
||||
FIND_OBJ_DATA,
|
||||
MOVE_OBJ_DATA,
|
||||
MOVE_OBJ_IX,
|
||||
FINISHED
|
||||
} spiffs_gc_clean_state;
|
||||
|
||||
typedef struct {
|
||||
spiffs_gc_clean_state state;
|
||||
spiffs_obj_id cur_obj_id;
|
||||
spiffs_span_ix cur_objix_spix;
|
||||
spiffs_page_ix cur_objix_pix;
|
||||
spiffs_page_ix cur_data_pix;
|
||||
int stored_scan_entry_index;
|
||||
u8_t obj_id_found;
|
||||
} spiffs_gc;
|
||||
|
||||
// Empties given block by moving all data into free pages of another block
|
||||
// Strategy:
|
||||
// loop:
|
||||
// scan object lookup for object data pages
|
||||
// for first found id, check spix and load corresponding object index page to memory
|
||||
// push object scan lookup entry index
|
||||
// rescan object lookup, find data pages with same id and referenced by same object index
|
||||
// move data page, update object index in memory
|
||||
// when reached end of lookup, store updated object index
|
||||
// pop object scan lookup entry index
|
||||
// repeat loop until end of object lookup
|
||||
// scan object lookup again for remaining object index pages, move to new page in other block
|
||||
//
|
||||
s32_t spiffs_gc_clean(spiffs *fs, spiffs_block_ix bix) {
|
||||
s32_t res = SPIFFS_OK;
|
||||
const int entries_per_page = (SPIFFS_CFG_LOG_PAGE_SZ(fs) / sizeof(spiffs_obj_id));
|
||||
// this is the global localizer being pushed and popped
|
||||
int cur_entry = 0;
|
||||
spiffs_obj_id *obj_lu_buf = (spiffs_obj_id *)fs->lu_work;
|
||||
spiffs_gc gc; // our stack frame/state
|
||||
spiffs_page_ix cur_pix = 0;
|
||||
spiffs_page_object_ix_header *objix_hdr = (spiffs_page_object_ix_header *)fs->work;
|
||||
spiffs_page_object_ix *objix = (spiffs_page_object_ix *)fs->work;
|
||||
|
||||
SPIFFS_GC_DBG("gc_clean: cleaning block "_SPIPRIbl"\n", bix);
|
||||
|
||||
memset(&gc, 0, sizeof(spiffs_gc));
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
|
||||
if (fs->free_cursor_block_ix == bix) {
|
||||
// move free cursor to next block, cannot use free pages from the block we want to clean
|
||||
fs->free_cursor_block_ix = (bix+1)%fs->block_count;
|
||||
fs->free_cursor_obj_lu_entry = 0;
|
||||
SPIFFS_GC_DBG("gc_clean: move free cursor to block "_SPIPRIbl"\n", fs->free_cursor_block_ix);
|
||||
}
|
||||
|
||||
while (res == SPIFFS_OK && gc.state != FINISHED) {
|
||||
SPIFFS_GC_DBG("gc_clean: state = "_SPIPRIi" entry:"_SPIPRIi"\n", gc.state, cur_entry);
|
||||
gc.obj_id_found = 0; // reset (to no found data page)
|
||||
|
||||
// scan through lookup pages
|
||||
int obj_lookup_page = cur_entry / entries_per_page;
|
||||
u8_t scan = 1;
|
||||
// check each object lookup page
|
||||
while (scan && res == SPIFFS_OK && obj_lookup_page < (int)SPIFFS_OBJ_LOOKUP_PAGES(fs)) {
|
||||
int entry_offset = obj_lookup_page * entries_per_page;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
// check each object lookup entry
|
||||
while (scan && res == SPIFFS_OK &&
|
||||
cur_entry - entry_offset < entries_per_page && cur_entry < (int)(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))) {
|
||||
spiffs_obj_id obj_id = obj_lu_buf[cur_entry-entry_offset];
|
||||
cur_pix = SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, bix, cur_entry);
|
||||
|
||||
// act upon object id depending on gc state
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
// find a data page
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
((obj_id & SPIFFS_OBJ_ID_IX_FLAG) == 0)) {
|
||||
// found a data page, stop scanning and handle in switch case below
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA state:"_SPIPRIi" - found obj id "_SPIPRIid"\n", gc.state, obj_id);
|
||||
gc.obj_id_found = 1;
|
||||
gc.cur_obj_id = obj_id;
|
||||
gc.cur_data_pix = cur_pix;
|
||||
scan = 0;
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA:
|
||||
// evacuate found data pages for corresponding object index we have in memory,
|
||||
// update memory representation
|
||||
if (obj_id == gc.cur_obj_id) {
|
||||
spiffs_page_header p_hdr;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA found data page "_SPIPRIid":"_SPIPRIsp" @ "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix);
|
||||
if (SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix) != gc.cur_objix_spix) {
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA no objix spix match, take in another run\n");
|
||||
} else {
|
||||
spiffs_page_ix new_data_pix;
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_data_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", gc.cur_obj_id, p_hdr.span_ix, cur_pix, new_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
new_data_pix = SPIFFS_OBJ_ID_FREE;
|
||||
}
|
||||
// update memory representation of object index page with new data page
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// update object index header page
|
||||
((spiffs_page_ix*)((u8_t *)objix_hdr + sizeof(spiffs_page_object_ix_header)))[p_hdr.span_ix] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix_hdr entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
} else {
|
||||
// update object index page
|
||||
((spiffs_page_ix*)((u8_t *)objix + sizeof(spiffs_page_object_ix)))[SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix)] = new_data_pix;
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA wrote page "_SPIPRIpg" to objix entry "_SPIPRIsp" in mem\n", new_data_pix, (spiffs_span_ix)SPIFFS_OBJ_IX_ENTRY(fs, p_hdr.span_ix));
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
// find and evacuate object index pages
|
||||
if (obj_id != SPIFFS_OBJ_ID_DELETED && obj_id != SPIFFS_OBJ_ID_FREE &&
|
||||
(obj_id & SPIFFS_OBJ_ID_IX_FLAG)) {
|
||||
// found an index object id
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix new_pix;
|
||||
// load header
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
if (p_hdr.flags & SPIFFS_PH_FLAG_DELET) {
|
||||
// move page
|
||||
res = spiffs_page_move(fs, 0, 0, obj_id, &p_hdr, cur_pix, &new_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX move objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg" to "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix, new_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)&p_hdr,
|
||||
SPIFFS_EV_IX_MOV, obj_id, p_hdr.span_ix, new_pix, 0);
|
||||
// move wipes obj_lu, reload it
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU | SPIFFS_OP_C_READ,
|
||||
0, bix * SPIFFS_CFG_LOG_BLOCK_SZ(fs) + SPIFFS_PAGE_TO_PADDR(fs, obj_lookup_page),
|
||||
SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->lu_work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// page is deleted but not deleted in lookup, scrap it -
|
||||
// might seem unnecessary as we will erase this block, but
|
||||
// we might get aborted
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_OBJIX wipe objix "_SPIPRIid":"_SPIPRIsp" page "_SPIPRIpg"\n", obj_id, p_hdr.span_ix, cur_pix);
|
||||
res = spiffs_page_delete(fs, cur_pix);
|
||||
if (res == SPIFFS_OK) {
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)0,
|
||||
SPIFFS_EV_IX_DEL, obj_id, p_hdr.span_ix, cur_pix, 0);
|
||||
}
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
scan = 0;
|
||||
break;
|
||||
} // switch gc state
|
||||
cur_entry++;
|
||||
} // per entry
|
||||
obj_lookup_page++; // no need to check scan variable here, obj_lookup_page is set in start of loop
|
||||
} // per object lookup page
|
||||
if (res != SPIFFS_OK) break;
|
||||
|
||||
// state finalization and switch
|
||||
switch (gc.state) {
|
||||
case FIND_OBJ_DATA:
|
||||
if (gc.obj_id_found) {
|
||||
// handle found data page -
|
||||
// find out corresponding obj ix page and load it to memory
|
||||
spiffs_page_header p_hdr;
|
||||
spiffs_page_ix objix_pix;
|
||||
gc.stored_scan_entry_index = cur_entry; // push cursor
|
||||
cur_entry = 0; // restart scan from start
|
||||
gc.state = MOVE_OBJ_DATA;
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, cur_pix), sizeof(spiffs_page_header), (u8_t*)&p_hdr);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
gc.cur_objix_spix = SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, p_hdr.span_ix);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA find objix span_ix:"_SPIPRIsp"\n", gc.cur_objix_spix);
|
||||
res = spiffs_obj_lu_find_id_and_span(fs, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix, 0, &objix_pix);
|
||||
if (res == SPIFFS_ERR_NOT_FOUND) {
|
||||
// on borked systems we might get an ERR_NOT_FOUND here -
|
||||
// this is handled by simply deleting the page as it is not referenced
|
||||
// from anywhere
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_OBJ_DATA objix not found! Wipe page "_SPIPRIpg"\n", gc.cur_data_pix);
|
||||
res = spiffs_page_delete(fs, gc.cur_data_pix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// then we restore states and continue scanning for data pages
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
break; // done
|
||||
}
|
||||
SPIFFS_CHECK_RES(res);
|
||||
SPIFFS_GC_DBG("gc_clean: FIND_DATA found object index at page "_SPIPRIpg"\n", objix_pix);
|
||||
res = _spiffs_rd(fs, SPIFFS_OP_T_OBJ_LU2 | SPIFFS_OP_C_READ,
|
||||
0, SPIFFS_PAGE_TO_PADDR(fs, objix_pix), SPIFFS_CFG_LOG_PAGE_SZ(fs), fs->work);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
// cannot allow a gc if the presumed index in fact is no index, a
|
||||
// check must run or lot of data may be lost
|
||||
SPIFFS_VALIDATE_OBJIX(objix->p_hdr, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_spix);
|
||||
gc.cur_objix_pix = objix_pix;
|
||||
} else {
|
||||
// no more data pages found, passed thru all block, start evacuating object indices
|
||||
gc.state = MOVE_OBJ_IX;
|
||||
cur_entry = 0; // restart entry scan index
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_DATA: {
|
||||
// store modified objix (hdr) page residing in memory now that all
|
||||
// data pages belonging to this object index and residing in the block
|
||||
// we want to evacuate
|
||||
spiffs_page_ix new_objix_pix;
|
||||
gc.state = FIND_OBJ_DATA;
|
||||
cur_entry = gc.stored_scan_entry_index; // pop cursor
|
||||
if (gc.cur_objix_spix == 0) {
|
||||
// store object index header page
|
||||
res = spiffs_object_update_index_hdr(fs, 0, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, gc.cur_objix_pix, fs->work, 0, 0, 0, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix_hdr page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, 0);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
} else {
|
||||
// store object index page
|
||||
res = spiffs_page_move(fs, 0, fs->work, gc.cur_obj_id | SPIFFS_OBJ_ID_IX_FLAG, 0, gc.cur_objix_pix, &new_objix_pix);
|
||||
SPIFFS_GC_DBG("gc_clean: MOVE_DATA store modified objix page, "_SPIPRIpg":"_SPIPRIsp"\n", new_objix_pix, objix->p_hdr.span_ix);
|
||||
SPIFFS_CHECK_RES(res);
|
||||
spiffs_cb_object_event(fs, (spiffs_page_object_ix *)fs->work,
|
||||
SPIFFS_EV_IX_UPD, gc.cur_obj_id, objix->p_hdr.span_ix, new_objix_pix, 0);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case MOVE_OBJ_IX:
|
||||
// scanned thru all block, no more object indices found - our work here is done
|
||||
gc.state = FINISHED;
|
||||
break;
|
||||
default:
|
||||
cur_entry = 0;
|
||||
break;
|
||||
} // switch gc.state
|
||||
SPIFFS_GC_DBG("gc_clean: state-> "_SPIPRIi"\n", gc.state);
|
||||
} // while state != FINISHED
|
||||
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
#endif // !SPIFFS_READ_ONLY
|
1405
components/spiffs/spiffs_hydrogen.c
Normal file
1405
components/spiffs/spiffs_hydrogen.c
Normal file
File diff suppressed because it is too large
Load Diff
2327
components/spiffs/spiffs_nucleus.c
Normal file
2327
components/spiffs/spiffs_nucleus.c
Normal file
File diff suppressed because it is too large
Load Diff
797
components/spiffs/spiffs_nucleus.h
Normal file
797
components/spiffs/spiffs_nucleus.h
Normal file
@ -0,0 +1,797 @@
|
||||
/*
|
||||
* spiffs_nucleus.h
|
||||
*
|
||||
* Created on: Jun 15, 2013
|
||||
* Author: petera
|
||||
*/
|
||||
|
||||
/* SPIFFS layout
|
||||
*
|
||||
* spiffs is designed for following spi flash characteristics:
|
||||
* - only big areas of data (blocks) can be erased
|
||||
* - erasing resets all bits in a block to ones
|
||||
* - writing pulls ones to zeroes
|
||||
* - zeroes cannot be pulled to ones, without erase
|
||||
* - wear leveling
|
||||
*
|
||||
* spiffs is also meant to be run on embedded, memory constraint devices.
|
||||
*
|
||||
* Entire area is divided in blocks. Entire area is also divided in pages.
|
||||
* Each block contains same number of pages. A page cannot be erased, but a
|
||||
* block can be erased.
|
||||
*
|
||||
* Entire area must be block_size * x
|
||||
* page_size must be block_size / (2^y) where y > 2
|
||||
*
|
||||
* ex: area = 1024*1024 bytes, block size = 65536 bytes, page size = 256 bytes
|
||||
*
|
||||
* BLOCK 0 PAGE 0 object lookup 1
|
||||
* PAGE 1 object lookup 2
|
||||
* ...
|
||||
* PAGE n-1 object lookup n
|
||||
* PAGE n object data 1
|
||||
* PAGE n+1 object data 2
|
||||
* ...
|
||||
* PAGE n+m-1 object data m
|
||||
*
|
||||
* BLOCK 1 PAGE n+m object lookup 1
|
||||
* PAGE n+m+1 object lookup 2
|
||||
* ...
|
||||
* PAGE 2n+m-1 object lookup n
|
||||
* PAGE 2n+m object data 1
|
||||
* PAGE 2n+m object data 2
|
||||
* ...
|
||||
* PAGE 2n+2m-1 object data m
|
||||
* ...
|
||||
*
|
||||
* n is number of object lookup pages, which is number of pages needed to index all pages
|
||||
* in a block by object id
|
||||
* : block_size / page_size * sizeof(obj_id) / page_size
|
||||
* m is number data pages, which is number of pages in block minus number of lookup pages
|
||||
* : block_size / page_size - block_size / page_size * sizeof(obj_id) / page_size
|
||||
* thus, n+m is total number of pages in a block
|
||||
* : block_size / page_size
|
||||
*
|
||||
* ex: n = 65536/256*2/256 = 2, m = 65536/256 - 2 = 254 => n+m = 65536/256 = 256
|
||||
*
|
||||
* Object lookup pages contain object id entries. Each entry represent the corresponding
|
||||
* data page.
|
||||
* Assuming a 16 bit object id, an object id being 0xffff represents a free page.
|
||||
* An object id being 0x0000 represents a deleted page.
|
||||
*
|
||||
* ex: page 0 : lookup : 0008 0001 0aaa ffff ffff ffff ffff ffff ..
|
||||
* page 1 : lookup : ffff ffff ffff ffff ffff ffff ffff ffff ..
|
||||
* page 2 : data : data for object id 0008
|
||||
* page 3 : data : data for object id 0001
|
||||
* page 4 : data : data for object id 0aaa
|
||||
* ...
|
||||
*
|
||||
*
|
||||
* Object data pages can be either object index pages or object content.
|
||||
* All object data pages contains a data page header, containing object id and span index.
|
||||
* The span index denotes the object page ordering amongst data pages with same object id.
|
||||
* This applies to both object index pages (when index spans more than one page of entries),
|
||||
* and object data pages.
|
||||
* An object index page contains page entries pointing to object content page. The entry index
|
||||
* in a object index page correlates to the span index in the actual object data page.
|
||||
* The first object index page (span index 0) is called object index header page, and also
|
||||
* contains object flags (directory/file), size, object name etc.
|
||||
*
|
||||
* ex:
|
||||
* BLOCK 1
|
||||
* PAGE 256: objectl lookup page 1
|
||||
* [*123] [ 123] [ 123] [ 123]
|
||||
* [ 123] [*123] [ 123] [ 123]
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 257: objectl lookup page 2
|
||||
* [free] [free] [free] [free] ...
|
||||
* PAGE 258: object index page (header)
|
||||
* obj.id:0123 span.ix:0000 flags:INDEX
|
||||
* size:1600 name:ex.txt type:file
|
||||
* [259] [260] [261] [262]
|
||||
* PAGE 259: object data page
|
||||
* obj.id:0123 span.ix:0000 flags:DATA
|
||||
* PAGE 260: object data page
|
||||
* obj.id:0123 span.ix:0001 flags:DATA
|
||||
* PAGE 261: object data page
|
||||
* obj.id:0123 span.ix:0002 flags:DATA
|
||||
* PAGE 262: object data page
|
||||
* obj.id:0123 span.ix:0003 flags:DATA
|
||||
* PAGE 263: object index page
|
||||
* obj.id:0123 span.ix:0001 flags:INDEX
|
||||
* [264] [265] [fre] [fre]
|
||||
* [fre] [fre] [fre] [fre]
|
||||
* PAGE 264: object data page
|
||||
* obj.id:0123 span.ix:0004 flags:DATA
|
||||
* PAGE 265: object data page
|
||||
* obj.id:0123 span.ix:0005 flags:DATA
|
||||
*
|
||||
*/
|
||||
#ifndef SPIFFS_NUCLEUS_H_
|
||||
#define SPIFFS_NUCLEUS_H_
|
||||
|
||||
#define _SPIFFS_ERR_CHECK_FIRST (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_OBJ_ID_MISM (SPIFFS_ERR_INTERNAL - 1)
|
||||
#define SPIFFS_ERR_CHECK_SPIX_MISM (SPIFFS_ERR_INTERNAL - 2)
|
||||
#define SPIFFS_ERR_CHECK_FLAGS_BAD (SPIFFS_ERR_INTERNAL - 3)
|
||||
#define _SPIFFS_ERR_CHECK_LAST (SPIFFS_ERR_INTERNAL - 4)
|
||||
|
||||
// visitor result, continue searching
|
||||
#define SPIFFS_VIS_COUNTINUE (SPIFFS_ERR_INTERNAL - 20)
|
||||
// visitor result, continue searching after reloading lu buffer
|
||||
#define SPIFFS_VIS_COUNTINUE_RELOAD (SPIFFS_ERR_INTERNAL - 21)
|
||||
// visitor result, stop searching
|
||||
#define SPIFFS_VIS_END (SPIFFS_ERR_INTERNAL - 22)
|
||||
|
||||
// updating an object index contents
|
||||
#define SPIFFS_EV_IX_UPD (0)
|
||||
// creating a new object index
|
||||
#define SPIFFS_EV_IX_NEW (1)
|
||||
// deleting an object index
|
||||
#define SPIFFS_EV_IX_DEL (2)
|
||||
// moving an object index without updating contents
|
||||
#define SPIFFS_EV_IX_MOV (3)
|
||||
// updating an object index header data only, not the table itself
|
||||
#define SPIFFS_EV_IX_UPD_HDR (4)
|
||||
|
||||
#define SPIFFS_OBJ_ID_IX_FLAG ((spiffs_obj_id)(1<<(8*sizeof(spiffs_obj_id)-1)))
|
||||
|
||||
#define SPIFFS_UNDEFINED_LEN (u32_t)(-1)
|
||||
|
||||
#define SPIFFS_OBJ_ID_DELETED ((spiffs_obj_id)0)
|
||||
#define SPIFFS_OBJ_ID_FREE ((spiffs_obj_id)-1)
|
||||
|
||||
#if SPIFFS_USE_MAGIC
|
||||
#if !SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs)))
|
||||
#else // SPIFFS_USE_MAGIC_LENGTH
|
||||
#define SPIFFS_MAGIC(fs, bix) \
|
||||
((spiffs_obj_id)(0x20140529 ^ SPIFFS_CFG_LOG_PAGE_SZ(fs) ^ ((fs)->block_count - (bix))))
|
||||
#endif // SPIFFS_USE_MAGIC_LENGTH
|
||||
#endif // SPIFFS_USE_MAGIC
|
||||
|
||||
#define SPIFFS_CONFIG_MAGIC (0x20090315)
|
||||
|
||||
#if SPIFFS_SINGLETON == 0
|
||||
#define SPIFFS_CFG_LOG_PAGE_SZ(fs) \
|
||||
((fs)->cfg.log_page_size)
|
||||
#define SPIFFS_CFG_LOG_BLOCK_SZ(fs) \
|
||||
((fs)->cfg.log_block_size)
|
||||
#define SPIFFS_CFG_PHYS_SZ(fs) \
|
||||
((fs)->cfg.phys_size)
|
||||
#define SPIFFS_CFG_PHYS_ERASE_SZ(fs) \
|
||||
((fs)->cfg.phys_erase_block)
|
||||
#define SPIFFS_CFG_PHYS_ADDR(fs) \
|
||||
((fs)->cfg.phys_addr)
|
||||
#endif
|
||||
|
||||
// total number of pages
|
||||
#define SPIFFS_MAX_PAGES(fs) \
|
||||
( SPIFFS_CFG_PHYS_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// total number of pages per block, including object lookup pages
|
||||
#define SPIFFS_PAGES_PER_BLOCK(fs) \
|
||||
( SPIFFS_CFG_LOG_BLOCK_SZ(fs)/SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// number of object lookup pages per block
|
||||
#define SPIFFS_OBJ_LOOKUP_PAGES(fs) \
|
||||
(MAX(1, (SPIFFS_PAGES_PER_BLOCK(fs) * sizeof(spiffs_obj_id)) / SPIFFS_CFG_LOG_PAGE_SZ(fs)) )
|
||||
// checks if page index belongs to object lookup
|
||||
#define SPIFFS_IS_LOOKUP_PAGE(fs,pix) \
|
||||
(((pix) % SPIFFS_PAGES_PER_BLOCK(fs)) < SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// number of object lookup entries in all object lookup pages
|
||||
#define SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) \
|
||||
(SPIFFS_PAGES_PER_BLOCK(fs)-SPIFFS_OBJ_LOOKUP_PAGES(fs))
|
||||
// converts a block to physical address
|
||||
#define SPIFFS_BLOCK_TO_PADDR(fs, block) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (block)* SPIFFS_CFG_LOG_BLOCK_SZ(fs) )
|
||||
// converts a object lookup entry to page index
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PIX(fs, block, entry) \
|
||||
((block)*SPIFFS_PAGES_PER_BLOCK(fs) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry))
|
||||
// converts a object lookup entry to physical address of corresponding page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_TO_PADDR(fs, block, entry) \
|
||||
(SPIFFS_BLOCK_TO_PADDR(fs, block) + (SPIFFS_OBJ_LOOKUP_PAGES(fs) + entry) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a page to physical address
|
||||
#define SPIFFS_PAGE_TO_PADDR(fs, page) \
|
||||
( SPIFFS_CFG_PHYS_ADDR(fs) + (page) * SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// converts a physical address to page
|
||||
#define SPIFFS_PADDR_TO_PAGE(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) / SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// gives index in page for a physical address
|
||||
#define SPIFFS_PADDR_TO_PAGE_OFFSET(fs, addr) \
|
||||
( ((addr) - SPIFFS_CFG_PHYS_ADDR(fs)) % SPIFFS_CFG_LOG_PAGE_SZ(fs) )
|
||||
// returns containing block for given page
|
||||
#define SPIFFS_BLOCK_FOR_PAGE(fs, page) \
|
||||
( (page) / SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// returns starting page for block
|
||||
#define SPIFFS_PAGE_FOR_BLOCK(fs, block) \
|
||||
( (block) * SPIFFS_PAGES_PER_BLOCK(fs) )
|
||||
// converts page to entry in object lookup page
|
||||
#define SPIFFS_OBJ_LOOKUP_ENTRY_FOR_PAGE(fs, page) \
|
||||
( (page) % SPIFFS_PAGES_PER_BLOCK(fs) - SPIFFS_OBJ_LOOKUP_PAGES(fs) )
|
||||
// returns data size in a data page
|
||||
#define SPIFFS_DATA_PAGE_SIZE(fs) \
|
||||
( SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_header) )
|
||||
// returns physical address for block's erase count,
|
||||
// always in the physical last entry of the last object lookup page
|
||||
#define SPIFFS_ERASE_COUNT_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id) )
|
||||
// returns physical address for block's magic,
|
||||
// always in the physical second last entry of the last object lookup page
|
||||
#define SPIFFS_MAGIC_PADDR(fs, bix) \
|
||||
( SPIFFS_BLOCK_TO_PADDR(fs, bix) + SPIFFS_OBJ_LOOKUP_PAGES(fs) * SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_obj_id)*2 )
|
||||
// checks if there is any room for magic in the object luts
|
||||
#define SPIFFS_CHECK_MAGIC_POSSIBLE(fs) \
|
||||
( (SPIFFS_OBJ_LOOKUP_MAX_ENTRIES(fs) % (SPIFFS_CFG_LOG_PAGE_SZ(fs)/sizeof(spiffs_obj_id))) * sizeof(spiffs_obj_id) \
|
||||
<= (SPIFFS_CFG_LOG_PAGE_SZ(fs)-sizeof(spiffs_obj_id)*2) )
|
||||
|
||||
// define helpers object
|
||||
|
||||
// entries in an object header page index
|
||||
#define SPIFFS_OBJ_HDR_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix_header))/sizeof(spiffs_page_ix))
|
||||
// entries in an object page index
|
||||
#define SPIFFS_OBJ_IX_LEN(fs) \
|
||||
((SPIFFS_CFG_LOG_PAGE_SZ(fs) - sizeof(spiffs_page_object_ix))/sizeof(spiffs_page_ix))
|
||||
// object index entry for given data span index
|
||||
#define SPIFFS_OBJ_IX_ENTRY(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? (spix) : (((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))%SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// object index span index number for given data span index or entry
|
||||
#define SPIFFS_OBJ_IX_ENTRY_SPAN_IX(fs, spix) \
|
||||
((spix) < SPIFFS_OBJ_HDR_IX_LEN(fs) ? 0 : (1+((spix)-SPIFFS_OBJ_HDR_IX_LEN(fs))/SPIFFS_OBJ_IX_LEN(fs)))
|
||||
// get data span index for object index span index
|
||||
#define SPIFFS_DATA_SPAN_IX_FOR_OBJ_IX_SPAN_IX(fs, spix) \
|
||||
( (spix) == 0 ? 0 : (SPIFFS_OBJ_HDR_IX_LEN(fs) + (((spix)-1) * SPIFFS_OBJ_IX_LEN(fs))) )
|
||||
|
||||
#define SPIFFS_OP_T_OBJ_LU (0<<0)
|
||||
#define SPIFFS_OP_T_OBJ_LU2 (1<<0)
|
||||
#define SPIFFS_OP_T_OBJ_IX (2<<0)
|
||||
#define SPIFFS_OP_T_OBJ_DA (3<<0)
|
||||
#define SPIFFS_OP_C_DELE (0<<2)
|
||||
#define SPIFFS_OP_C_UPDT (1<<2)
|
||||
#define SPIFFS_OP_C_MOVS (2<<2)
|
||||
#define SPIFFS_OP_C_MOVD (3<<2)
|
||||
#define SPIFFS_OP_C_FLSH (4<<2)
|
||||
#define SPIFFS_OP_C_READ (5<<2)
|
||||
#define SPIFFS_OP_C_WRTHRU (6<<2)
|
||||
|
||||
#define SPIFFS_OP_TYPE_MASK (3<<0)
|
||||
#define SPIFFS_OP_COM_MASK (7<<2)
|
||||
|
||||
|
||||
// if 0, this page is written to, else clean
|
||||
#define SPIFFS_PH_FLAG_USED (1<<0)
|
||||
// if 0, writing is finalized, else under modification
|
||||
#define SPIFFS_PH_FLAG_FINAL (1<<1)
|
||||
// if 0, this is an index page, else a data page
|
||||
#define SPIFFS_PH_FLAG_INDEX (1<<2)
|
||||
// if 0, page is deleted, else valid
|
||||
#define SPIFFS_PH_FLAG_DELET (1<<7)
|
||||
// if 0, this index header is being deleted
|
||||
#define SPIFFS_PH_FLAG_IXDELE (1<<6)
|
||||
|
||||
|
||||
#define SPIFFS_CHECK_MOUNT(fs) \
|
||||
((fs)->mounted != 0)
|
||||
|
||||
#define SPIFFS_CHECK_CFG(fs) \
|
||||
((fs)->config_magic == SPIFFS_CONFIG_MAGIC)
|
||||
|
||||
#define SPIFFS_CHECK_RES(res) \
|
||||
do { \
|
||||
if ((res) < SPIFFS_OK) return (res); \
|
||||
} while (0);
|
||||
|
||||
#define SPIFFS_API_CHECK_MOUNT(fs) \
|
||||
if (!SPIFFS_CHECK_MOUNT((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_MOUNTED; \
|
||||
return SPIFFS_ERR_NOT_MOUNTED; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_CFG(fs) \
|
||||
if (!SPIFFS_CHECK_CFG((fs))) { \
|
||||
(fs)->err_code = SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
return SPIFFS_ERR_NOT_CONFIGURED; \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
return (res); \
|
||||
}
|
||||
|
||||
#define SPIFFS_API_CHECK_RES_UNLOCK(fs, res) \
|
||||
if ((res) < SPIFFS_OK) { \
|
||||
(fs)->err_code = (res); \
|
||||
SPIFFS_UNLOCK(fs); \
|
||||
return (res); \
|
||||
}
|
||||
|
||||
#define SPIFFS_VALIDATE_OBJIX(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) != 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if (((objid) & SPIFFS_OBJ_ID_IX_FLAG) == 0) return SPIFFS_ERR_NOT_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_INDEX_SPAN_MISMATCH;
|
||||
//if ((spix) == 0 && ((ph).flags & SPIFFS_PH_FLAG_IXDELE) == 0) return SPIFFS_ERR_DELETED;
|
||||
|
||||
#define SPIFFS_VALIDATE_DATA(ph, objid, spix) \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_USED) != 0) return SPIFFS_ERR_IS_FREE; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_DELET) == 0) return SPIFFS_ERR_DELETED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_FINAL) != 0) return SPIFFS_ERR_NOT_FINALIZED; \
|
||||
if (((ph).flags & SPIFFS_PH_FLAG_INDEX) == 0) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((objid) & SPIFFS_OBJ_ID_IX_FLAG) return SPIFFS_ERR_IS_INDEX; \
|
||||
if ((ph).span_ix != (spix)) return SPIFFS_ERR_DATA_SPAN_MISMATCH;
|
||||
|
||||
|
||||
// check id, only visit matching objec ids
|
||||
#define SPIFFS_VIS_CHECK_ID (1<<0)
|
||||
// report argument object id to visitor - else object lookup id is reported
|
||||
#define SPIFFS_VIS_CHECK_PH (1<<1)
|
||||
// stop searching at end of all look up pages
|
||||
#define SPIFFS_VIS_NO_WRAP (1<<2)
|
||||
|
||||
#if SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_fs), (_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_fs), (_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_fs), (_paddr), (_len))
|
||||
|
||||
#else // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#define SPIFFS_HAL_WRITE(_fs, _paddr, _len, _src) \
|
||||
(_fs)->cfg.hal_write_f((_paddr), (_len), (_src))
|
||||
#define SPIFFS_HAL_READ(_fs, _paddr, _len, _dst) \
|
||||
(_fs)->cfg.hal_read_f((_paddr), (_len), (_dst))
|
||||
#define SPIFFS_HAL_ERASE(_fs, _paddr, _len) \
|
||||
(_fs)->cfg.hal_erase_f((_paddr), (_len))
|
||||
|
||||
#endif // SPIFFS_HAL_CALLBACK_EXTRA
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
|
||||
#define SPIFFS_CACHE_FLAG_DIRTY (1<<0)
|
||||
#define SPIFFS_CACHE_FLAG_WRTHRU (1<<1)
|
||||
#define SPIFFS_CACHE_FLAG_OBJLU (1<<2)
|
||||
#define SPIFFS_CACHE_FLAG_OBJIX (1<<3)
|
||||
#define SPIFFS_CACHE_FLAG_DATA (1<<4)
|
||||
#define SPIFFS_CACHE_FLAG_TYPE_WR (1<<7)
|
||||
|
||||
#define SPIFFS_CACHE_PAGE_SIZE(fs) \
|
||||
(sizeof(spiffs_cache_page) + SPIFFS_CFG_LOG_PAGE_SZ(fs))
|
||||
|
||||
#define spiffs_get_cache(fs) \
|
||||
((spiffs_cache *)((fs)->cache))
|
||||
|
||||
#define spiffs_get_cache_page_hdr(fs, c, ix) \
|
||||
((spiffs_cache_page *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])))
|
||||
|
||||
#define spiffs_get_cache_page(fs, c, ix) \
|
||||
((u8_t *)(&((c)->cpages[(ix) * SPIFFS_CACHE_PAGE_SIZE(fs)])) + sizeof(spiffs_cache_page))
|
||||
|
||||
// cache page struct
|
||||
typedef struct {
|
||||
// cache flags
|
||||
u8_t flags;
|
||||
// cache page index
|
||||
u8_t ix;
|
||||
// last access of this cache page
|
||||
u32_t last_access;
|
||||
union {
|
||||
// type read cache
|
||||
struct {
|
||||
// read cache page index
|
||||
spiffs_page_ix pix;
|
||||
};
|
||||
#if SPIFFS_CACHE_WR
|
||||
// type write cache
|
||||
struct {
|
||||
// write cache
|
||||
spiffs_obj_id obj_id;
|
||||
// offset in cache page
|
||||
u32_t offset;
|
||||
// size of cache page
|
||||
u16_t size;
|
||||
};
|
||||
#endif
|
||||
};
|
||||
} spiffs_cache_page;
|
||||
|
||||
// cache struct
|
||||
typedef struct {
|
||||
u8_t cpage_count;
|
||||
u32_t last_access;
|
||||
u32_t cpage_use_map;
|
||||
u32_t cpage_use_mask;
|
||||
u8_t *cpages;
|
||||
} spiffs_cache;
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
// spiffs nucleus file descriptor
|
||||
typedef struct {
|
||||
// the filesystem of this descriptor
|
||||
spiffs *fs;
|
||||
// number of file descriptor - if 0, the file descriptor is closed
|
||||
spiffs_file file_nbr;
|
||||
// object id - if SPIFFS_OBJ_ID_ERASED, the file was deleted
|
||||
spiffs_obj_id obj_id;
|
||||
// size of the file
|
||||
u32_t size;
|
||||
// cached object index header page index
|
||||
spiffs_page_ix objix_hdr_pix;
|
||||
// cached offset object index page index
|
||||
spiffs_page_ix cursor_objix_pix;
|
||||
// cached offset object index span index
|
||||
spiffs_span_ix cursor_objix_spix;
|
||||
// current absolute offset
|
||||
u32_t offset;
|
||||
// current file descriptor offset
|
||||
u32_t fdoffset;
|
||||
// fd flags
|
||||
spiffs_flags flags;
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *cache_page;
|
||||
#endif
|
||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||
// djb2 hash of filename
|
||||
u32_t name_hash;
|
||||
// hit score (score == 0 indicates never used fd)
|
||||
u16_t score;
|
||||
#endif
|
||||
#if SPIFFS_IX_MAP
|
||||
// spiffs index map, if 0 it means unmapped
|
||||
spiffs_ix_map *ix_map;
|
||||
#endif
|
||||
} spiffs_fd;
|
||||
|
||||
|
||||
// object structs
|
||||
|
||||
// page header, part of each page except object lookup pages
|
||||
// NB: this is always aligned when the data page is an object index,
|
||||
// as in this case struct spiffs_page_object_ix is used
|
||||
typedef struct __attribute(( packed )) {
|
||||
// object id
|
||||
spiffs_obj_id obj_id;
|
||||
// object span index
|
||||
spiffs_span_ix span_ix;
|
||||
// flags
|
||||
u8_t flags;
|
||||
} spiffs_page_header;
|
||||
|
||||
// object index header page header
|
||||
typedef struct __attribute(( packed ))
|
||||
#if SPIFFS_ALIGNED_OBJECT_INDEX_TABLES
|
||||
__attribute(( aligned(sizeof(spiffs_page_ix)) ))
|
||||
#endif
|
||||
{
|
||||
// common page header
|
||||
spiffs_page_header p_hdr;
|
||||
// alignment
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
// size of object
|
||||
u32_t size;
|
||||
// type of object
|
||||
spiffs_obj_type type;
|
||||
// name of object
|
||||
u8_t name[SPIFFS_OBJ_NAME_LEN];
|
||||
#if SPIFFS_OBJ_META_LEN
|
||||
// metadata. not interpreted by SPIFFS in any way.
|
||||
u8_t meta[SPIFFS_OBJ_META_LEN];
|
||||
#endif
|
||||
} spiffs_page_object_ix_header;
|
||||
|
||||
// object index page header
|
||||
typedef struct __attribute(( packed )) {
|
||||
spiffs_page_header p_hdr;
|
||||
u8_t _align[4 - ((sizeof(spiffs_page_header)&3)==0 ? 4 : (sizeof(spiffs_page_header)&3))];
|
||||
} spiffs_page_object_ix;
|
||||
|
||||
// callback func for object lookup visitor
|
||||
typedef s32_t (*spiffs_visitor_f)(spiffs *fs, spiffs_obj_id id, spiffs_block_ix bix, int ix_entry,
|
||||
const void *user_const_p, void *user_var_p);
|
||||
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (op), (fh), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (op), (fh), (addr), (len), (src))
|
||||
#else
|
||||
#define _spiffs_rd(fs, op, fh, addr, len, dst) \
|
||||
spiffs_phys_rd((fs), (addr), (len), (dst))
|
||||
#define _spiffs_wr(fs, op, fh, addr, len, src) \
|
||||
spiffs_phys_wr((fs), (addr), (len), (src))
|
||||
#endif
|
||||
|
||||
#ifndef MIN
|
||||
#define MIN(a,b) ((a) < (b) ? (a) : (b))
|
||||
#endif
|
||||
#ifndef MAX
|
||||
#define MAX(a,b) ((a) > (b) ? (a) : (b))
|
||||
#endif
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_phys_rd(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_phys_wr(
|
||||
spiffs *fs,
|
||||
#if SPIFFS_CACHE
|
||||
u8_t op,
|
||||
spiffs_file fh,
|
||||
#endif
|
||||
u32_t addr,
|
||||
u32_t len,
|
||||
u8_t *src);
|
||||
|
||||
s32_t spiffs_phys_cpy(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u32_t dst,
|
||||
u32_t src,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_phys_count_free_blocks(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_entry_visitor(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
u8_t flags,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_visitor_f v,
|
||||
const void *user_const_p,
|
||||
void *user_var_p,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_erase_block(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
#if SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
s32_t spiffs_probe(
|
||||
spiffs_config *cfg);
|
||||
#endif // SPIFFS_USE_MAGIC && SPIFFS_USE_MAGIC_LENGTH
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_obj_lu_scan(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free_obj_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id *obj_id,
|
||||
const u8_t *conflicting_name);
|
||||
|
||||
s32_t spiffs_obj_lu_find_free(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix starting_block,
|
||||
int starting_lu_entry,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_block_ix *block_ix,
|
||||
int *lu_entry);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_obj_lu_find_id_and_span_by_phdr(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix exclusion_pix,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_page_allocate_data(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *ph,
|
||||
u8_t *data,
|
||||
u32_t len,
|
||||
u32_t page_offs,
|
||||
u8_t finalize,
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
s32_t spiffs_page_move(
|
||||
spiffs *fs,
|
||||
spiffs_file fh,
|
||||
u8_t *page_data,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_header *page_hdr,
|
||||
spiffs_page_ix src_pix,
|
||||
spiffs_page_ix *dst_pix);
|
||||
|
||||
s32_t spiffs_page_delete(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_object_create(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
const u8_t name[],
|
||||
const u8_t meta[],
|
||||
spiffs_obj_type type,
|
||||
spiffs_page_ix *objix_hdr_pix);
|
||||
|
||||
s32_t spiffs_object_update_index_hdr(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_page_ix objix_hdr_pix,
|
||||
u8_t *new_objix_hdr_data,
|
||||
const u8_t name[],
|
||||
const u8_t meta[],
|
||||
u32_t size,
|
||||
spiffs_page_ix *new_pix);
|
||||
|
||||
#if SPIFFS_IX_MAP
|
||||
|
||||
s32_t spiffs_populate_ix_map(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd,
|
||||
u32_t vec_entry_start,
|
||||
u32_t vec_entry_end);
|
||||
|
||||
#endif
|
||||
|
||||
void spiffs_cb_object_event(
|
||||
spiffs *fs,
|
||||
spiffs_page_object_ix *objix,
|
||||
int ev,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_span_ix spix,
|
||||
spiffs_page_ix new_pix,
|
||||
u32_t new_size);
|
||||
|
||||
s32_t spiffs_object_open_by_id(
|
||||
spiffs *fs,
|
||||
spiffs_obj_id obj_id,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_open_by_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix,
|
||||
spiffs_fd *f,
|
||||
spiffs_flags flags,
|
||||
spiffs_mode mode);
|
||||
|
||||
s32_t spiffs_object_append(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_modify(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u8_t *data,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_object_read(
|
||||
spiffs_fd *fd,
|
||||
u32_t offset,
|
||||
u32_t len,
|
||||
u8_t *dst);
|
||||
|
||||
s32_t spiffs_object_truncate(
|
||||
spiffs_fd *fd,
|
||||
u32_t new_len,
|
||||
u8_t remove_object);
|
||||
|
||||
s32_t spiffs_object_find_object_index_header_by_name(
|
||||
spiffs *fs,
|
||||
const u8_t name[SPIFFS_OBJ_NAME_LEN],
|
||||
spiffs_page_ix *pix);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_gc_check(
|
||||
spiffs *fs,
|
||||
u32_t len);
|
||||
|
||||
s32_t spiffs_gc_erase_page_stats(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_find_candidate(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix **block_candidate,
|
||||
int *candidate_count,
|
||||
char fs_crammed);
|
||||
|
||||
s32_t spiffs_gc_clean(
|
||||
spiffs *fs,
|
||||
spiffs_block_ix bix);
|
||||
|
||||
s32_t spiffs_gc_quick(
|
||||
spiffs *fs, u16_t max_free_pages);
|
||||
|
||||
// ---------------
|
||||
|
||||
s32_t spiffs_fd_find_new(
|
||||
spiffs *fs,
|
||||
spiffs_fd **fd,
|
||||
const char *name);
|
||||
|
||||
s32_t spiffs_fd_return(
|
||||
spiffs *fs,
|
||||
spiffs_file f);
|
||||
|
||||
s32_t spiffs_fd_get(
|
||||
spiffs *fs,
|
||||
spiffs_file f,
|
||||
spiffs_fd **fd);
|
||||
|
||||
#if SPIFFS_TEMPORAL_FD_CACHE
|
||||
void spiffs_fd_temporal_cache_rehash(
|
||||
spiffs *fs,
|
||||
const char *old_path,
|
||||
const char *new_path);
|
||||
#endif
|
||||
|
||||
#if SPIFFS_CACHE
|
||||
void spiffs_cache_init(
|
||||
spiffs *fs);
|
||||
|
||||
void spiffs_cache_drop_page(
|
||||
spiffs *fs,
|
||||
spiffs_page_ix pix);
|
||||
|
||||
#if SPIFFS_CACHE_WR
|
||||
spiffs_cache_page *spiffs_cache_page_allocate_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
|
||||
void spiffs_cache_fd_release(
|
||||
spiffs *fs,
|
||||
spiffs_cache_page *cp);
|
||||
|
||||
spiffs_cache_page *spiffs_cache_page_get_by_fd(
|
||||
spiffs *fs,
|
||||
spiffs_fd *fd);
|
||||
#endif
|
||||
#endif
|
||||
|
||||
s32_t spiffs_lookup_consistency_check(
|
||||
spiffs *fs,
|
||||
u8_t check_all_objects);
|
||||
|
||||
s32_t spiffs_page_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
s32_t spiffs_object_index_consistency_check(
|
||||
spiffs *fs);
|
||||
|
||||
#endif /* SPIFFS_NUCLEUS_H_ */
|
878
components/spiffs/spiffs_vfs.c
Normal file
878
components/spiffs/spiffs_vfs.c
Normal file
@ -0,0 +1,878 @@
|
||||
/*
|
||||
* spiffs VFS operations
|
||||
*
|
||||
* Author: LoBo (loboris@gmail.com / https://github.com/loboris)
|
||||
*
|
||||
* Part of this code is copied from or inspired by LUA-RTOS_ESP32 project:
|
||||
*
|
||||
* https://github.com/whitecatboard/Lua-RTOS-ESP32
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
* Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#include <freertos/FreeRTOS.h>
|
||||
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
#include "esp_log.h"
|
||||
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "esp_vfs.h"
|
||||
#include "esp_attr.h"
|
||||
#include <errno.h>
|
||||
|
||||
#include <spiffs_vfs.h>
|
||||
#include <spiffs.h>
|
||||
#include <esp_spiffs.h>
|
||||
#include <spiffs_nucleus.h>
|
||||
#include "list.h"
|
||||
#include <sys/fcntl.h>
|
||||
#include <sys/dirent.h>
|
||||
#include "sdkconfig.h"
|
||||
|
||||
|
||||
#ifdef PATH_MAX
|
||||
#undef PATH_MAX
|
||||
#endif
|
||||
#define PATH_MAX MAXNAMLEN+8
|
||||
|
||||
#define SPIFFS_ERASE_SIZE 4096
|
||||
|
||||
int spiffs_is_registered = 0;
|
||||
int spiffs_is_mounted = 0;
|
||||
|
||||
QueueHandle_t spiffs_mutex = NULL;
|
||||
|
||||
static int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode);
|
||||
static ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size);
|
||||
static ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size);
|
||||
static int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st);
|
||||
static int IRAM_ATTR vfs_spiffs_close(int fd);
|
||||
static off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode);
|
||||
|
||||
typedef struct {
|
||||
DIR dir;
|
||||
spiffs_DIR spiffs_dir;
|
||||
char path[MAXNAMLEN + 1];
|
||||
struct dirent ent;
|
||||
uint8_t read_mount;
|
||||
} vfs_spiffs_dir_t;
|
||||
|
||||
typedef struct {
|
||||
spiffs_file spiffs_file;
|
||||
char path[MAXNAMLEN + 1];
|
||||
uint8_t is_dir;
|
||||
} vfs_spiffs_file_t;
|
||||
|
||||
typedef struct {
|
||||
time_t mtime;
|
||||
time_t ctime;
|
||||
time_t atime;
|
||||
uint8_t spare[SPIFFS_OBJ_META_LEN - (sizeof(time_t)*3)];
|
||||
} spiffs_metadata_t;
|
||||
|
||||
static spiffs fs;
|
||||
static struct list files;
|
||||
|
||||
static u8_t *my_spiffs_work_buf;
|
||||
static u8_t *my_spiffs_fds;
|
||||
static u8_t *my_spiffs_cache;
|
||||
|
||||
|
||||
/*
|
||||
* ########################################
|
||||
* file names/paths passed to the functions
|
||||
* do not contain '/spiffs' prefix
|
||||
* ########################################
|
||||
*/
|
||||
|
||||
//----------------------------------------------------
|
||||
void spiffs_fs_stat(uint32_t *total, uint32_t *used) {
|
||||
if (SPIFFS_info(&fs, total, used) != SPIFFS_OK) {
|
||||
*total = 0;
|
||||
*used = 0;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Test if path corresponds to a directory. Return 0 if is not a directory,
|
||||
* 1 if it's a directory.
|
||||
*
|
||||
*/
|
||||
//-----------------------------------
|
||||
static int is_dir(const char *path) {
|
||||
spiffs_DIR d;
|
||||
char npath[PATH_MAX + 1];
|
||||
int res = 0;
|
||||
|
||||
struct spiffs_dirent e;
|
||||
|
||||
// Add /. to path
|
||||
strlcpy(npath, path, PATH_MAX);
|
||||
if (strcmp(path,"/") != 0) {
|
||||
strlcat(npath,"/.", PATH_MAX);
|
||||
} else {
|
||||
strlcat(npath,".", PATH_MAX);
|
||||
}
|
||||
|
||||
SPIFFS_opendir(&fs, "/", &d);
|
||||
while (SPIFFS_readdir(&d, &e)) {
|
||||
if (strncmp(npath, (const char *)e.name, strlen(npath)) == 0) {
|
||||
res = 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
SPIFFS_closedir(&d);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
/*
|
||||
* This function translate error codes from SPIFFS to errno error codes
|
||||
*
|
||||
*/
|
||||
//-------------------------------
|
||||
static int spiffs_result(int res) {
|
||||
switch (res) {
|
||||
case SPIFFS_OK:
|
||||
case SPIFFS_ERR_END_OF_OBJECT:
|
||||
return 0;
|
||||
|
||||
case SPIFFS_ERR_NOT_FOUND:
|
||||
case SPIFFS_ERR_CONFLICTING_NAME:
|
||||
return ENOENT;
|
||||
|
||||
case SPIFFS_ERR_NOT_WRITABLE:
|
||||
case SPIFFS_ERR_NOT_READABLE:
|
||||
return EACCES;
|
||||
|
||||
case SPIFFS_ERR_FILE_EXISTS:
|
||||
return EEXIST;
|
||||
|
||||
default:
|
||||
return res;
|
||||
}
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_getstat(spiffs_file fd, spiffs_stat *st, spiffs_metadata_t *metadata) {
|
||||
int res = SPIFFS_fstat(&fs, fd, st);
|
||||
if (res == SPIFFS_OK) {
|
||||
// Get file's time information from metadata
|
||||
memcpy(metadata, st->meta, sizeof(spiffs_metadata_t));
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// ## path does not contain '/spiffs' prefix !
|
||||
//---------------------------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_open(const char *path, int flags, int mode) {
|
||||
int fd, result = 0, exists = 0;
|
||||
spiffs_stat stat;
|
||||
spiffs_metadata_t meta;
|
||||
|
||||
// Allocate new file
|
||||
vfs_spiffs_file_t *file = calloc(1, sizeof(vfs_spiffs_file_t));
|
||||
if (!file) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Add file to file list. List index is file descriptor.
|
||||
int res = list_add(&files, file, &fd);
|
||||
if (res) {
|
||||
free(file);
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Check if file exists
|
||||
if (SPIFFS_stat(&fs, path, &stat) == SPIFFS_OK) exists = 1;
|
||||
|
||||
// Make a copy of path
|
||||
strlcpy(file->path, path, MAXNAMLEN);
|
||||
|
||||
// Open file
|
||||
spiffs_flags spiffs_mode = 0;
|
||||
|
||||
// Translate flags to SPIFFS flags
|
||||
if (flags == O_RDONLY)
|
||||
spiffs_mode |= SPIFFS_RDONLY;
|
||||
|
||||
if (flags & O_WRONLY)
|
||||
spiffs_mode |= SPIFFS_WRONLY;
|
||||
|
||||
if (flags & O_RDWR)
|
||||
spiffs_mode = SPIFFS_RDWR;
|
||||
|
||||
if (flags & O_EXCL)
|
||||
spiffs_mode |= SPIFFS_EXCL;
|
||||
|
||||
if (flags & O_CREAT)
|
||||
spiffs_mode |= SPIFFS_CREAT;
|
||||
|
||||
if (flags & O_TRUNC)
|
||||
spiffs_mode |= SPIFFS_TRUNC;
|
||||
|
||||
if (is_dir(path)) {
|
||||
char npath[PATH_MAX + 1];
|
||||
|
||||
// Add /. to path
|
||||
strlcpy(npath, path, PATH_MAX);
|
||||
if (strcmp(path,"/") != 0) {
|
||||
strlcat(npath,"/.", PATH_MAX);
|
||||
} else {
|
||||
strlcat(npath,".", PATH_MAX);
|
||||
}
|
||||
|
||||
// Open SPIFFS file
|
||||
file->spiffs_file = SPIFFS_open(&fs, npath, spiffs_mode, 0);
|
||||
if (file->spiffs_file < 0) {
|
||||
result = spiffs_result(fs.err_code);
|
||||
}
|
||||
|
||||
file->is_dir = 1;
|
||||
} else {
|
||||
// Open SPIFFS file
|
||||
file->spiffs_file = SPIFFS_open(&fs, path, spiffs_mode, 0);
|
||||
if (file->spiffs_file < 0) {
|
||||
result = spiffs_result(fs.err_code);
|
||||
}
|
||||
}
|
||||
|
||||
if (result != 0) {
|
||||
list_remove(&files, fd, 1);
|
||||
errno = result;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);
|
||||
if (res == SPIFFS_OK) {
|
||||
// update file's time information
|
||||
meta.atime = time(NULL); // Get the system time to access time
|
||||
if (!exists) meta.ctime = meta.atime;
|
||||
if (spiffs_mode != SPIFFS_RDONLY) meta.mtime = meta.atime;
|
||||
SPIFFS_fupdate_meta(&fs, file->spiffs_file, &meta);
|
||||
}
|
||||
|
||||
return fd;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------------------
|
||||
static ssize_t IRAM_ATTR vfs_spiffs_write(int fd, const void *data, size_t size) {
|
||||
vfs_spiffs_file_t *file;
|
||||
int res;
|
||||
|
||||
res = list_get(&files, fd, (void **)&file);
|
||||
if (res) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file->is_dir) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Write SPIFFS file
|
||||
res = SPIFFS_write(&fs, file->spiffs_file, (void *)data, size);
|
||||
if (res >= 0) {
|
||||
return res;
|
||||
} else {
|
||||
res = spiffs_result(fs.err_code);
|
||||
if (res != 0) {
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static ssize_t IRAM_ATTR vfs_spiffs_read(int fd, void * dst, size_t size) {
|
||||
vfs_spiffs_file_t *file;
|
||||
int res;
|
||||
|
||||
res = list_get(&files, fd, (void **)&file);
|
||||
if (res) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file->is_dir) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Read SPIFFS file
|
||||
res = SPIFFS_read(&fs, file->spiffs_file, dst, size);
|
||||
if (res >= 0) {
|
||||
return res;
|
||||
} else {
|
||||
res = spiffs_result(fs.err_code);
|
||||
if (res != 0) {
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// EOF
|
||||
return 0;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_fstat(int fd, struct stat * st) {
|
||||
vfs_spiffs_file_t *file;
|
||||
spiffs_stat stat;
|
||||
int res;
|
||||
spiffs_metadata_t meta;
|
||||
|
||||
res = list_get(&files, fd, (void **)&file);
|
||||
if (res) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Set block size for this file system
|
||||
st->st_blksize = CONFIG_SPIFFS_LOG_PAGE_SIZE;
|
||||
|
||||
// Get file/directory statistics
|
||||
res = vfs_spiffs_getstat(file->spiffs_file, &stat, &meta);
|
||||
if (res == SPIFFS_OK) {
|
||||
// Set file's time information from metadata
|
||||
st->st_mtime = meta.mtime;
|
||||
st->st_ctime = meta.ctime;
|
||||
st->st_atime = meta.atime;
|
||||
|
||||
st->st_size = stat.size;
|
||||
|
||||
} else {
|
||||
st->st_mtime = 0;
|
||||
st->st_ctime = 0;
|
||||
st->st_atime = 0;
|
||||
st->st_size = 0;
|
||||
errno = spiffs_result(fs.err_code);
|
||||
//printf("SPIFFS_STAT: error %d\r\n", res);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Test if it's a directory entry
|
||||
if (file->is_dir) st->st_mode = S_IFDIR;
|
||||
else st->st_mode = S_IFREG;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_close(int fd) {
|
||||
vfs_spiffs_file_t *file;
|
||||
int res;
|
||||
|
||||
res = list_get(&files, fd, (void **)&file);
|
||||
if (res) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = SPIFFS_close(&fs, file->spiffs_file);
|
||||
if (res) {
|
||||
res = spiffs_result(fs.err_code);
|
||||
}
|
||||
|
||||
if (res < 0) {
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
list_remove(&files, fd, 1);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//---------------------------------------------------------------------
|
||||
static off_t IRAM_ATTR vfs_spiffs_lseek(int fd, off_t size, int mode) {
|
||||
vfs_spiffs_file_t *file;
|
||||
int res;
|
||||
|
||||
res = list_get(&files, fd, (void **)&file);
|
||||
if (res) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (file->is_dir) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int whence = SPIFFS_SEEK_CUR;
|
||||
|
||||
switch (mode) {
|
||||
case SEEK_SET: whence = SPIFFS_SEEK_SET;break;
|
||||
case SEEK_CUR: whence = SPIFFS_SEEK_CUR;break;
|
||||
case SEEK_END: whence = SPIFFS_SEEK_END;break;
|
||||
}
|
||||
|
||||
res = SPIFFS_lseek(&fs, file->spiffs_file, size, whence);
|
||||
if (res < 0) {
|
||||
res = spiffs_result(fs.err_code);
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_stat(const char * path, struct stat * st) {
|
||||
int fd;
|
||||
int res;
|
||||
fd = vfs_spiffs_open(path, 0, 0);
|
||||
res = vfs_spiffs_fstat(fd, st);
|
||||
vfs_spiffs_close(fd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_unlink(const char *path) {
|
||||
char npath[PATH_MAX + 1];
|
||||
|
||||
strlcpy(npath, path, PATH_MAX);
|
||||
|
||||
if (is_dir(path)) {
|
||||
// Check if directory is empty
|
||||
int nument = 0;
|
||||
sprintf(npath, "/spiffs");
|
||||
strlcat(npath, path, PATH_MAX);
|
||||
|
||||
DIR *dir = opendir(npath);
|
||||
if (dir) {
|
||||
struct dirent *ent;
|
||||
// Read directory entries
|
||||
while ((ent = readdir(dir)) != NULL) {
|
||||
nument++;
|
||||
}
|
||||
}
|
||||
else {
|
||||
errno = ENOTEMPTY;
|
||||
return -1;
|
||||
}
|
||||
closedir(dir);
|
||||
|
||||
if (nument > 0) {
|
||||
// Directory not empty, cannot remove
|
||||
errno = ENOTEMPTY;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strlcpy(npath, path, PATH_MAX);
|
||||
// Add /. to path
|
||||
if (strcmp(path,"/") != 0) {
|
||||
strlcat(npath,"/.", PATH_MAX);
|
||||
}
|
||||
}
|
||||
|
||||
// Open SPIFFS file
|
||||
spiffs_file FP = SPIFFS_open(&fs, npath, SPIFFS_RDWR, 0);
|
||||
if (FP < 0) {
|
||||
errno = spiffs_result(fs.err_code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Remove SPIFSS file
|
||||
if (SPIFFS_fremove(&fs, FP) < 0) {
|
||||
errno = spiffs_result(fs.err_code);
|
||||
SPIFFS_close(&fs, FP);
|
||||
return -1;
|
||||
}
|
||||
|
||||
SPIFFS_close(&fs, FP);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_rename(const char *src, const char *dst) {
|
||||
if (SPIFFS_rename(&fs, src, dst) < 0) {
|
||||
errno = spiffs_result(fs.err_code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------
|
||||
static DIR* vfs_spiffs_opendir(const char* name) {
|
||||
struct stat st;
|
||||
|
||||
if (strcmp(name, "/") != 0) {
|
||||
// Not on root
|
||||
if (vfs_spiffs_stat(name, &st)) {
|
||||
// Not found
|
||||
errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
if (!S_ISDIR(st.st_mode)) {
|
||||
// Not a directory
|
||||
errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
vfs_spiffs_dir_t *dir = calloc(1, sizeof(vfs_spiffs_dir_t));
|
||||
|
||||
if (!dir) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (!SPIFFS_opendir(&fs, name, &dir->spiffs_dir)) {
|
||||
free(dir);
|
||||
errno = spiffs_result(fs.err_code);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
strlcpy(dir->path, name, MAXNAMLEN);
|
||||
|
||||
return (DIR *)dir;
|
||||
}
|
||||
|
||||
//---------------------------------------------------
|
||||
static struct dirent* vfs_spiffs_readdir(DIR* pdir) {
|
||||
int res = 0, len = 0, entries = 0;
|
||||
vfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;
|
||||
|
||||
struct spiffs_dirent e;
|
||||
struct spiffs_dirent *pe = &e;
|
||||
|
||||
struct dirent *ent = &dir->ent;
|
||||
|
||||
char *fn;
|
||||
|
||||
// Clear current dirent
|
||||
memset(ent,0,sizeof(struct dirent));
|
||||
|
||||
// If this is the first call to readdir for pdir, and
|
||||
// directory is the root path, return the mounted point if any
|
||||
if (!dir->read_mount) {
|
||||
if (strcmp(dir->path,"/") == 0) {
|
||||
strlcpy(ent->d_name, "/spiffs", PATH_MAX);
|
||||
ent->d_type = DT_DIR;
|
||||
dir->read_mount = 1;
|
||||
|
||||
return ent;
|
||||
}
|
||||
|
||||
dir->read_mount = 1;
|
||||
}
|
||||
|
||||
// Search for next entry
|
||||
for(;;) {
|
||||
// Read directory
|
||||
pe = SPIFFS_readdir(&dir->spiffs_dir, pe);
|
||||
if (!pe) {
|
||||
res = spiffs_result(fs.err_code);
|
||||
errno = res;
|
||||
break;
|
||||
}
|
||||
|
||||
// Break condition
|
||||
if (pe->name[0] == 0) break;
|
||||
|
||||
// Get name and length
|
||||
fn = (char *)pe->name;
|
||||
len = strlen(fn);
|
||||
|
||||
// Get entry type and size
|
||||
ent->d_type = DT_REG;
|
||||
|
||||
if (len >= 2) {
|
||||
if (fn[len - 1] == '.') {
|
||||
if (fn[len - 2] == '/') {
|
||||
ent->d_type = DT_DIR;
|
||||
|
||||
fn[len - 2] = '\0';
|
||||
|
||||
len = strlen(fn);
|
||||
|
||||
// Skip root dir
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip entries not belonged to path
|
||||
if (strncmp(fn, dir->path, strlen(dir->path)) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strlen(dir->path) > 1) {
|
||||
if (*(fn + strlen(dir->path)) != '/') {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip root directory
|
||||
fn = fn + strlen(dir->path);
|
||||
len = strlen(fn);
|
||||
if (len == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Skip initial /
|
||||
if (len > 1) {
|
||||
if (*fn == '/') {
|
||||
fn = fn + 1;
|
||||
len--;
|
||||
}
|
||||
}
|
||||
|
||||
// Skip subdirectories
|
||||
if (strchr(fn,'/')) {
|
||||
continue;
|
||||
}
|
||||
|
||||
//ent->d_fsize = pe->size;
|
||||
|
||||
strlcpy(ent->d_name, fn, MAXNAMLEN);
|
||||
|
||||
entries++;
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
if (entries > 0) {
|
||||
return ent;
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
//--------------------------------------------------
|
||||
static int IRAM_ATTR vfs_piffs_closedir(DIR* pdir) {
|
||||
vfs_spiffs_dir_t* dir = (vfs_spiffs_dir_t*) pdir;
|
||||
int res;
|
||||
|
||||
if (!pdir) {
|
||||
errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if ((res = SPIFFS_closedir(&dir->spiffs_dir)) < 0) {
|
||||
errno = spiffs_result(fs.err_code);;
|
||||
return -1;
|
||||
}
|
||||
|
||||
free(dir);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//--------------------------------------------------------------------
|
||||
static int IRAM_ATTR vfs_spiffs_mkdir(const char *path, mode_t mode) {
|
||||
char npath[PATH_MAX + 1];
|
||||
int res;
|
||||
|
||||
// Add /. to path
|
||||
strlcpy(npath, path, PATH_MAX);
|
||||
if ((strcmp(path,"/") != 0) && (strcmp(path,"/.") != 0)) {
|
||||
strlcat(npath,"/.", PATH_MAX);
|
||||
}
|
||||
|
||||
spiffs_file fd = SPIFFS_open(&fs, npath, SPIFFS_CREAT, 0);
|
||||
if (fd < 0) {
|
||||
res = spiffs_result(fs.err_code);
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (SPIFFS_close(&fs, fd) < 0) {
|
||||
res = spiffs_result(fs.err_code);
|
||||
errno = res;
|
||||
return -1;
|
||||
}
|
||||
|
||||
spiffs_metadata_t meta;
|
||||
meta.atime = time(NULL); // Get the system time to access time
|
||||
meta.ctime = meta.atime;
|
||||
meta.mtime = meta.atime;
|
||||
SPIFFS_update_meta(&fs, npath, &meta);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static const char tag[] = "[SPIFFS]";
|
||||
|
||||
//==================
|
||||
int spiffs_mount() {
|
||||
|
||||
if (!spiffs_is_registered) return 0;
|
||||
if (spiffs_is_mounted) return 1;
|
||||
|
||||
spiffs_config cfg;
|
||||
int res = 0;
|
||||
int retries = 0;
|
||||
int err = 0;
|
||||
|
||||
ESP_LOGI(tag, "Mounting SPIFFS files system");
|
||||
|
||||
cfg.phys_addr = CONFIG_SPIFFS_BASE_ADDR;
|
||||
cfg.phys_size = CONFIG_SPIFFS_SIZE;
|
||||
cfg.phys_erase_block = SPIFFS_ERASE_SIZE;
|
||||
cfg.log_page_size = CONFIG_SPIFFS_LOG_PAGE_SIZE;
|
||||
cfg.log_block_size = CONFIG_SPIFFS_LOG_BLOCK_SIZE;
|
||||
|
||||
cfg.hal_read_f = (spiffs_read)low_spiffs_read;
|
||||
cfg.hal_write_f = (spiffs_write)low_spiffs_write;
|
||||
cfg.hal_erase_f = (spiffs_erase)low_spiffs_erase;
|
||||
|
||||
my_spiffs_work_buf = malloc(cfg.log_page_size * 8);
|
||||
if (!my_spiffs_work_buf) {
|
||||
err = 1;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
int fds_len = sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
|
||||
my_spiffs_fds = malloc(fds_len);
|
||||
if (!my_spiffs_fds) {
|
||||
free(my_spiffs_work_buf);
|
||||
err = 2;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
int cache_len = cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE;
|
||||
my_spiffs_cache = malloc(cache_len);
|
||||
if (!my_spiffs_cache) {
|
||||
free(my_spiffs_work_buf);
|
||||
free(my_spiffs_fds);
|
||||
err = 3;
|
||||
goto err_exit;
|
||||
}
|
||||
|
||||
ESP_LOGI(tag, "Start address: 0x%x; Size %d KB", cfg.phys_addr, cfg.phys_size / 1024);
|
||||
ESP_LOGI(tag, " Work buffer: %d B", cfg.log_page_size * 8);
|
||||
ESP_LOGI(tag, " FDS buffer: %d B", sizeof(spiffs_fd) * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);
|
||||
ESP_LOGI(tag, " Cache size: %d B", cfg.log_page_size * SPIFFS_TEMPORAL_CACHE_HIT_SCORE);
|
||||
while (retries < 2) {
|
||||
res = SPIFFS_mount(
|
||||
&fs, &cfg, my_spiffs_work_buf, my_spiffs_fds,
|
||||
fds_len, my_spiffs_cache, cache_len, NULL
|
||||
);
|
||||
|
||||
if (res < 0) {
|
||||
if (fs.err_code == SPIFFS_ERR_NOT_A_FS) {
|
||||
ESP_LOGW(tag, "No file system detected, formating...");
|
||||
SPIFFS_unmount(&fs);
|
||||
res = SPIFFS_format(&fs);
|
||||
if (res < 0) {
|
||||
free(my_spiffs_work_buf);
|
||||
free(my_spiffs_fds);
|
||||
free(my_spiffs_cache);
|
||||
ESP_LOGE(tag, "Format error");
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(my_spiffs_work_buf);
|
||||
free(my_spiffs_fds);
|
||||
free(my_spiffs_cache);
|
||||
ESP_LOGE(tag, "Error mounting fs (%d)", res);
|
||||
goto exit;
|
||||
}
|
||||
}
|
||||
else break;
|
||||
retries++;
|
||||
}
|
||||
|
||||
if (retries > 1) {
|
||||
free(my_spiffs_work_buf);
|
||||
free(my_spiffs_fds);
|
||||
free(my_spiffs_cache);
|
||||
ESP_LOGE(tag, "Can't mount");
|
||||
goto exit;
|
||||
}
|
||||
|
||||
list_init(&files, 0);
|
||||
|
||||
ESP_LOGI(tag, "Mounted");
|
||||
|
||||
spiffs_is_mounted = 1;
|
||||
return 1;
|
||||
|
||||
err_exit:
|
||||
ESP_LOGE(tag, "Error allocating fs structures (%d)", err);
|
||||
exit:
|
||||
esp_vfs_unregister("/spiffs");
|
||||
spiffs_is_registered = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
//==========================
|
||||
void vfs_spiffs_register() {
|
||||
|
||||
if (spiffs_is_registered) return;
|
||||
|
||||
if (spiffs_mutex == NULL) {
|
||||
spiffs_mutex = xSemaphoreCreateMutex();
|
||||
if (spiffs_mutex == NULL) {
|
||||
ESP_LOGE(tag, "Error creating SPIFFS mutex");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
esp_vfs_t vfs = {
|
||||
//.fd_offset = 0, // not available in latest esp-idf
|
||||
.flags = ESP_VFS_FLAG_DEFAULT,
|
||||
.write = &vfs_spiffs_write,
|
||||
.open = &vfs_spiffs_open,
|
||||
.fstat = &vfs_spiffs_fstat,
|
||||
.close = &vfs_spiffs_close,
|
||||
.read = &vfs_spiffs_read,
|
||||
.lseek = &vfs_spiffs_lseek,
|
||||
.stat = &vfs_spiffs_stat,
|
||||
.link = NULL,
|
||||
.unlink = &vfs_spiffs_unlink,
|
||||
.rename = &vfs_spiffs_rename,
|
||||
.mkdir = &vfs_spiffs_mkdir,
|
||||
.opendir = &vfs_spiffs_opendir,
|
||||
.readdir = &vfs_spiffs_readdir,
|
||||
.closedir = &vfs_piffs_closedir,
|
||||
};
|
||||
|
||||
ESP_LOGI(tag, "Registering SPIFFS file system");
|
||||
esp_err_t res = esp_vfs_register(SPIFFS_BASE_PATH, &vfs, NULL);
|
||||
if (res != ESP_OK) {
|
||||
ESP_LOGE(tag, "Error, SPIFFS file system not registered");
|
||||
return;
|
||||
}
|
||||
spiffs_is_registered = 1;
|
||||
|
||||
spiffs_mount();
|
||||
}
|
||||
|
||||
//=============================
|
||||
int spiffs_unmount(int unreg) {
|
||||
|
||||
if (!spiffs_is_mounted) return 0;
|
||||
|
||||
SPIFFS_unmount(&fs);
|
||||
spiffs_is_mounted = 0;
|
||||
|
||||
if (unreg) {
|
||||
esp_vfs_unregister("/spiffs");
|
||||
spiffs_is_registered = 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
23
components/spiffs/spiffs_vfs.h
Normal file
23
components/spiffs/spiffs_vfs.h
Normal file
@ -0,0 +1,23 @@
|
||||
/*
|
||||
* spiffs VFS public function
|
||||
*
|
||||
* Author: LoBo (loboris@gmail.com / https://github.com/loboris)
|
||||
*
|
||||
* Part of this code is copied from or inspired by LUA-RTOS_ESP32 project:
|
||||
*
|
||||
* https://github.com/whitecatboard/Lua-RTOS-ESP32
|
||||
* IBEROXARXA SERVICIOS INTEGRALES, S.L. & CSS IBÉRICA, S.L.
|
||||
* Jaume Olivé (jolive@iberoxarxa.com / jolive@whitecatboard.org)
|
||||
*
|
||||
*/
|
||||
|
||||
#define SPIFFS_BASE_PATH "/spiffs"
|
||||
|
||||
|
||||
int spiffs_is_registered;
|
||||
int spiffs_is_mounted;
|
||||
|
||||
void vfs_spiffs_register();
|
||||
int spiffs_mount();
|
||||
int spiffs_unmount(int unreg);
|
||||
void spiffs_fs_stat(uint32_t *total, uint32_t *used);
|
26
components/spiffs_image/Makefile.projbuild
Normal file
26
components/spiffs_image/Makefile.projbuild
Normal file
@ -0,0 +1,26 @@
|
||||
SPIFFS_IMAGE_COMPONENT_PATH := $(COMPONENT_PATH)
|
||||
ifeq ($(OS),Windows_NT)
|
||||
MKSPIFFS_BIN="mkspiffs.exe"
|
||||
else
|
||||
MKSPIFFS_BIN="mkspiffs"
|
||||
endif
|
||||
|
||||
.PHONY: flashfs
|
||||
.PHONY: makefs
|
||||
.PHONY: copyfs
|
||||
|
||||
flashfs: $(SDKCONFIG_MAKEFILE) mkspiffs
|
||||
@echo "Making spiffs image ..."
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH)"
|
||||
$(MKSPIFFS_COMPONENT_PATH)/../mkspiffs/src/$(MKSPIFFS_BIN) -c $(SPIFFS_IMAGE_COMPONENT_PATH)/image -b $(CONFIG_SPIFFS_LOG_BLOCK_SIZE) -p $(CONFIG_SPIFFS_LOG_PAGE_SIZE) -s $(CONFIG_SPIFFS_SIZE) $(BUILD_DIR_BASE)/spiffs_image.img
|
||||
$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_SPIFFS_BASE_ADDR) $(BUILD_DIR_BASE)/spiffs_image.img
|
||||
|
||||
makefs: $(SDKCONFIG_MAKEFILE) mkspiffs
|
||||
@echo "Making spiffs image ..."
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH)"
|
||||
$(MKSPIFFS_COMPONENT_PATH)/../mkspiffs/src/$(MKSPIFFS_BIN) -c $(SPIFFS_IMAGE_COMPONENT_PATH)/image -b $(CONFIG_SPIFFS_LOG_BLOCK_SIZE) -p $(CONFIG_SPIFFS_LOG_PAGE_SIZE) -s $(CONFIG_SPIFFS_SIZE) $(BUILD_DIR_BASE)/spiffs_image.img
|
||||
|
||||
copyfs:
|
||||
@echo "Flashing spiffs image ..."
|
||||
@echo "$(ESPTOOLPY_WRITE_FLASH)"
|
||||
$(ESPTOOLPY_WRITE_FLASH) $(CONFIG_SPIFFS_BASE_ADDR) $(SPIFFS_IMAGE_COMPONENT_PATH)/spiffs_image.img
|
6
components/spiffs_image/component.mk
Normal file
6
components/spiffs_image/component.mk
Normal file
@ -0,0 +1,6 @@
|
||||
#
|
||||
# Component Makefile
|
||||
#
|
||||
|
||||
COMPONENT_SRCDIRS :=
|
||||
COMPONENT_ADD_INCLUDEDIRS :=
|
BIN
components/spiffs_image/image/fonts/BigFont.fon
Normal file
BIN
components/spiffs_image/image/fonts/BigFont.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/DejaVuSans12.fon
Normal file
BIN
components/spiffs_image/image/fonts/DejaVuSans12.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/DejaVuSans18.fon
Normal file
BIN
components/spiffs_image/image/fonts/DejaVuSans18.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/DejaVuSans24.fon
Normal file
BIN
components/spiffs_image/image/fonts/DejaVuSans24.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/DotMatrix_M.fon
Normal file
BIN
components/spiffs_image/image/fonts/DotMatrix_M.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/Grotesk24x48.fon
Normal file
BIN
components/spiffs_image/image/fonts/Grotesk24x48.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/SmallFont.fon
Normal file
BIN
components/spiffs_image/image/fonts/SmallFont.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/Ubuntu.fon
Normal file
BIN
components/spiffs_image/image/fonts/Ubuntu.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/fonts/arial_bold.fon
Normal file
BIN
components/spiffs_image/image/fonts/arial_bold.fon
Normal file
Binary file not shown.
119
components/spiffs_image/image/fonts/ocrfont.c
Normal file
119
components/spiffs_image/image/fonts/ocrfont.c
Normal file
@ -0,0 +1,119 @@
|
||||
// OCR_A_Extended_M.c
|
||||
// Font type : Full (95 characters)
|
||||
// Font size : 16x24 pixels
|
||||
// Memory usage : 4564 bytes
|
||||
|
||||
#if defined(__AVR__)
|
||||
#include <avr/pgmspace.h>
|
||||
#define fontdatatype const uint8_t
|
||||
#elif defined(__PIC32MX__)
|
||||
#define PROGMEM
|
||||
#define fontdatatype const unsigned char
|
||||
#elif defined(__arm__)
|
||||
#define PROGMEM
|
||||
#define fontdatatype const unsigned char
|
||||
#endif
|
||||
|
||||
fontdatatype OCR_A_Extended_M[4564] PROGMEM={
|
||||
0x10,0x18,0x20,0x5F,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <space>
|
||||
0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // !
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x1E,0x78,0x1E,0x78,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // "
|
||||
0x00,0x00,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x1F,0xF8,0x1F,0xF8,0x06,0x60,0x06,0x60,0x06,0x60,0x1F,0xF8,0x1F,0xF8,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // #
|
||||
0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0xF8,0x1F,0xF8,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x18,0x00,0x18,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // $
|
||||
0x00,0x00,0x1C,0x00,0x1C,0x18,0x1C,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0xE0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x07,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x38,0x18,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // %
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xC0,0x0F,0xC0,0x18,0x60,0x18,0x60,0x18,0x60,0x18,0x60,0x0C,0xC0,0x07,0x80,0x07,0x00,0x0F,0x80,0x1D,0xC8,0x18,0xF8,0x18,0x70,0x18,0xF0,0x0F,0xD8,0x0F,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // &
|
||||
0x00,0x00,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // '
|
||||
0x00,0x00,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x80,0x01,0x80,0x00,0xC0,0x00,0x60,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // (
|
||||
0x00,0x00,0x0C,0x00,0x06,0x00,0x03,0x00,0x01,0x80,0x01,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x00,0xC0,0x01,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // )
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x19,0x88,0x19,0x98,0x0F,0xF0,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x0F,0xF0,0x1D,0xB8,0x11,0x98,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // *
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // +
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x07,0xE0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ,
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // -
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // .
|
||||
0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // /
|
||||
|
||||
0x00,0x00,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 0
|
||||
0x00,0x00,0x1F,0x80,0x1F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x98,0x01,0x98,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 1
|
||||
0x00,0x00,0x1F,0xF0,0x1F,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0xF8,0x1F,0xF0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 2
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xFC,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x07,0xF8,0x07,0xF8,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x00,0x0C,0x1F,0xFC,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 3
|
||||
0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x1F,0xF8,0x1F,0xF8,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 4
|
||||
0x00,0x00,0x07,0xF8,0x07,0xF8,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x07,0xF0,0x07,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x18,0x18,0x1F,0xF8,0x07,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 5
|
||||
0x00,0x00,0x1C,0x00,0x1C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 6
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 7
|
||||
0x00,0x00,0x07,0xE0,0x07,0xE0,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 8
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // 9
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // :
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x00,0x07,0x00,0x07,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x07,0xE0,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ;
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x78,0x00,0xE0,0x01,0xC0,0x07,0x00,0x0E,0x00,0x1C,0x00,0x0E,0x00,0x07,0x00,0x01,0xC0,0x00,0xE0,0x00,0x78,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // =
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x00,0x1E,0x00,0x07,0x00,0x03,0x80,0x00,0xE0,0x00,0x70,0x00,0x38,0x00,0x70,0x00,0xE0,0x03,0x80,0x07,0x00,0x1E,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // >
|
||||
0x00,0x00,0x00,0x20,0x00,0x60,0x01,0xF0,0x03,0x98,0x07,0x18,0x0E,0x18,0x18,0x70,0x10,0xE0,0x01,0xC0,0x03,0x80,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ?
|
||||
|
||||
0x00,0x00,0x07,0xE0,0x0F,0xF0,0x18,0x18,0x18,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0x98,0x0F,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // @
|
||||
0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x06,0x60,0x06,0x60,0x0C,0x30,0x0F,0xF0,0x0F,0xF0,0x0C,0x30,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // A
|
||||
0x00,0x00,0x1F,0xF0,0x1F,0xF8,0x18,0x1C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x1C,0x1F,0xF8,0x1F,0xF8,0x18,0x1C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x1C,0x1F,0xF8,0x1F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // B
|
||||
0x00,0x00,0x01,0xFC,0x03,0xFC,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0x00,0x0C,0x00,0x0E,0x00,0x06,0x00,0x07,0x00,0x03,0xFC,0x01,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // C
|
||||
0x00,0x00,0x1F,0xC0,0x1F,0xE0,0x06,0x70,0x06,0x30,0x06,0x30,0x06,0x18,0x06,0x18,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x0C,0x06,0x1C,0x06,0x18,0x06,0x38,0x06,0x30,0x06,0x70,0x1F,0xE0,0x1F,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // D
|
||||
0x00,0x00,0x1F,0xFC,0x1F,0xFC,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xC0,0x1F,0xC0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xFC,0x1F,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // E
|
||||
0x00,0x00,0x1F,0xFC,0x1F,0xFC,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF0,0x1F,0xF0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // F
|
||||
0x00,0x00,0x01,0xF8,0x03,0xF8,0x03,0x00,0x06,0x00,0x0E,0x00,0x0C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0xF8,0x18,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // G
|
||||
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // H
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // I
|
||||
0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x0C,0x18,0x07,0xF0,0x03,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // J
|
||||
0x00,0x00,0x18,0x0C,0x18,0x18,0x18,0x30,0x18,0x60,0x18,0xC0,0x19,0x80,0x1B,0x00,0x1E,0x00,0x1C,0x00,0x1E,0x00,0x1F,0x00,0x1B,0x80,0x19,0xC0,0x18,0xE0,0x18,0x70,0x18,0x30,0x18,0x18,0x18,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // K
|
||||
0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // L
|
||||
0x00,0x00,0x1C,0x38,0x1C,0x38,0x1E,0x78,0x1E,0xF8,0x1B,0xD8,0x19,0x98,0x19,0x98,0x19,0x98,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // M
|
||||
0x00,0x00,0x1C,0x18,0x1C,0x18,0x1E,0x18,0x1E,0x18,0x1E,0x18,0x1B,0x18,0x1B,0x18,0x1B,0x18,0x19,0x98,0x19,0x98,0x18,0xD8,0x18,0xD8,0x18,0xD8,0x18,0x78,0x18,0x78,0x18,0x78,0x18,0x38,0x18,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // N
|
||||
0x00,0x00,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x0E,0x70,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x06,0x60,0x06,0x60,0x03,0xC0,0x01,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // O
|
||||
|
||||
0x00,0x00,0x1F,0xF0,0x1F,0xF0,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF0,0x1F,0xF0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // P
|
||||
0x00,0x00,0x00,0x70,0x00,0xF8,0x01,0xD8,0x03,0x98,0x07,0x18,0x0C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x98,0x19,0x98,0x19,0xF0,0x18,0xE0,0x19,0xC0,0x1B,0xE0,0x1F,0x78,0x0E,0x78,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Q
|
||||
0x00,0x00,0x1F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF0,0x19,0x80,0x19,0x80,0x18,0xC0,0x18,0xC0,0x18,0x60,0x18,0x60,0x18,0x30,0x18,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // R
|
||||
0x00,0x00,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x18,0x0C,0x00,0x06,0x00,0x06,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0xC0,0x00,0x60,0x00,0x60,0x00,0x30,0x18,0x18,0x18,0x18,0x1F,0xF8,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // S
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x19,0x98,0x19,0x98,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // T
|
||||
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // U
|
||||
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x0E,0x70,0x06,0x60,0x06,0x60,0x07,0xE0,0x03,0xC0,0x03,0xC0,0x03,0xC0,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // V
|
||||
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x19,0x98,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // W
|
||||
0x00,0x00,0x18,0x18,0x18,0x18,0x0C,0x30,0x0C,0x30,0x06,0x60,0x06,0x60,0x03,0xC0,0x03,0xC0,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x06,0x60,0x06,0x60,0x0C,0x30,0x0C,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // X
|
||||
0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x0C,0x30,0x0E,0x60,0x07,0xE0,0x03,0xC0,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Y
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x30,0x00,0x30,0x00,0x60,0x00,0x60,0x00,0xC0,0x00,0xC0,0x01,0x80,0x01,0x80,0x03,0x00,0x03,0x00,0x06,0x00,0x06,0x00,0x0C,0x00,0x0C,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // Z
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1B,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // [
|
||||
0x00,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x06,0x00,0x07,0x00,0x03,0x00,0x01,0x80,0x01,0x80,0x00,0xC0,0x00,0xC0,0x00,0x60,0x00,0x70,0x00,0x30,0x00,0x18,0x00,0x18,0x00,0x0C,0x00,0x0C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // <backslash>
|
||||
0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x00,0xD8,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ]
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x80,0x01,0x80,0x03,0xC0,0x03,0xC0,0x07,0xE0,0x07,0xE0,0x0E,0x70,0x0E,0x70,0x1C,0x30,0x1C,0x38,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ^
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0xFF,0xFF,0xFF,0x00,0x00,0x00,0x00, // _
|
||||
|
||||
0x00,0x00,0x06,0x00,0x07,0xC0,0x03,0xE0,0x00,0x60,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // `
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xF0,0x07,0xF0,0x00,0x18,0x00,0x18,0x00,0x18,0x0F,0xF8,0x0F,0xF8,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1F,0xF8,0x0F,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // a
|
||||
0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1B,0xE0,0x1F,0xF0,0x1E,0x38,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x18,0x1E,0x38,0x1F,0xF0,0x1B,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // b
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xFC,0x07,0xFC,0x0E,0x00,0x1C,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x1C,0x00,0x0E,0x00,0x07,0xFC,0x03,0xFC,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // c
|
||||
0x00,0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x07,0xD8,0x0F,0xF8,0x1C,0x78,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1C,0x78,0x0F,0xF8,0x07,0xD8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // d
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x0F,0xF0,0x1C,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x1F,0xF8,0x1F,0xF8,0x18,0x00,0x18,0x00,0x1C,0x00,0x0F,0xF8,0x07,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // e
|
||||
0x00,0x00,0x00,0xFC,0x01,0xFC,0x03,0x80,0x03,0x00,0x03,0x00,0x0F,0xF0,0x0F,0xF0,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x03,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // f
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xD8,0x0F,0xF8,0x1C,0x78,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1C,0x78,0x0F,0xF8,0x07,0xD8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x38,0x0F,0xF0,0x0F,0xE0, // g
|
||||
0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x19,0xF0,0x1B,0xF0,0x1F,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // h
|
||||
0x03,0x80,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0x80,0x0F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // i
|
||||
0x00,0x38,0x00,0x38,0x00,0x38,0x00,0x00,0x00,0x00,0x00,0x00,0x03,0xF8,0x03,0xF8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x0C,0x18,0x0C,0x18,0x07,0xF0,0x03,0xE0, // j
|
||||
0x00,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x30,0x18,0x60,0x18,0xC0,0x19,0x80,0x1B,0x80,0x1F,0x00,0x1E,0x00,0x1F,0x00,0x19,0x80,0x18,0xC0,0x18,0x60,0x18,0x30,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // k
|
||||
0x00,0x00,0x0F,0x80,0x0F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x0F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // l
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x3F,0x78,0x3F,0xFC,0x39,0xCC,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // m
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xF0,0x1B,0xF0,0x1F,0x18,0x1C,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // n
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xE0,0x0F,0xF0,0x1C,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x38,0x0F,0xF0,0x07,0xE0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // o
|
||||
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1B,0xC0,0x1F,0xE0,0x1E,0x70,0x1C,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x1C,0x38,0x1E,0x70,0x1F,0xE0,0x1B,0xC0,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00, // p
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0xD8,0x0F,0xF8,0x1C,0x78,0x18,0x38,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x1C,0x78,0x0F,0xF8,0x07,0xD8,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18, // q
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x19,0xF0,0x1B,0xF8,0x1F,0x0C,0x1C,0x0C,0x18,0x0C,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // r
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x0F,0xF0,0x1F,0xF8,0x18,0x18,0x18,0x00,0x1E,0x00,0x07,0x80,0x01,0xF0,0x00,0x70,0x00,0x18,0x00,0x18,0x18,0x18,0x1F,0xF0,0x0F,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // s
|
||||
0x00,0x00,0x00,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x1F,0xF8,0x1F,0xF8,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x00,0x06,0x0C,0x06,0x1C,0x03,0xF8,0x01,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // t
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x38,0x18,0xF8,0x0F,0xD8,0x07,0x98,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // u
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x38,0x38,0x18,0x30,0x18,0x30,0x0C,0x60,0x0C,0x60,0x06,0xC0,0x06,0xC0,0x03,0x80,0x03,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // v
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x30,0x0C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x31,0x8C,0x33,0xCC,0x1F,0xF8,0x1E,0x78,0x1C,0x30,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // w
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x18,0x18,0x1C,0x38,0x0C,0x30,0x06,0x60,0x03,0xC0,0x03,0xC0,0x01,0x80,0x03,0xC0,0x06,0xE0,0x0E,0x70,0x0C,0x30,0x18,0x18,0x18,0x18,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // x
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x18,0x30,0x18,0x30,0x18,0x30,0x18,0x38,0x38,0x18,0x30,0x18,0x30,0x0C,0x60,0x0C,0x60,0x06,0xC0,0x07,0xC0,0x07,0x80,0x01,0x80,0x03,0x80,0x03,0x00,0x03,0x00,0x3E,0x00,0x3E,0x00, // y
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x38,0x00,0x30,0x00,0x60,0x00,0xC0,0x01,0x80,0x03,0x00,0x06,0x00,0x0C,0x00,0x1C,0x00,0x1F,0xF8,0x1F,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // z
|
||||
0x00,0x00,0x00,0xF8,0x01,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0x00,0x1F,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0xF8,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // {
|
||||
0x00,0x00,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // |
|
||||
0x00,0x00,0x1F,0x00,0x1F,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x00,0xF8,0x00,0xF8,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x01,0x80,0x1F,0x80,0x1F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // }
|
||||
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x07,0x8C,0x1F,0xFC,0x18,0xF0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00, // ~
|
||||
};
|
BIN
components/spiffs_image/image/fonts/swiss721_outline.fon
Normal file
BIN
components/spiffs_image/image/fonts/swiss721_outline.fon
Normal file
Binary file not shown.
BIN
components/spiffs_image/image/images/Flintstones.jpg
Normal file
BIN
components/spiffs_image/image/images/Flintstones.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 26 KiB |
BIN
components/spiffs_image/image/images/animal-silhouettes.jpg
Normal file
BIN
components/spiffs_image/image/images/animal-silhouettes.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 12 KiB |
BIN
components/spiffs_image/image/images/evolution-of-human.jpg
Normal file
BIN
components/spiffs_image/image/images/evolution-of-human.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 13 KiB |
BIN
components/spiffs_image/image/images/girl_silhouettes.jpg
Normal file
BIN
components/spiffs_image/image/images/girl_silhouettes.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 11 KiB |
BIN
components/spiffs_image/image/images/people_silhouettes.jpg
Normal file
BIN
components/spiffs_image/image/images/people_silhouettes.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 17 KiB |
BIN
components/spiffs_image/image/images/silhouettes-dancing.jpg
Normal file
BIN
components/spiffs_image/image/images/silhouettes-dancing.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 15 KiB |
11
components/spiffs_image/image/spiffs.info
Normal file
11
components/spiffs_image/image/spiffs.info
Normal file
@ -0,0 +1,11 @@
|
||||
INTRODUCTION
|
||||
|
||||
Spiffs is a file system intended for SPI NOR flash devices on embedded targets.
|
||||
Spiffs is designed with following characteristics in mind:
|
||||
|
||||
* Small (embedded) targets, sparse RAM without heap
|
||||
* Only big areas of data (blocks) can be erased
|
||||
* An erase will reset all bits in block to ones
|
||||
* Writing pulls one to zeroes
|
||||
* Zeroes can only be pulled to ones by erase
|
||||
* Wear leveling
|
BIN
components/spiffs_image/spiffs_image.img
Normal file
BIN
components/spiffs_image/spiffs_image.img
Normal file
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user