Start work on dedicated sd card formatter program

This commit is contained in:
KemoNine 2020-09-13 00:35:41 -04:00
parent 4639aa70ab
commit 3fefcf7e34
135 changed files with 56322 additions and 0 deletions

5
hardware/sd_card_formatter/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
build/
sd_card_formatter*.bak
gui_backup/
sd_card_formatter.ino.beta
sd_card_formatter.ino.orig

View file

@ -0,0 +1,7 @@
# SD Card Formatter
A simple utility that will **FORMAT** the inserted SD Card.
**YOU MUST USE THIS TOOL TO INITIALIZE AN SD CARD 100% SAFELY**
*This utility is designed to be run from the ```_controller``` build!*

View file

@ -0,0 +1 @@
arduino-cli compile --log-level=warn --fqbn adafruit:nrf52:feather52840 sd_card_formatter.ino

View file

@ -0,0 +1,8 @@
# Ensure this script fails if either build or upload fails
$ErrorActionPreference = "Stop"
# Ensure we actually build before upload (common mistake)
& .\build.ps1
# Upload to board
& .\upload.ps1

View file

@ -0,0 +1,804 @@
//<App !Start!>
// FILE: [sd_card_formatter.ino]
// Created by GUIslice Builder version: [0.15.b004]
//
// GUIslice Builder Generated File
//
// For the latest guides, updates and support view:
// https://github.com/ImpulseAdventure/GUIslice
//
//<App !End!>
// ------------------------------------------------
// Headers to include
// ------------------------------------------------
//<Includes !Start!>
// Varous system includes
#include <Arduino.h>
// Various library includes
#include <Adafruit_NeoPixel.h>
#include <Adafruit_GFX.h>
#include <Adafruit_ILI9341.h>
#include <BBQ10Keyboard.h>
#include <CircularBuffer.h>
// Various local includes
#include "sd_card_formatter_GSLC.h"
//<Includes !End!>
// ------------------------------------------------
// Program Globals
// ------------------------------------------------
// Battery level measurement
#define VBATPIN A6
float measuredVBat;
int batteryPercent;
// TFT Setup
#define TFT_CS 9
#define TFT_DC 10
Adafruit_ILI9341 tft(TFT_CS, TFT_DC);
// Keyboard
BBQ10Keyboard keyboard;
#define KBD_BTN_1 0x06
#define KBD_BTN_2 0x11
#define KBD_BTN_3 0x07
#define KBD_BTN_4 0x12
#define KBD_SW_UP 0x01
#define KBD_SW_DN 0x02
#define KBD_SW_LF 0x03
#define KBD_SW_RT 0x04
#define KBD_SW_OK 0x05
CircularBuffer<int16_t,8> uiKeyBuffer;
// NeoPixels
#define PIXELS_NUM_BOARD 1
#define PIXELS_NUM_WING 1
#define PIXELS_WING_PIN 11
Adafruit_NeoPixel pixels_board(PIXELS_NUM_BOARD, PIN_NEOPIXEL, NEO_GRB + NEO_KHZ800);
Adafruit_NeoPixel pixels_wing(PIXELS_NUM_WING, PIXELS_WING_PIN, NEO_GRB + NEO_KHZ800);
// GUI state globals
bool popupOnScreen = false;
// Various loop handlers
void handlerKeyboard();
void handlerBatteryLevel();
void eraseAndFormatCard();
// Save some element references for direct access
//<Save_References !Start!>
gslc_tsElemRef* m_pElemBatteryLevel= NULL;
gslc_tsElemRef* m_pElemBtSDNo = NULL;
gslc_tsElemRef* m_pElemBtSDYes = NULL;
gslc_tsElemRef* m_pElemSDInfo = NULL;
gslc_tsElemRef* m_pElemStatusText = NULL;
//<Save_References !End!>
// Keyboard map related
#define MAX_INPUT_MAP 5
gslc_tsInputMap m_asInputMap[MAX_INPUT_MAP];
// Define debug message function
static int16_t DebugOut(char ch) { if (ch == (char)'\n') Serial.println(""); else Serial.write(ch); return 0; }
// ------------------------------------------------
// Callback Methods
// ------------------------------------------------
// Common Button callback
bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY)
{
// Typecast the parameters to match the GUI and element types
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
if ( eTouch == GSLC_TOUCH_UP_IN ) {
// From the element's ID we can determine which button was pressed.
switch (pElem->nId) {
//<Button Enums !Start!>
case E_ELEM_BTN_SD_FMT:
gslc_PopupShow(&m_gui, E_PG_SD_CONFIRM, false);
popupOnScreen = true;
break;
case E_ELEM_SD_NO:
gslc_PopupHide(&m_gui);
popupOnScreen = false;
break;
case E_ELEM_SD_YES:
gslc_PopupHide(&m_gui);
popupOnScreen = false;
gslc_ElemXTextboxReset(&m_gui, m_pElemSDInfo);
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "Formatting SD Card\n");
gslc_Update(&m_gui);
eraseAndFormatCard();
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "Formatting Complete\n");
gslc_Update(&m_gui);
break;
//<Button Enums !End!>
default:
break;
}
}
return true;
}
//<Checkbox Callback !Start!>
//<Checkbox Callback !End!>
//<Keypad Callback !Start!>
//<Keypad Callback !End!>
//<Spinner Callback !Start!>
//<Spinner Callback !End!>
//<Listbox Callback !Start!>
//<Listbox Callback !End!>
//<Draw Callback !Start!>
//<Draw Callback !End!>
//<Slider Enums !Start!>
//<Slider Enums !End!>
//<Tick Callback !Start!>
//<Tick Callback !End!>
// Keyboard Input polling callback function
bool CbKbdPoll(void* pvGui, int16_t* pnPinInd, int16_t* pnPinVal) {
// Check for new keyboard events just in case
handlerKeyboard();
// If the key buffer is empty no events to process
if (uiKeyBuffer.isEmpty()) {
return false;
}
// Process a key that's on the key buffer for the UI event(s)
*pnPinInd = uiKeyBuffer.pop();
*pnPinVal = 1;
return true;
}
// ------------------------------------------------
// Setup
// ------------------------------------------------
void setup() {
Serial.begin(115200);
// If GUI Slice debug of drivers is turned on, wait for serial so we get proper debug output
#if defined(DBG_LOG) || defined(DBG_TOUCH) || defined(DBG_FRAME_RATE) || defined(DBG_DRAW_IMM) || defined(DBG_DRIVER)
while (!Serial) {
;
}
#endif
// GUI Slice debugging
gslc_InitDebug(&DebugOut);
// Setup red LED to indicate device is on (in case we disable NeoPixel battery level later)
pinMode(3, OUTPUT);
digitalWrite(3, HIGH);
// Setup NeoPixels
pixels_board.begin();
pixels_wing.begin();
pixels_board.clear();
pixels_wing.clear();
pixels_board.setBrightness(10);
pixels_wing.setBrightness(5);
// Setup neopixels to indicate we are initializing gui slice
// This can serve as an indication something has gone wrong like the sd card is missing
pixels_wing.setPixelColor(0, pixels_board.Color(255, 0, 0));
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
pixels_wing.show();
pixels_board.show();
// Setup BBQ10Keyboard
Wire.begin();
keyboard.begin();
keyboard.setBacklight(0.5f);
// Init GUI Slicle
InitGUIslice_gen();
// Set the pin poll callback function
gslc_SetPinPollFunc(&m_gui, CbKbdPoll);
// Create the GUI input mapping (pin event to GUI action)
gslc_InitInputMap(&m_gui, m_asInputMap, MAX_INPUT_MAP);
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_UP, GSLC_ACTION_FOCUS_NEXT, 0);
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_DN, GSLC_ACTION_FOCUS_PREV, 0);
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_LF, GSLC_ACTION_FOCUS_NEXT, 0);
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_RT, GSLC_ACTION_FOCUS_PREV, 0);
gslc_InputMapAdd(&m_gui, GSLC_INPUT_PIN_ASSERT, KBD_SW_OK, GSLC_ACTION_SELECT, 0);
// Flip to main screen
// This wouldn't be necessary if we hadn't chopped off the formatter from the main _controller project and actually updated the main screen ;)
gslc_SetPageCur(&m_gui, E_SD_CARD);
// Set neopixels to standard start state
pixels_wing.clear();
pixels_wing.show();
pixels_board.setPixelColor(0, pixels_board.Color(0, 0, 255));
pixels_board.show();
}
// -----------------------------------
// Main event loop
// -----------------------------------
void loop() {
// Handle keyboard events
handlerKeyboard();
// Update battery level as appropriate
handlerBatteryLevel();
gslc_Update(&m_gui);
}
// ------------------------------------------------
// Keyboard Handler
// ------------------------------------------------
void handlerKeyboard() {
// Don't do anything if there are no key presses to process
if (keyboard.keyCount() == 0) {
return;
}
// Check if keys were pressed and drain queue of pressed keys
while (keyboard.keyCount() > 0) {
// Get keyboard event
const BBQ10Keyboard::KeyEvent key = keyboard.keyEvent();
// Process key press events
if (key.state == BBQ10Keyboard::StatePress) {
// Add keys to the key buffer that are mapped to UI functions (only for config screens)
if (key.key == KBD_SW_UP
|| key.key == KBD_SW_DN
|| key.key == KBD_SW_LF
|| key.key == KBD_SW_RT
|| key.key == KBD_SW_OK) {
uiKeyBuffer.push(key.key);
}
}
// Pick color for signaling a key was pressed (short or long press)
uint32_t keyboard_pixel_color = pixels_wing.Color(0, 0, 255);
if (key.state == BBQ10Keyboard::StateLongPress) {
keyboard_pixel_color = pixels_wing.Color(0, 255, 255);
}
// Display indicator accordingly
if (key.state == BBQ10Keyboard::StatePress || key.state == BBQ10Keyboard::StateLongPress) {
pixels_wing.setPixelColor(0, keyboard_pixel_color);
pixels_wing.show();
}
else {
pixels_wing.clear();
pixels_wing.show();
}
}
}
// ------------------------------------------------
// Battery level handler
// ------------------------------------------------
void handlerBatteryLevel() {
measuredVBat = analogRead(VBATPIN);
measuredVBat *= 2; // we divided by 2, so multiply back
measuredVBat *= 3.3; // Multiply by 3.3V, our reference voltage
measuredVBat /= 1024; // convert to voltage
batteryPercent = (measuredVBat / 3.3) * 100;
gslc_tsColor colorForHeaderElements;
if (batteryPercent >= 75) {
pixels_board.setPixelColor(0, pixels_board.Color(0, 255, 0));
colorForHeaderElements = GSLC_COL_GREEN;
}
else if (batteryPercent >= 50) {
colorForHeaderElements = GSLC_COL_YELLOW;
pixels_board.setPixelColor(0, pixels_board.Color(255, 255, 0));
}
else if (batteryPercent >= 25) {
colorForHeaderElements = GSLC_COL_ORANGE;
pixels_board.setPixelColor(0, pixels_board.Color(255, 128, 0));
}
else {
colorForHeaderElements = GSLC_COL_RED;
pixels_board.setPixelColor(0, pixels_board.Color(255, 0, 0));
}
gslc_ElemXProgressSetVal(&m_gui, m_pElemBatteryLevel, batteryPercent);
gslc_tsXProgress* pGauge = (gslc_tsXProgress*)gslc_GetXDataFromRef(&m_gui,m_pElemBatteryLevel,GSLC_TYPEX_PROGRESS,__LINE__);
pGauge->colGauge = colorForHeaderElements;
gslc_ElemSetTxtCol(&m_gui, m_pElemStatusText, colorForHeaderElements);
// Update GUI and NeoPixel with battery status information
pixels_board.show();
}
// ------------------------------------------------
// Format SD Card
// ------------------------------------------------
/*
* This program will format an SD or SDHC card.
* Warning all data will be deleted!
*
* For SD/SDHC cards larger than 64 MB this
* program attempts to match the format
* generated by SDFormatter available here:
*
* http://www.sdcard.org/consumers/formatter/
*
* For smaller cards this program uses FAT16
* and SDFormatter uses FAT12.
*/
// Set USE_SDIO to zero for SPI card access.
#define USE_SDIO 0
//
// Change the value of chipSelect if your hardware does
// not use the default value, SS. Common values are:
// Arduino Ethernet shield: pin 4
// Sparkfun SD shield: pin 8
// Adafruit SD shields and modules: pin 10
const uint8_t chipSelect = 5;
// Initialize at highest supported speed not over 50 MHz.
// Reduce max speed if errors occur.
#define SPI_SPEED SD_SCK_MHZ(50)
// Print extra info for debug if DEBUG_PRINT is nonzero
#include <SPI.h>
#include "src/SdFat/SdFat.h"
#include "src/SdFat/sdios.h"
#if USE_SDIO
// Use faster SdioCardEX
SdioCardEX card;
// SdioCard card;
#else // USE_SDIO
Sd2Card card;
#endif // USE_SDIO
uint32_t cardSizeBlocks;
uint32_t cardCapacityMB;
// cache for SD block
cache_t cache;
// MBR information
uint8_t partType;
uint32_t relSector;
uint32_t partSize;
// Fake disk geometry
uint8_t numberOfHeads;
uint8_t sectorsPerTrack;
// FAT parameters
uint16_t reservedSectors;
uint8_t sectorsPerCluster;
uint32_t fatStart;
uint32_t fatSize;
uint32_t dataStart;
// constants for file system structure
uint16_t const BU16 = 128;
uint16_t const BU32 = 8192;
// strings needed in file system structures
char noName[] = "NO NAME ";
char fat16str[] = "FAT16 ";
char fat32str[] = "FAT32 ";
//------------------------------------------------------------------------------
void sdError(char* msg) {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "error: ");
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, msg);
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "\n");
gslc_Update(&m_gui);
sdErrorHalt();
}
//------------------------------------------------------------------------------
void sdErrorHalt() {
if (card.errorCode()) {
char textForDisplay[32];
snprintf(textForDisplay, 32, "SD error: %d\n", int(card.errorCode()));
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, textForDisplay);
gslc_Update(&m_gui);
}
SysCall::halt();
}
//------------------------------------------------------------------------------
// write cached block to the card
uint8_t writeCache(uint32_t lbn) {
return card.writeBlock(lbn, cache.data);
}
//------------------------------------------------------------------------------
// initialize appropriate sizes for SD capacity
void initSizes() {
if (cardCapacityMB <= 6) {
sdError("Card is too small.");
} else if (cardCapacityMB <= 16) {
sectorsPerCluster = 2;
} else if (cardCapacityMB <= 32) {
sectorsPerCluster = 4;
} else if (cardCapacityMB <= 64) {
sectorsPerCluster = 8;
} else if (cardCapacityMB <= 128) {
sectorsPerCluster = 16;
} else if (cardCapacityMB <= 1024) {
sectorsPerCluster = 32;
} else if (cardCapacityMB <= 32768) {
sectorsPerCluster = 64;
} else {
// SDXC cards
sectorsPerCluster = 128;
}
char textForDisplay[64];
snprintf(textForDisplay, 64, "Blocks/Cluster: %d\n", int(sectorsPerCluster));
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, textForDisplay);
gslc_Update(&m_gui);
// set fake disk geometry
sectorsPerTrack = cardCapacityMB <= 256 ? 32 : 63;
if (cardCapacityMB <= 16) {
numberOfHeads = 2;
} else if (cardCapacityMB <= 32) {
numberOfHeads = 4;
} else if (cardCapacityMB <= 128) {
numberOfHeads = 8;
} else if (cardCapacityMB <= 504) {
numberOfHeads = 16;
} else if (cardCapacityMB <= 1008) {
numberOfHeads = 32;
} else if (cardCapacityMB <= 2016) {
numberOfHeads = 64;
} else if (cardCapacityMB <= 4032) {
numberOfHeads = 128;
} else {
numberOfHeads = 255;
}
}
//------------------------------------------------------------------------------
// zero cache and optionally set the sector signature
void clearCache(uint8_t addSig) {
memset(&cache, 0, sizeof(cache));
if (addSig) {
cache.mbr.mbrSig0 = BOOTSIG0;
cache.mbr.mbrSig1 = BOOTSIG1;
}
}
//------------------------------------------------------------------------------
// zero FAT and root dir area on SD
void clearFatDir(uint32_t bgn, uint32_t count) {
clearCache(false);
#if USE_SDIO
for (uint32_t i = 0; i < count; i++) {
if (!card.writeBlock(bgn + i, cache.data)) {
sdError("Clear FAT/DIR writeBlock failed");
}
if ((i & 0XFF) == 0) {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, ".");
gslc_Update(&m_gui);
}
}
#else // USE_SDIO
if (!card.writeStart(bgn, count)) {
sdError("Clear FAT/DIR writeStart failed");
}
for (uint32_t i = 0; i < count; i++) {
if ((i & 0XFF) == 0) {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, ".");
gslc_Update(&m_gui);
}
if (!card.writeData(cache.data)) {
sdError("Clear FAT/DIR writeData failed");
}
}
if (!card.writeStop()) {
sdError("Clear FAT/DIR writeStop failed");
}
#endif // USE_SDIO
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "\n");
gslc_Update(&m_gui);
}
//------------------------------------------------------------------------------
// return cylinder number for a logical block number
uint16_t lbnToCylinder(uint32_t lbn) {
return lbn / (numberOfHeads * sectorsPerTrack);
}
//------------------------------------------------------------------------------
// return head number for a logical block number
uint8_t lbnToHead(uint32_t lbn) {
return (lbn % (numberOfHeads * sectorsPerTrack)) / sectorsPerTrack;
}
//------------------------------------------------------------------------------
// return sector number for a logical block number
uint8_t lbnToSector(uint32_t lbn) {
return (lbn % sectorsPerTrack) + 1;
}
//------------------------------------------------------------------------------
// format and write the Master Boot Record
void writeMbr() {
clearCache(true);
part_t* p = cache.mbr.part;
p->boot = 0;
uint16_t c = lbnToCylinder(relSector);
if (c > 1023) {
sdError("MBR CHS");
}
p->beginCylinderHigh = c >> 8;
p->beginCylinderLow = c & 0XFF;
p->beginHead = lbnToHead(relSector);
p->beginSector = lbnToSector(relSector);
p->type = partType;
uint32_t endLbn = relSector + partSize - 1;
c = lbnToCylinder(endLbn);
if (c <= 1023) {
p->endCylinderHigh = c >> 8;
p->endCylinderLow = c & 0XFF;
p->endHead = lbnToHead(endLbn);
p->endSector = lbnToSector(endLbn);
} else {
// Too big flag, c = 1023, h = 254, s = 63
p->endCylinderHigh = 3;
p->endCylinderLow = 255;
p->endHead = 254;
p->endSector = 63;
}
p->firstSector = relSector;
p->totalSectors = partSize;
if (!writeCache(0)) {
sdError("write MBR");
}
}
//------------------------------------------------------------------------------
// generate serial number from card size and micros since boot
uint32_t volSerialNumber() {
return (cardSizeBlocks << 8) + micros();
}
//------------------------------------------------------------------------------
// format the SD as FAT16
void makeFat16() {
uint32_t nc;
for (dataStart = 2 * BU16;; dataStart += BU16) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 255)/256;
uint32_t r = BU16 + 1 + 2 * fatSize + 32;
if (dataStart < r) {
continue;
}
relSector = dataStart - r + BU16;
break;
}
// check valid cluster count for FAT16 volume
if (nc < 4085 || nc >= 65525) {
sdError("Bad cluster count");
}
reservedSectors = 1;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + 2 * fatSize + reservedSectors + 32;
if (partSize < 32680) {
partType = 0X01;
} else if (partSize < 65536) {
partType = 0X04;
} else {
partType = 0X06;
}
// write MBR
writeMbr();
clearCache(true);
fat_boot_t* pb = &cache.fbs;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->rootDirEntryCount = 512;
pb->mediaType = 0XF8;
pb->sectorsPerFat16 = fatSize;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->driveNumber = 0X80;
pb->bootSignature = EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
memcpy(pb->fileSystemType, fat16str, sizeof(pb->fileSystemType));
// write partition boot sector
if (!writeCache(relSector)) {
sdError("FAT16 write PBS failed");
}
// clear FAT and root directory
clearFatDir(fatStart, dataStart - fatStart);
clearCache(false);
cache.fat16[0] = 0XFFF8;
cache.fat16[1] = 0XFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
sdError("FAT16 reserve failed");
}
}
//------------------------------------------------------------------------------
// format the SD as FAT32
void makeFat32() {
uint32_t nc;
relSector = BU32;
for (dataStart = 2 * BU32;; dataStart += BU32) {
nc = (cardSizeBlocks - dataStart)/sectorsPerCluster;
fatSize = (nc + 2 + 127)/128;
uint32_t r = relSector + 9 + 2 * fatSize;
if (dataStart >= r) {
break;
}
}
// error if too few clusters in FAT32 volume
if (nc < 65525) {
sdError("Bad cluster count");
}
reservedSectors = dataStart - relSector - 2 * fatSize;
fatStart = relSector + reservedSectors;
partSize = nc * sectorsPerCluster + dataStart - relSector;
// type depends on address of end sector
// max CHS has lbn = 16450560 = 1024*255*63
if ((relSector + partSize) <= 16450560) {
// FAT32
partType = 0X0B;
} else {
// FAT32 with INT 13
partType = 0X0C;
}
writeMbr();
clearCache(true);
fat32_boot_t* pb = &cache.fbs32;
pb->jump[0] = 0XEB;
pb->jump[1] = 0X00;
pb->jump[2] = 0X90;
for (uint8_t i = 0; i < sizeof(pb->oemId); i++) {
pb->oemId[i] = ' ';
}
pb->bytesPerSector = 512;
pb->sectorsPerCluster = sectorsPerCluster;
pb->reservedSectorCount = reservedSectors;
pb->fatCount = 2;
pb->mediaType = 0XF8;
pb->sectorsPerTrack = sectorsPerTrack;
pb->headCount = numberOfHeads;
pb->hidddenSectors = relSector;
pb->totalSectors32 = partSize;
pb->sectorsPerFat32 = fatSize;
pb->fat32RootCluster = 2;
pb->fat32FSInfo = 1;
pb->fat32BackBootBlock = 6;
pb->driveNumber = 0X80;
pb->bootSignature = EXTENDED_BOOT_SIG;
pb->volumeSerialNumber = volSerialNumber();
memcpy(pb->volumeLabel, noName, sizeof(pb->volumeLabel));
memcpy(pb->fileSystemType, fat32str, sizeof(pb->fileSystemType));
// write partition boot sector and backup
if (!writeCache(relSector)
|| !writeCache(relSector + 6)) {
sdError("FAT32 write PBS failed");
}
clearCache(true);
// write extra boot area and backup
if (!writeCache(relSector + 2)
|| !writeCache(relSector + 8)) {
sdError("FAT32 PBS ext failed");
}
fat32_fsinfo_t* pf = &cache.fsinfo;
pf->leadSignature = FSINFO_LEAD_SIG;
pf->structSignature = FSINFO_STRUCT_SIG;
pf->freeCount = 0XFFFFFFFF;
pf->nextFree = 0XFFFFFFFF;
// write FSINFO sector and backup
if (!writeCache(relSector + 1)
|| !writeCache(relSector + 7)) {
sdError("FAT32 FSINFO failed");
}
clearFatDir(fatStart, 2 * fatSize + sectorsPerCluster);
clearCache(false);
cache.fat32[0] = 0x0FFFFFF8;
cache.fat32[1] = 0x0FFFFFFF;
cache.fat32[2] = 0x0FFFFFFF;
// write first block of FAT and backup for reserved clusters
if (!writeCache(fatStart)
|| !writeCache(fatStart + fatSize)) {
sdError("FAT32 reserve failed");
}
}
//------------------------------------------------------------------------------
// flash erase all data
uint32_t const ERASE_SIZE = 262144L;
void eraseCard() {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "Erasing\n");
gslc_Update(&m_gui);
uint32_t firstBlock = 0;
uint32_t lastBlock;
uint16_t n = 0;
do {
lastBlock = firstBlock + ERASE_SIZE - 1;
if (lastBlock >= cardSizeBlocks) {
lastBlock = cardSizeBlocks - 1;
}
if (!card.erase(firstBlock, lastBlock)) {
sdError("erase failed");
}
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, ".");
gslc_Update(&m_gui);
if ((n++)%32 == 31) {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "\n");
gslc_Update(&m_gui);
}
firstBlock += ERASE_SIZE;
} while (firstBlock < cardSizeBlocks);
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "\n");
gslc_Update(&m_gui);
if (!card.readBlock(0, cache.data)) {
sdError("readBlock");
}
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "Erase done\n");
gslc_Update(&m_gui);
}
//------------------------------------------------------------------------------
void formatCard() {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "Formatting\n");
gslc_Update(&m_gui);
initSizes();
if (card.type() != SD_CARD_TYPE_SDHC) {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "FAT16\n");
gslc_Update(&m_gui);
makeFat16();
} else {
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "FAT32\n");
gslc_Update(&m_gui);
makeFat32();
}
#if DEBUG_PRINT
debugPrint();
#endif // DEBUG_PRINT
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, "Format done\n");
gslc_Update(&m_gui);
}
//------------------------------------------------------------------------------
void eraseAndFormatCard() {
#if USE_SDIO
if (!card.begin()) {
sdError("card.begin failed");
}
#else // USE_SDIO
if (!card.begin(chipSelect, SPI_SPEED)) {
sdError("card.begin failed");
}
#endif
cardSizeBlocks = card.cardSize();
if (cardSizeBlocks == 0) {
sdError("cardSize");
}
cardCapacityMB = (cardSizeBlocks + 2047)/2048;
char textForDisplay[128];
snprintf(textForDisplay, 128, "Card Size: : %.0fMB, (MB = 1,000,000 bytes)\n", 1.048576*cardCapacityMB);
gslc_ElemXTextboxAdd(&m_gui, m_pElemSDInfo, textForDisplay);
gslc_Update(&m_gui);
eraseCard();
formatCard();
}
//------------------------------------------------------------------------------

Binary file not shown.

View file

@ -0,0 +1,255 @@
//<File !Start!>
// FILE: [sd_card_formatter_GSLC.h]
// Created by GUIslice Builder version: [0.15.b004]
//
// GUIslice Builder Generated GUI Framework File
//
// For the latest guides, updates and support view:
// https://github.com/ImpulseAdventure/GUIslice
//
//<File !End!>
#ifndef _GUISLICE_GEN_H
#define _GUISLICE_GEN_H
// ------------------------------------------------
// Headers to include
// ------------------------------------------------
#include "src/guislice/GUIslice.h"
#include "src/guislice/GUIslice_drv.h"
// Include any extended elements
//<Includes !Start!>
// Include extended elements
#include "src/guislice/XProgress.h"
#include "src/guislice/XTextbox.h"
//<Includes !End!>
// ------------------------------------------------
// Headers and Defines for fonts
// Note that font files are located within the Adafruit-GFX library folder:
// ------------------------------------------------
//<Fonts !Start!>
#if defined(DRV_DISP_TFT_ESPI)
#error Project tab->Target Platform should be tft_espi
#endif
#include <Adafruit_GFX.h>
#include "src/guislice/NotoMono10pt7b.h"
#include "src/guislice/NotoMono12pt7b.h"
#include "src/guislice/NotoMono16pt7b.h"
#include "src/guislice/NotoMono8pt7b.h"
//<Fonts !End!>
// ------------------------------------------------
// Defines for resources
// ------------------------------------------------
//<Resources !Start!>
//<Resources !End!>
// ------------------------------------------------
// Enumerations for pages, elements, fonts, images
// ------------------------------------------------
//<Enum !Start!>
enum {E_PG_BASE,E_PG_MAIN,E_SD_CARD,E_PG_SD_CONFIRM};
enum {E_ELEM_BATT_LEVEL,E_ELEM_BOX1,E_ELEM_BTN_SD_FMT,E_ELEM_SD_NO
,E_ELEM_SD_YES,E_ELEM_STATUS,E_ELEM_TEXT14,E_ELEM_TEXT15
,E_ELEM_TX_SD_INFO,E_STATUS_LINE};
// Must use separate enum for fonts with MAX_FONT at end to use gslc_FontSet.
enum {E_AO_NOTOMONO10PT7B,E_AO_NOTOMONO12PT7B,E_AO_NOTOMONO16PT7B
,E_AO_NOTOMONO8PT7B,MAX_FONT};
//<Enum !End!>
// ------------------------------------------------
// Instantiate the GUI
// ------------------------------------------------
// ------------------------------------------------
// Define the maximum number of elements and pages
// ------------------------------------------------
//<ElementDefines !Start!>
#define MAX_PAGE 4
#define MAX_ELEM_PG_BASE 3 // # Elems total on page
#define MAX_ELEM_PG_BASE_RAM MAX_ELEM_PG_BASE // # Elems in RAM
#define MAX_ELEM_PG_MAIN 0 // # Elems total on page
#define MAX_ELEM_PG_MAIN_RAM MAX_ELEM_PG_MAIN // # Elems in RAM
#define MAX_ELEM_SD_CARD 2 // # Elems total on page
#define MAX_ELEM_SD_CARD_RAM MAX_ELEM_SD_CARD // # Elems in RAM
#define MAX_ELEM_PG_SD_CONFIRM 5 // # Elems total on page
#define MAX_ELEM_PG_SD_CONFIRM_RAM MAX_ELEM_PG_SD_CONFIRM // # Elems in RAM
//<ElementDefines !End!>
// ------------------------------------------------
// Create element storage
// ------------------------------------------------
gslc_tsGui m_gui;
gslc_tsDriver m_drv;
gslc_tsFont m_asFont[MAX_FONT];
gslc_tsPage m_asPage[MAX_PAGE];
//<GUI_Extra_Elements !Start!>
gslc_tsElem m_asBasePage1Elem[MAX_ELEM_PG_BASE_RAM];
gslc_tsElemRef m_asBasePage1ElemRef[MAX_ELEM_PG_BASE];
gslc_tsElem m_asPage1Elem[MAX_ELEM_PG_MAIN_RAM];
gslc_tsElemRef m_asPage1ElemRef[MAX_ELEM_PG_MAIN];
gslc_tsElem m_asPage3Elem[MAX_ELEM_SD_CARD_RAM];
gslc_tsElemRef m_asPage3ElemRef[MAX_ELEM_SD_CARD];
gslc_tsElem m_asPopup1Elem[MAX_ELEM_PG_SD_CONFIRM_RAM];
gslc_tsElemRef m_asPopup1ElemRef[MAX_ELEM_PG_SD_CONFIRM];
gslc_tsXProgress m_sXBarGauge2;
gslc_tsXTextbox m_sTextbox2;
char m_acTextboxBuf2[224]; // NRows=8 NCols=28
#define MAX_STR 100
//<GUI_Extra_Elements !End!>
// ------------------------------------------------
// Program Globals
// ------------------------------------------------
// Element References for direct access
//<Extern_References !Start!>
extern gslc_tsElemRef* m_pElemBatteryLevel;
extern gslc_tsElemRef* m_pElemBtSDNo;
extern gslc_tsElemRef* m_pElemBtSDYes;
extern gslc_tsElemRef* m_pElemSDInfo;
extern gslc_tsElemRef* m_pElemStatusText;
extern gslc_tsElemRef* m_pTextSliderSDInfo;
//<Extern_References !End!>
// Define debug message function
static int16_t DebugOut(char ch);
// ------------------------------------------------
// Callback Methods
// ------------------------------------------------
bool CbBtnCommon(void* pvGui,void *pvElemRef,gslc_teTouch eTouch,int16_t nX,int16_t nY);
bool CbCheckbox(void* pvGui, void* pvElemRef, int16_t nSelId, bool bState);
bool CbDrawScanner(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
bool CbKeypad(void* pvGui, void *pvElemRef, int16_t nState, void* pvData);
bool CbListbox(void* pvGui, void* pvElemRef, int16_t nSelId);
bool CbSlidePos(void* pvGui,void* pvElemRef,int16_t nPos);
bool CbSpinner(void* pvGui, void *pvElemRef, int16_t nState, void* pvData);
bool CbTickScanner(void* pvGui,void* pvScope);
// ------------------------------------------------
// Create page elements
// ------------------------------------------------
void InitGUIslice_gen()
{
gslc_tsElemRef* pElemRef = NULL;
if (!gslc_Init(&m_gui,&m_drv,m_asPage,MAX_PAGE,m_asFont,MAX_FONT)) { return; }
// ------------------------------------------------
// Load Fonts
// ------------------------------------------------
//<Load_Fonts !Start!>
if (!gslc_FontSet(&m_gui,E_AO_NOTOMONO10PT7B,GSLC_FONTREF_PTR,&NotoMono10pt7b,1)) { return; }
if (!gslc_FontSet(&m_gui,E_AO_NOTOMONO12PT7B,GSLC_FONTREF_PTR,&NotoMono12pt7b,1)) { return; }
if (!gslc_FontSet(&m_gui,E_AO_NOTOMONO16PT7B,GSLC_FONTREF_PTR,&NotoMono16pt7b,1)) { return; }
if (!gslc_FontSet(&m_gui,E_AO_NOTOMONO8PT7B,GSLC_FONTREF_PTR,&NotoMono8pt7b,1)) { return; }
//<Load_Fonts !End!>
//<InitGUI !Start!>
gslc_PageAdd(&m_gui,E_PG_BASE,m_asBasePage1Elem,MAX_ELEM_PG_BASE_RAM,m_asBasePage1ElemRef,MAX_ELEM_PG_BASE);
gslc_PageAdd(&m_gui,E_PG_MAIN,m_asPage1Elem,MAX_ELEM_PG_MAIN_RAM,m_asPage1ElemRef,MAX_ELEM_PG_MAIN);
gslc_PageAdd(&m_gui,E_SD_CARD,m_asPage3Elem,MAX_ELEM_SD_CARD_RAM,m_asPage3ElemRef,MAX_ELEM_SD_CARD);
gslc_PageAdd(&m_gui,E_PG_SD_CONFIRM,m_asPopup1Elem,MAX_ELEM_PG_SD_CONFIRM_RAM,m_asPopup1ElemRef,MAX_ELEM_PG_SD_CONFIRM);
// Now mark E_PG_BASE as a "base" page which means that it's elements
// are always visible. This is useful for common page elements.
gslc_SetPageBase(&m_gui, E_PG_BASE);
// NOTE: The current page defaults to the first page added. Here we explicitly
// ensure that the main page is the correct page no matter the add order.
gslc_SetPageCur(&m_gui,E_PG_MAIN);
// Set Background to a flat color
gslc_SetBkgndColor(&m_gui,GSLC_COL_BLACK);
// -----------------------------------
// PAGE: E_PG_BASE
// Create progress bar E_ELEM_BATT_LEVEL
pElemRef = gslc_ElemXProgressCreate(&m_gui,E_ELEM_BATT_LEVEL,E_PG_BASE,&m_sXBarGauge2,
(gslc_tsRect){263,5,50,15},0,100,0,GSLC_COL_GREEN,false);
m_pElemBatteryLevel = pElemRef;
// Create E_ELEM_STATUS text label
pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_STATUS,E_PG_BASE,(gslc_tsRect){2,2,250,21},
(char*)"SD Card Formatter",0,E_AO_NOTOMONO8PT7B);
gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_GREEN);
m_pElemStatusText = pElemRef;
// Create E_STATUS_LINE line
pElemRef = gslc_ElemCreateLine(&m_gui,E_STATUS_LINE,E_PG_BASE,0,25,320,25);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLACK,GSLC_COL_GRAY_DK1,GSLC_COL_GRAY_DK1);
// -----------------------------------
// PAGE: E_PG_MAIN
// -----------------------------------
// PAGE: E_SD_CARD
// Create textbox
pElemRef = gslc_ElemXTextboxCreate(&m_gui,E_ELEM_TX_SD_INFO,E_SD_CARD,&m_sTextbox2,
(gslc_tsRect){3,30,313,150},E_AO_NOTOMONO8PT7B,
(char*)&m_acTextboxBuf2,8,28);
gslc_ElemXTextboxWrapSet(&m_gui,pElemRef,true);
gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_GRAY_LT3);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_GRAY,GSLC_COL_BLACK,GSLC_COL_BLACK);
m_pElemSDInfo = pElemRef;
// create E_ELEM_BTN_SD_FMT button with text label
pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_BTN_SD_FMT,E_SD_CARD,
(gslc_tsRect){110,190,100,40},(char*)"FORMAT?",0,E_AO_NOTOMONO8PT7B,&CbBtnCommon);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_RED_DK1,GSLC_COL_GRAY,GSLC_COL_RED_DK1);
// -----------------------------------
// PAGE: E_PG_SD_CONFIRM
// Create E_ELEM_BOX1 box
pElemRef = gslc_ElemCreateBox(&m_gui,E_ELEM_BOX1,E_PG_SD_CONFIRM,(gslc_tsRect){0,0,320,240});
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLACK,GSLC_COL_BLACK,GSLC_COL_BLACK);
// Create E_ELEM_TEXT14 text label
pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT14,E_PG_SD_CONFIRM,(gslc_tsRect){0,30,320,42},
(char*)"Format SD Card?",0,E_AO_NOTOMONO16PT7B);
gslc_ElemSetTxtAlign(&m_gui,pElemRef,GSLC_ALIGN_MID_MID);
gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_RED_LT1);
// Create E_ELEM_TEXT15 text label
pElemRef = gslc_ElemCreateTxt(&m_gui,E_ELEM_TEXT15,E_PG_SD_CONFIRM,(gslc_tsRect){0,90,320,32},
(char*)"This will ERASE it!",0,E_AO_NOTOMONO12PT7B);
gslc_ElemSetTxtAlign(&m_gui,pElemRef,GSLC_ALIGN_MID_MID);
gslc_ElemSetTxtCol(&m_gui,pElemRef,GSLC_COL_RED_LT4);
// create E_ELEM_SD_NO button with text label
pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_SD_NO,E_PG_SD_CONFIRM,
(gslc_tsRect){50,160,80,40},(char*)"No",0,E_AO_NOTOMONO10PT7B,&CbBtnCommon);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_BLUE_LT2,GSLC_COL_GRAY,GSLC_COL_BLUE_LT2);
m_pElemBtSDNo = pElemRef;
// create E_ELEM_SD_YES button with text label
pElemRef = gslc_ElemCreateBtnTxt(&m_gui,E_ELEM_SD_YES,E_PG_SD_CONFIRM,
(gslc_tsRect){170,160,80,40},(char*)"Yes",0,E_AO_NOTOMONO10PT7B,&CbBtnCommon);
gslc_ElemSetCol(&m_gui,pElemRef,GSLC_COL_RED_LT1,GSLC_COL_GRAY,GSLC_COL_RED_LT1);
m_pElemBtSDYes = pElemRef;
//<InitGUI !End!>
//<Startup !Start!>
//<Startup !End!>
}
#endif // end _GUISLICE_GEN_H

View file

@ -0,0 +1,40 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* \file
* \brief Define block driver.
*/
#ifndef BlockDriver_h
#define BlockDriver_h
#include "FatLib/BaseBlockDriver.h"
#include "SdCard/SdSpiCard.h"
//-----------------------------------------------------------------------------
/** typedef for BlockDriver */
#if ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
typedef BaseBlockDriver BlockDriver;
#else // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
typedef SdSpiCard BlockDriver;
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
#endif // BlockDriver_h

View file

@ -0,0 +1,249 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* \file
* \brief PrintFile class
*/
#ifndef ArduinoFiles_h
#define ArduinoFiles_h
#include "FatLibConfig.h"
#if ENABLE_ARDUINO_FEATURES
#include "FatFile.h"
#include <limits.h>
//------------------------------------------------------------------------------
/** Arduino SD.h style flag for open for read. */
#define FILE_READ O_RDONLY
/** Arduino SD.h style flag for open at EOF for read/write with create. */
#define FILE_WRITE (O_RDWR | O_CREAT | O_AT_END)
//==============================================================================
/**
* \class PrintFile
* \brief FatFile with Print.
*/
class PrintFile : public FatFile, public Print {
public:
PrintFile() {}
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of open flags. see
* FatFile::open(FatFile*, const char*, oflag_t).
*/
PrintFile(const char* path, oflag_t oflag) : FatFile(path, oflag) {}
#if DESTRUCTOR_CLOSES_FILE
~PrintFile() {}
#endif // DESTRUCTOR_CLOSES_FILE
using FatFile::clearWriteError;
using FatFile::getWriteError;
using FatFile::read;
using FatFile::write;
/** \return number of bytes available from the current position to EOF
* or INT_MAX if more than INT_MAX bytes are available.
*/
int available() {
uint32_t n = FatFile::available();
return n > INT_MAX ? INT_MAX : n;
}
/** Ensure that any bytes written to the file are saved to the SD card. */
void flush() {
FatFile::sync();
}
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int peek() {
return FatFile::peek();
}
/** Read the next byte from a file.
*
* \return For success return the next byte in the file as an int.
* If an error occurs or end of file is reached return -1.
*/
// int read() {
// return FatFile::read();
// }
/** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written.
* Use getWriteError to check for errors.
* \return 1 for success and 0 for failure.
*/
size_t write(uint8_t b) {
return FatFile::write(b);
}
/** Write data to an open file. Form required by Print.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] size Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an
* I/O error.
*/
size_t write(const uint8_t *buf, size_t size) {
return FatFile::write(buf, size);
}
};
//==============================================================================
/**
* \class File
* \brief Arduino SD.h style File API
*/
class File : public FatFile, public Stream {
public:
File() {}
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of open flags. see
* FatFile::open(FatFile*, const char*, oflag_t).
*/
File(const char* path, oflag_t oflag) {
open(path, oflag);
}
using FatFile::clearWriteError;
using FatFile::getWriteError;
using FatFile::read;
using FatFile::write;
/** The parenthesis operator.
*
* \return true if a file is open.
*/
operator bool() {
return isOpen();
}
/** \return number of bytes available from the current position to EOF
* or INT_MAX if more than INT_MAX bytes are available.
*/
int available() {
uint32_t n = FatFile::available();
return n > INT_MAX ? INT_MAX : n;
}
/** Ensure that any bytes written to the file are saved to the SD card. */
void flush() {
FatFile::sync();
}
/** This function reports if the current file is a directory or not.
* \return true if the file is a directory.
*/
bool isDirectory() {
return isDir();
}
/** No longer implemented due to Long File Names.
*
* Use getName(char* name, size_t size).
* \return a pointer to replacement suggestion.
*/
const char* name() const {
return "use getName()";
}
/** Return the next available byte without consuming it.
*
* \return The byte if no error and not at eof else -1;
*/
int peek() {
return FatFile::peek();
}
/** \return the current file position. */
uint32_t position() {
return curPosition();
}
/** Opens the next file or folder in a directory.
*
* \param[in] oflag open oflag flags.
* \return a File object.
*/
File openNextFile(oflag_t oflag = O_RDONLY) {
File tmpFile;
tmpFile.openNext(this, oflag);
return tmpFile;
}
/** Read the next byte from a file.
*
* \return For success return the next byte in the file as an int.
* If an error occurs or end of file is reached return -1.
*/
int read() {
return FatFile::read();
}
/** Rewind a file if it is a directory */
void rewindDirectory() {
if (isDir()) {
rewind();
}
}
/**
* Seek to a new position in the file, which must be between
* 0 and the size of the file (inclusive).
*
* \param[in] pos the new file position.
* \return true for success else false.
*/
bool seek(uint32_t pos) {
return seekSet(pos);
}
/** \return the file's size. */
uint32_t size() {
return fileSize();
}
/** Write a byte to a file. Required by the Arduino Print class.
* \param[in] b the byte to be written.
* Use getWriteError to check for errors.
* \return 1 for success and 0 for failure.
*/
size_t write(uint8_t b) {
return FatFile::write(b);
}
/** Write data to an open file. Form required by Print.
*
* \note Data is moved to the cache but may not be written to the
* storage device until sync() is called.
*
* \param[in] buf Pointer to the location of the data to be written.
*
* \param[in] size Number of bytes to write.
*
* \return For success write() returns the number of bytes written, always
* \a nbyte. If an error occurs, write() returns -1. Possible errors
* include write() is called before a file has been opened, write is called
* for a read-only file, device is full, a corrupt file system or an
* I/O error.
*/
size_t write(const uint8_t *buf, size_t size) {
return FatFile::write(buf, size);
}
};
#endif // ENABLE_ARDUINO_FEATURES
#endif // ArduinoFiles_h

View file

@ -0,0 +1,153 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ArduinoStream_h
#define ArduinoStream_h
/**
* \file
* \brief ArduinoInStream and ArduinoOutStream classes
*/
#include "FatLibConfig.h"
#if ENABLE_ARDUINO_FEATURES
#include "bufstream.h"
//==============================================================================
/**
* \class ArduinoInStream
* \brief Input stream for Arduino Stream objects
*/
class ArduinoInStream : public ibufstream {
public:
/**
* Constructor
* \param[in] hws hardware stream
* \param[in] buf buffer for input line
* \param[in] size size of input buffer
*/
ArduinoInStream(Stream &hws, char* buf, size_t size) {
m_hw = &hws;
m_line = buf;
m_size = size;
}
/** read a line. */
void readline() {
size_t i = 0;
uint32_t t;
m_line[0] = '\0';
while (!m_hw->available()) {
yield();
}
while (1) {
t = millis();
while (!m_hw->available()) {
if ((millis() - t) > 10) {
goto done;
}
}
if (i >= (m_size - 1)) {
setstate(failbit);
return;
}
m_line[i++] = m_hw->read();
m_line[i] = '\0';
}
done:
init(m_line);
}
protected:
/** Internal - do not use.
* \param[in] off
* \param[in] way
* \return true/false.
*/
bool seekoff(off_type off, seekdir way) {
(void)off;
(void)way;
return false;
}
/** Internal - do not use.
* \param[in] pos
* \return true/false.
*/
bool seekpos(pos_type pos) {
(void)pos;
return false;
}
private:
char *m_line;
size_t m_size;
Stream* m_hw;
};
//==============================================================================
/**
* \class ArduinoOutStream
* \brief Output stream for Arduino Print objects
*/
class ArduinoOutStream : public ostream {
public:
/** constructor
*
* \param[in] pr Print object for this ArduinoOutStream.
*/
explicit ArduinoOutStream(Print& pr) : m_pr(&pr) {}
protected:
/// @cond SHOW_PROTECTED
/**
* Internal do not use
* \param[in] c
*/
void putch(char c) {
if (c == '\n') {
m_pr->write('\r');
}
m_pr->write(c);
}
void putstr(const char* str) {
m_pr->write(str);
}
bool seekoff(off_type off, seekdir way) {
(void)off;
(void)way;
return false;
}
bool seekpos(pos_type pos) {
(void)pos;
return false;
}
bool sync() {
return true;
}
pos_type tellpos() {
return 0;
}
/// @endcond
private:
ArduinoOutStream() {}
Print* m_pr;
};
#endif // ENABLE_ARDUINO_FEATURES
#endif // ArduinoStream_h

View file

@ -0,0 +1,80 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef BaseBlockDriver_h
#define BaseBlockDriver_h
#include "FatLibConfig.h"
/**
* \class BaseBlockDriver
* \brief Base block driver.
*/
class BaseBlockDriver {
public:
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool readBlock(uint32_t block, uint8_t* dst) = 0;
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool syncBlocks() = 0;
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool writeBlock(uint32_t block, const uint8_t* src) = 0;
#if USE_MULTI_BLOCK_IO
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) = 0;
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
virtual bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) = 0;
#endif // USE_MULTI_BLOCK_IO
};
#endif // BaseBlockDriver_h

View file

@ -0,0 +1,87 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatApiConstants_h
#define FatApiConstants_h
#include "../SdFatConfig.h"
#if USE_FCNTL_H
#include <fcntl.h>
/* values for GNU Arm Embedded Toolchain.
* O_RDONLY: 0x0
* O_WRONLY: 0x1
* O_RDWR: 0x2
* O_ACCMODE: 0x3
* O_APPEND: 0x8
* O_CREAT: 0x200
* O_TRUNC: 0x400
* O_EXCL: 0x800
* O_SYNC: 0x2000
* O_NONBLOCK: 0x4000
*/
/** Use O_NONBLOCK for open at EOF */
#define O_AT_END O_NONBLOCK ///< Open at EOF.
typedef int oflag_t;
#else // USE_FCNTL_H
#define O_RDONLY 0X00 ///< Open for reading only.
#define O_WRONLY 0X01 ///< Open for writing only.
#define O_RDWR 0X02 ///< Open for reading and writing.
#define O_AT_END 0X04 ///< Open at EOF.
#define O_APPEND 0X08 ///< Set append mode.
#define O_CREAT 0x10 ///< Create file if it does not exist.
#define O_TRUNC 0x20 ///< Truncate file to zero length.
#define O_EXCL 0x40 ///< Fail if the file exists.
#define O_SYNC 0x80 ///< Synchronized write I/O operations.
#define O_ACCMODE (O_RDONLY|O_WRONLY|O_RDWR) ///< Mask for access mode.
typedef uint8_t oflag_t;
#endif // USE_FCNTL_H
#define O_READ O_RDONLY
#define O_WRITE O_WRONLY
inline bool isWriteMode(oflag_t oflag) {
oflag &= O_ACCMODE;
return oflag == O_WRONLY || oflag == O_RDWR;
}
// FatFile class static and const definitions
// flags for ls()
/** ls() flag for list all files including hidden. */
#define LS_A 1
/** ls() flag to print modify. date */
#define LS_DATE 2
/** ls() flag to print file size. */
#define LS_SIZE 4
/** ls() flag for recursive list of subdirectories */
#define LS_R 8
// flags for timestamp
/** set the file's last access date */
#define T_ACCESS 1
/** set the file's creation date and time */
#define T_CREATE 2
/** Set the file's write date and time */
#define T_WRITE 4
#endif // FatApiConstants_h

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,685 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "FatFile.h"
//------------------------------------------------------------------------------
//
uint8_t FatFile::lfnChecksum(uint8_t* name) {
uint8_t sum = 0;
for (uint8_t i = 0; i < 11; i++) {
sum = (((sum & 1) << 7) | ((sum & 0xfe) >> 1)) + name[i];
}
return sum;
}
#if USE_LONG_FILE_NAMES
//------------------------------------------------------------------------------
// Saves about 90 bytes of flash on 328 over tolower().
inline char lfnToLower(char c) {
return 'A' <= c && c <= 'Z' ? c + 'a' - 'A' : c;
}
//------------------------------------------------------------------------------
// Daniel Bernstein University of Illinois at Chicago.
// Original had + instead of ^
static uint16_t Bernstein(uint16_t hash, const char *str, size_t len) {
for (size_t i = 0; i < len; i++) {
// hash = hash * 33 ^ str[i];
hash = ((hash << 5) + hash) ^ str[i];
}
return hash;
}
//------------------------------------------------------------------------------
/**
* Fetch a 16-bit long file name character.
*
* \param[in] ldir Pointer to long file name directory entry.
* \param[in] i Index of character.
* \return The 16-bit character.
*/
static uint16_t lfnGetChar(ldir_t *ldir, uint8_t i) {
if (i < LDIR_NAME1_DIM) {
return ldir->name1[i];
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
return ldir->name2[i - LDIR_NAME1_DIM];
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
return ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM];
}
return 0;
}
//------------------------------------------------------------------------------
static bool lfnGetName(ldir_t *ldir, char* name, size_t n) {
uint8_t i;
size_t k = 13*((ldir->ord & 0X1F) - 1);
for (i = 0; i < 13; i++) {
uint16_t c = lfnGetChar(ldir, i);
if (c == 0 || k >= n) {
break;
}
name[k++] = c >= 0X7F ? '?' : c;
}
// Terminate with zero byte if name fits.
if (k < n && (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY)) {
name[k] = 0;
}
// Truncate if name is too long.
name[n - 1] = 0;
return true;
}
//------------------------------------------------------------------------------
inline bool lfnLegalChar(char c) {
if (c == '/' || c == '\\' || c == '"' || c == '*' ||
c == ':' || c == '<' || c == '>' || c == '?' || c == '|') {
return false;
}
return 0X1F < c && c < 0X7F;
}
//------------------------------------------------------------------------------
/**
* Store a 16-bit long file name character.
*
* \param[in] ldir Pointer to long file name directory entry.
* \param[in] i Index of character.
* \param[in] c The 16-bit character.
*/
static void lfnPutChar(ldir_t *ldir, uint8_t i, uint16_t c) {
if (i < LDIR_NAME1_DIM) {
ldir->name1[i] = c;
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM)) {
ldir->name2[i - LDIR_NAME1_DIM] = c;
} else if (i < (LDIR_NAME1_DIM + LDIR_NAME2_DIM + LDIR_NAME2_DIM)) {
ldir->name3[i - LDIR_NAME1_DIM - LDIR_NAME2_DIM] = c;
}
}
//------------------------------------------------------------------------------
static void lfnPutName(ldir_t *ldir, const char* name, size_t n) {
size_t k = 13*((ldir->ord & 0X1F) - 1);
for (uint8_t i = 0; i < 13; i++, k++) {
uint16_t c = k < n ? name[k] : k == n ? 0 : 0XFFFF;
lfnPutChar(ldir, i, c);
}
}
//==============================================================================
bool FatFile::getName(char* name, size_t size) {
FatFile dirFile;
ldir_t* ldir;
if (!isOpen() || size < 13) {
DBG_FAIL_MACRO;
goto fail;
}
if (!isLFN()) {
return getSFN(name);
}
if (!dirFile.openCluster(this)) {
DBG_FAIL_MACRO;
goto fail;
}
for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
DBG_FAIL_MACRO;
goto fail;
}
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->attr != DIR_ATT_LONG_NAME) {
DBG_FAIL_MACRO;
goto fail;
}
if (ord != (ldir->ord & 0X1F)) {
DBG_FAIL_MACRO;
goto fail;
}
if (!lfnGetName(ldir, name, size)) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
return true;
}
}
// Fall into fail.
DBG_FAIL_MACRO;
fail:
name[0] = 0;
return false;
}
//------------------------------------------------------------------------------
bool FatFile::openCluster(FatFile* file) {
if (file->m_dirCluster == 0) {
return openRoot(file->m_vol);
}
memset(this, 0, sizeof(FatFile));
m_attr = FILE_ATTR_SUBDIR;
m_flags = F_READ;
m_vol = file->m_vol;
m_firstCluster = file->m_dirCluster;
return true;
}
//------------------------------------------------------------------------------
bool FatFile::parsePathName(const char* path,
fname_t* fname, const char** ptr) {
char c;
bool is83;
uint8_t bit = DIR_NT_LC_BASE;
uint8_t lc = 0;
uint8_t uc = 0;
uint8_t i = 0;
uint8_t in = 7;
int end;
int len = 0;
int si;
int dot;
// Skip leading spaces.
while (*path == ' ') {
path++;
}
fname->lfn = path;
for (len = 0; ; len++) {
c = path[len];
if (c == 0 || isDirSeparator(c)) {
break;
}
if (!lfnLegalChar(c)) {
return false;
}
}
// Advance to next path component.
for (end = len; path[end] == ' ' || isDirSeparator(path[end]); end++) {}
*ptr = &path[end];
// Back over spaces and dots.
while (len) {
c = path[len - 1];
if (c != '.' && c != ' ') {
break;
}
len--;
}
// Max length of LFN is 255.
if (len > 255) {
return false;
}
fname->len = len;
// Blank file short name.
for (uint8_t k = 0; k < 11; k++) {
fname->sfn[k] = ' ';
}
// skip leading spaces and dots.
for (si = 0; path[si] == '.' || path[si] == ' '; si++) {}
// Not 8.3 if leading dot or space.
is83 = !si;
// find last dot.
for (dot = len - 1; dot >= 0 && path[dot] != '.'; dot--) {}
for (; si < len; si++) {
c = path[si];
if (c == ' ' || (c == '.' && dot != si)) {
is83 = false;
continue;
}
if (!legal83Char(c) && si != dot) {
is83 = false;
c = '_';
}
if (si == dot || i > in) {
if (in == 10) {
// Done - extension longer than three characters.
is83 = false;
break;
}
if (si != dot) {
is83 = false;
}
// Break if no dot and base-name is longer than eight characters.
if (si > dot) {
break;
}
si = dot;
in = 10; // Max index for full 8.3 name.
i = 8; // Place for extension.
bit = DIR_NT_LC_EXT; // bit for extension.
} else {
if ('a' <= c && c <= 'z') {
c += 'A' - 'a';
lc |= bit;
} else if ('A' <= c && c <= 'Z') {
uc |= bit;
}
fname->sfn[i++] = c;
if (i < 7) {
fname->seqPos = i;
}
}
}
if (fname->sfn[0] == ' ') {
return false;
}
if (is83) {
fname->flags = lc & uc ? FNAME_FLAG_MIXED_CASE : lc;
} else {
fname->flags = FNAME_FLAG_LOST_CHARS;
fname->sfn[fname->seqPos] = '~';
fname->sfn[fname->seqPos + 1] = '1';
}
return true;
}
//------------------------------------------------------------------------------
bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
bool fnameFound = false;
uint8_t lfnOrd = 0;
uint8_t freeNeed;
uint8_t freeFound = 0;
uint8_t ord = 0;
uint8_t chksum = 0;
uint16_t freeIndex = 0;
uint16_t curIndex;
dir_t* dir;
ldir_t* ldir;
size_t len = fname->len;
if (!dirFile || !dirFile->isDir() || isOpen()) {
DBG_FAIL_MACRO;
goto fail;
}
// Number of directory entries needed.
freeNeed = fname->flags & FNAME_FLAG_NEED_LFN ? 1 + (len + 12)/13 : 1;
dirFile->rewind();
while (1) {
curIndex = dirFile->m_curPosition/32;
dir = dirFile->readDirCache(true);
if (!dir) {
if (dirFile->getError()) {
DBG_FAIL_MACRO;
goto fail;
}
// At EOF
goto create;
}
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == DIR_NAME_FREE) {
if (freeFound == 0) {
freeIndex = curIndex;
}
if (freeFound < freeNeed) {
freeFound++;
}
if (dir->name[0] == DIR_NAME_FREE) {
goto create;
}
} else {
if (freeFound < freeNeed) {
freeFound = 0;
}
}
// skip empty slot or '.' or '..'
if (dir->name[0] == DIR_NAME_DELETED || dir->name[0] == '.') {
lfnOrd = 0;
} else if (DIR_IS_LONG_NAME(dir)) {
ldir_t *ldir = reinterpret_cast<ldir_t*>(dir);
if (!lfnOrd) {
if ((ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) == 0) {
continue;
}
lfnOrd = ord = ldir->ord & 0X1F;
chksum = ldir->chksum;
} else if (ldir->ord != --ord || chksum != ldir->chksum) {
lfnOrd = 0;
continue;
}
size_t k = 13*(ord - 1);
if (k >= len) {
// Not found.
lfnOrd = 0;
continue;
}
for (uint8_t i = 0; i < 13; i++) {
uint16_t u = lfnGetChar(ldir, i);
if (k == len) {
if (u != 0) {
// Not found.
lfnOrd = 0;
}
break;
}
if (u > 255 || lfnToLower(u) != lfnToLower(fname->lfn[k++])) {
// Not found.
lfnOrd = 0;
break;
}
}
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
if (lfnOrd) {
if (1 == ord && lfnChecksum(dir->name) == chksum) {
goto found;
}
DBG_FAIL_MACRO;
goto fail;
}
if (!memcmp(dir->name, fname->sfn, sizeof(fname->sfn))) {
if (!(fname->flags & FNAME_FLAG_LOST_CHARS)) {
goto found;
}
fnameFound = true;
}
} else {
lfnOrd = 0;
}
}
found:
// Don't open if create only.
if (oflag & O_EXCL) {
DBG_FAIL_MACRO;
goto fail;
}
goto open;
create:
// don't create unless O_CREAT and write mode.
if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
DBG_FAIL_MACRO;
goto fail;
}
// If at EOF start in next cluster.
if (freeFound == 0) {
freeIndex = curIndex;
}
while (freeFound < freeNeed) {
dir = dirFile->readDirCache();
if (!dir) {
if (dirFile->getError()) {
DBG_FAIL_MACRO;
goto fail;
}
// EOF if no error.
break;
}
freeFound++;
}
while (freeFound < freeNeed) {
// Will fail if FAT16 root.
if (!dirFile->addDirCluster()) {
DBG_FAIL_MACRO;
goto fail;
}
// Done if more than one block per cluster. Max freeNeed is 21.
if (dirFile->m_vol->blocksPerCluster() > 1) {
break;
}
freeFound += 16;
}
if (fnameFound) {
if (!dirFile->lfnUniqueSfn(fname)) {
goto fail;
}
}
if (!dirFile->seekSet(32UL*freeIndex)) {
DBG_FAIL_MACRO;
goto fail;
}
lfnOrd = freeNeed - 1;
for (uint8_t ord = lfnOrd ; ord ; ord--) {
ldir = reinterpret_cast<ldir_t*>(dirFile->readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
dirFile->m_vol->cacheDirty();
ldir->ord = ord == lfnOrd ? LDIR_ORD_LAST_LONG_ENTRY | ord : ord;
ldir->attr = DIR_ATT_LONG_NAME;
ldir->type = 0;
ldir->chksum = lfnChecksum(fname->sfn);
ldir->mustBeZero = 0;
lfnPutName(ldir, fname->lfn, len);
}
curIndex = dirFile->m_curPosition/32;
dir = dirFile->readDirCache();
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// initialize as empty file
memset(dir, 0, sizeof(dir_t));
memcpy(dir->name, fname->sfn, 11);
// Set base-name and extension lower case bits.
dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;
// set timestamps
if (m_dateTime) {
// call user date/time function
m_dateTime(&dir->creationDate, &dir->creationTime);
} else {
// use default date/time
dir->creationDate = FAT_DEFAULT_DATE;
dir->creationTime = FAT_DEFAULT_TIME;
}
dir->lastAccessDate = dir->creationDate;
dir->lastWriteDate = dir->creationDate;
dir->lastWriteTime = dir->creationTime;
// Force write of entry to device.
dirFile->m_vol->cacheDirty();
open:
// open entry in cache.
if (!openCachedEntry(dirFile, curIndex, oflag, lfnOrd)) {
DBG_FAIL_MACRO;
goto fail;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printName(print_t* pr) {
FatFile dirFile;
ldir_t* ldir;
size_t n = 0;
uint16_t u;
uint8_t buf[13];
uint8_t i;
if (!isLFN()) {
return printSFN(pr);
}
if (!dirFile.openCluster(this)) {
DBG_FAIL_MACRO;
goto fail;
}
for (uint8_t ord = 1; ord <= m_lfnOrd; ord++) {
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
DBG_FAIL_MACRO;
goto fail;
}
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->attr != DIR_ATT_LONG_NAME ||
ord != (ldir->ord & 0X1F)) {
DBG_FAIL_MACRO;
goto fail;
}
for (i = 0; i < 13; i++) {
u = lfnGetChar(ldir, i);
if (u == 0) {
// End of name.
break;
}
buf[i] = u < 0X7F ? u : '?';
n++;
}
pr->write(buf, i);
}
return n;
fail:
return 0;
}
//------------------------------------------------------------------------------
bool FatFile::remove() {
bool last;
uint8_t chksum;
uint8_t ord;
FatFile dirFile;
dir_t* dir;
ldir_t* ldir;
// Cant' remove not open for write.
if (!isFile() || !(m_flags & F_WRITE)) {
DBG_FAIL_MACRO;
goto fail;
}
// Free any clusters.
if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// Cache directory entry.
dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
chksum = lfnChecksum(dir->name);
// Mark entry deleted.
dir->name[0] = DIR_NAME_DELETED;
// Set this file closed.
m_attr = FILE_ATTR_CLOSED;
// Write entry to device.
if (!m_vol->cacheSync()) {
DBG_FAIL_MACRO;
goto fail;
}
if (!isLFN()) {
// Done, no LFN entries.
return true;
}
if (!dirFile.openCluster(this)) {
DBG_FAIL_MACRO;
goto fail;
}
for (ord = 1; ord <= m_lfnOrd; ord++) {
if (!dirFile.seekSet(32UL*(m_dirIndex - ord))) {
DBG_FAIL_MACRO;
goto fail;
}
ldir = reinterpret_cast<ldir_t*>(dirFile.readDirCache());
if (!ldir) {
DBG_FAIL_MACRO;
goto fail;
}
if (ldir->attr != DIR_ATT_LONG_NAME ||
ord != (ldir->ord & 0X1F) ||
chksum != ldir->chksum) {
DBG_FAIL_MACRO;
goto fail;
}
last = ldir->ord & LDIR_ORD_LAST_LONG_ENTRY;
ldir->ord = DIR_NAME_DELETED;
m_vol->cacheDirty();
if (last) {
if (!m_vol->cacheSync()) {
DBG_FAIL_MACRO;
goto fail;
}
return true;
}
}
// Fall into fail.
DBG_FAIL_MACRO;
fail:
return false;
}
//------------------------------------------------------------------------------
bool FatFile::lfnUniqueSfn(fname_t* fname) {
const uint8_t FIRST_HASH_SEQ = 2; // min value is 2
uint8_t pos = fname->seqPos;;
dir_t *dir;
uint16_t hex;
DBG_HALT_IF(!(fname->flags & FNAME_FLAG_LOST_CHARS));
DBG_HALT_IF(fname->sfn[pos] != '~' && fname->sfn[pos + 1] != '1');
for (uint8_t seq = 2; seq < 100; seq++) {
if (seq < FIRST_HASH_SEQ) {
fname->sfn[pos + 1] = '0' + seq;
} else {
DBG_PRINT_IF(seq > FIRST_HASH_SEQ);
hex = Bernstein(seq + fname->len, fname->lfn, fname->len);
if (pos > 3) {
// Make space in name for ~HHHH.
pos = 3;
}
for (uint8_t i = pos + 4 ; i > pos; i--) {
uint8_t h = hex & 0XF;
fname->sfn[i] = h < 10 ? h + '0' : h + 'A' - 10;
hex >>= 4;
}
}
fname->sfn[pos] = '~';
rewind();
while (1) {
dir = readDirCache(true);
if (!dir) {
if (!getError()) {
// At EOF and name not found if no error.
goto done;
}
DBG_FAIL_MACRO;
goto fail;
}
if (dir->name[0] == DIR_NAME_FREE) {
goto done;
}
if (DIR_IS_FILE_OR_SUBDIR(dir) && !memcmp(fname->sfn, dir->name, 11)) {
// Name found - try another.
break;
}
}
}
// fall inti fail - too many tries.
DBG_FAIL_MACRO;
fail:
return false;
done:
return true;
}
#endif // #if USE_LONG_FILE_NAMES

View file

@ -0,0 +1,267 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <math.h>
#include "FatFile.h"
#include "FmtNumber.h"
//------------------------------------------------------------------------------
// print uint8_t with width 2
static void print2u(print_t* pr, uint8_t v) {
char c0 = '?';
char c1 = '?';
if (v < 100) {
c1 = v/10;
c0 = v - 10*c1 + '0';
c1 += '0';
}
pr->write(c1);
pr->write(c0);
}
//------------------------------------------------------------------------------
static void printU32(print_t* pr, uint32_t v) {
char buf[11];
char* ptr = buf + sizeof(buf);
*--ptr = 0;
pr->write(fmtDec(v, ptr));
}
//------------------------------------------------------------------------------
static void printHex(print_t* pr, uint8_t w, uint16_t h) {
char buf[5];
char* ptr = buf + sizeof(buf);
*--ptr = 0;
for (uint8_t i = 0; i < w; i++) {
char c = h & 0XF;
*--ptr = c < 10 ? c + '0' : c + 'A' - 10;
h >>= 4;
}
pr->write(ptr);
}
//------------------------------------------------------------------------------
void FatFile::dmpFile(print_t* pr, uint32_t pos, size_t n) {
char text[17];
text[16] = 0;
if (n >= 0XFFF0) {
n = 0XFFF0;
}
if (!seekSet(pos)) {
return;
}
for (size_t i = 0; i <= n; i++) {
if ((i & 15) == 0) {
if (i) {
pr->write(' ');
pr->write(text);
if (i == n) {
break;
}
}
pr->write('\r');
pr->write('\n');
if (i >= n) {
break;
}
printHex(pr, 4, i);
pr->write(' ');
}
int16_t h = read();
if (h < 0) {
break;
}
pr->write(' ');
printHex(pr, 2, h);
text[i&15] = ' ' <= h && h < 0X7F ? h : '.';
}
pr->write('\r');
pr->write('\n');
}
//------------------------------------------------------------------------------
bool FatFile::ls(print_t* pr, uint8_t flags, uint8_t indent) {
FatFile file;
if (!isDir() || getError()) {
DBG_FAIL_MACRO;
goto fail;
}
rewind();
while (file.openNext(this, O_RDONLY)) {
if (!file.isHidden() || (flags & LS_A)) {
// indent for dir level
for (uint8_t i = 0; i < indent; i++) {
pr->write(' ');
}
if (flags & LS_DATE) {
file.printModifyDateTime(pr);
pr->write(' ');
}
if (flags & LS_SIZE) {
file.printFileSize(pr);
pr->write(' ');
}
file.printName(pr);
if (file.isDir()) {
pr->write('/');
}
pr->write('\r');
pr->write('\n');
if ((flags & LS_R) && file.isDir()) {
if (!file.ls(pr, flags, indent + 2)) {
DBG_FAIL_MACRO;
goto fail;
}
}
}
file.close();
}
if (getError()) {
DBG_FAIL_MACRO;
goto fail;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool FatFile::printCreateDateTime(print_t* pr) {
dir_t dir;
if (!dirEntry(&dir)) {
DBG_FAIL_MACRO;
goto fail;
}
printFatDate(pr, dir.creationDate);
pr->write(' ');
printFatTime(pr, dir.creationTime);
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
void FatFile::printFatDate(print_t* pr, uint16_t fatDate) {
printU32(pr, FAT_YEAR(fatDate));
pr->write('-');
print2u(pr, FAT_MONTH(fatDate));
pr->write('-');
print2u(pr, FAT_DAY(fatDate));
}
//------------------------------------------------------------------------------
void FatFile::printFatTime(print_t* pr, uint16_t fatTime) {
print2u(pr, FAT_HOUR(fatTime));
pr->write(':');
print2u(pr, FAT_MINUTE(fatTime));
pr->write(':');
print2u(pr, FAT_SECOND(fatTime));
}
//------------------------------------------------------------------------------
/** Template for FatFile::printField() */
template <typename Type>
static int printFieldT(FatFile* file, char sign, Type value, char term) {
char buf[3*sizeof(Type) + 3];
char* str = &buf[sizeof(buf)];
if (term) {
*--str = term;
if (term == '\n') {
*--str = '\r';
}
}
#ifdef OLD_FMT
do {
Type m = value;
value /= 10;
*--str = '0' + m - 10*value;
} while (value);
#else // OLD_FMT
str = fmtDec(value, str);
#endif // OLD_FMT
if (sign) {
*--str = sign;
}
return file->write(str, &buf[sizeof(buf)] - str);
}
//------------------------------------------------------------------------------
int FatFile::printField(float value, char term, uint8_t prec) {
char buf[24];
char* str = &buf[sizeof(buf)];
if (term) {
*--str = term;
if (term == '\n') {
*--str = '\r';
}
}
str = fmtFloat(value, str, prec);
return write(str, buf + sizeof(buf) - str);
}
//------------------------------------------------------------------------------
int FatFile::printField(uint16_t value, char term) {
return printFieldT(this, 0, value, term);
}
//------------------------------------------------------------------------------
int FatFile::printField(int16_t value, char term) {
char sign = 0;
if (value < 0) {
sign = '-';
value = -value;
}
return printFieldT(this, sign, (uint16_t)value, term);
}
//------------------------------------------------------------------------------
int FatFile::printField(uint32_t value, char term) {
return printFieldT(this, 0, value, term);
}
//------------------------------------------------------------------------------
int FatFile::printField(int32_t value, char term) {
char sign = 0;
if (value < 0) {
sign = '-';
value = -value;
}
return printFieldT(this, sign, (uint32_t)value, term);
}
//------------------------------------------------------------------------------
bool FatFile::printModifyDateTime(print_t* pr) {
dir_t dir;
if (!dirEntry(&dir)) {
DBG_FAIL_MACRO;
goto fail;
}
printFatDate(pr, dir.lastWriteDate);
pr->write(' ');
printFatTime(pr, dir.lastWriteTime);
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printFileSize(print_t* pr) {
char buf[11];
char *ptr = buf + sizeof(buf);
*--ptr = 0;
ptr = fmtDec(fileSize(), ptr);
while (ptr > buf) {
*--ptr = ' ';
}
return pr->write(buf);
}

View file

@ -0,0 +1,278 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "FatFile.h"
#include "FatFileSystem.h"
//------------------------------------------------------------------------------
bool FatFile::getSFN(char* name) {
dir_t* dir;
if (!isOpen()) {
DBG_FAIL_MACRO;
goto fail;
}
if (isRoot()) {
name[0] = '/';
name[1] = '\0';
return true;
}
// cache entry
dir = cacheDirEntry(FatCache::CACHE_FOR_READ);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// format name
dirName(dir, name);
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printSFN(print_t* pr) {
char name[13];
if (!getSFN(name)) {
DBG_FAIL_MACRO;
goto fail;
}
return pr->write(name);
fail:
return 0;
}
#if !USE_LONG_FILE_NAMES
//------------------------------------------------------------------------------
bool FatFile::getName(char* name, size_t size) {
return size < 13 ? 0 : getSFN(name);
}
//------------------------------------------------------------------------------
// format directory name field from a 8.3 name string
bool FatFile::parsePathName(const char* path, fname_t* fname,
const char** ptr) {
uint8_t uc = 0;
uint8_t lc = 0;
uint8_t bit = FNAME_FLAG_LC_BASE;
// blank fill name and extension
for (uint8_t i = 0; i < 11; i++) {
fname->sfn[i] = ' ';
}
for (uint8_t i = 0, n = 7;; path++) {
uint8_t c = *path;
if (c == 0 || isDirSeparator(c)) {
// Done.
break;
}
if (c == '.' && n == 7) {
n = 10; // max index for full 8.3 name
i = 8; // place for extension
// bit for extension.
bit = FNAME_FLAG_LC_EXT;
} else {
if (!legal83Char(c) || i > n) {
DBG_FAIL_MACRO;
goto fail;
}
if ('a' <= c && c <= 'z') {
c += 'A' - 'a';
lc |= bit;
} else if ('A' <= c && c <= 'Z') {
uc |= bit;
}
fname->sfn[i++] = c;
}
}
// must have a file name, extension is optional
if (fname->sfn[0] == ' ') {
DBG_FAIL_MACRO;
goto fail;
}
// Set base-name and extension bits.
fname->flags = lc & uc ? 0 : lc;
while (isDirSeparator(*path)) {
path++;
}
*ptr = path;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// open with filename in fname
#define SFN_OPEN_USES_CHKSUM 0
bool FatFile::open(FatFile* dirFile, fname_t* fname, oflag_t oflag) {
bool emptyFound = false;
#if SFN_OPEN_USES_CHKSUM
uint8_t chksum;
#endif
uint8_t lfnOrd = 0;
uint16_t emptyIndex;
uint16_t index = 0;
dir_t* dir;
ldir_t* ldir;
dirFile->rewind();
while (1) {
if (!emptyFound) {
emptyIndex = index;
}
dir = dirFile->readDirCache(true);
if (!dir) {
if (dirFile->getError()) {
DBG_FAIL_MACRO;
goto fail;
}
// At EOF if no error.
break;
}
if (dir->name[0] == DIR_NAME_FREE) {
emptyFound = true;
break;
}
if (dir->name[0] == DIR_NAME_DELETED) {
lfnOrd = 0;
emptyFound = true;
} else if (DIR_IS_FILE_OR_SUBDIR(dir)) {
if (!memcmp(fname->sfn, dir->name, 11)) {
// don't open existing file if O_EXCL
if (oflag & O_EXCL) {
DBG_FAIL_MACRO;
goto fail;
}
#if SFN_OPEN_USES_CHKSUM
if (lfnOrd && chksum != lfnChecksum(dir->name)) {
DBG_FAIL_MACRO;
goto fail;
}
#endif // SFN_OPEN_USES_CHKSUM
if (!openCachedEntry(dirFile, index, oflag, lfnOrd)) {
DBG_FAIL_MACRO;
goto fail;
}
return true;
} else {
lfnOrd = 0;
}
} else if (DIR_IS_LONG_NAME(dir)) {
ldir = reinterpret_cast<ldir_t*>(dir);
if (ldir->ord & LDIR_ORD_LAST_LONG_ENTRY) {
lfnOrd = ldir->ord & 0X1F;
#if SFN_OPEN_USES_CHKSUM
chksum = ldir->chksum;
#endif // SFN_OPEN_USES_CHKSUM
}
} else {
lfnOrd = 0;
}
index++;
}
// don't create unless O_CREAT and write mode
if (!(oflag & O_CREAT) || !isWriteMode(oflag)) {
DBG_FAIL_MACRO;
goto fail;
}
if (emptyFound) {
index = emptyIndex;
} else {
if (!dirFile->addDirCluster()) {
DBG_FAIL_MACRO;
goto fail;
}
}
if (!dirFile->seekSet(32UL*index)) {
DBG_FAIL_MACRO;
goto fail;
}
dir = dirFile->readDirCache();
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// initialize as empty file
memset(dir, 0, sizeof(dir_t));
memcpy(dir->name, fname->sfn, 11);
// Set base-name and extension lower case bits.
dir->reservedNT = (DIR_NT_LC_BASE | DIR_NT_LC_EXT) & fname->flags;
// set timestamps
if (m_dateTime) {
// call user date/time function
m_dateTime(&dir->creationDate, &dir->creationTime);
} else {
// use default date/time
dir->creationDate = FAT_DEFAULT_DATE;
dir->creationTime = FAT_DEFAULT_TIME;
}
dir->lastAccessDate = dir->creationDate;
dir->lastWriteDate = dir->creationDate;
dir->lastWriteTime = dir->creationTime;
// Force write of entry to device.
dirFile->m_vol->cacheDirty();
// open entry in cache.
return openCachedEntry(dirFile, index, oflag, 0);
fail:
return false;
}
//------------------------------------------------------------------------------
size_t FatFile::printName(print_t* pr) {
return printSFN(pr);
}
//------------------------------------------------------------------------------
bool FatFile::remove() {
dir_t* dir;
// Can't remove if LFN or not open for write.
if (!isFile() || isLFN() || !(m_flags & F_WRITE)) {
DBG_FAIL_MACRO;
goto fail;
}
// Free any clusters.
if (m_firstCluster && !m_vol->freeChain(m_firstCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// Cache directory entry.
dir = cacheDirEntry(FatCache::CACHE_FOR_WRITE);
if (!dir) {
DBG_FAIL_MACRO;
goto fail;
}
// Mark entry deleted.
dir->name[0] = DIR_NAME_DELETED;
// Set this file closed.
m_attr = FILE_ATTR_CLOSED;
// Write entry to device.
return m_vol->cacheSync();
fail:
return false;
}
#endif // !USE_LONG_FILE_NAMES

View file

@ -0,0 +1,332 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatFileSystem_h
#define FatFileSystem_h
#include "FatVolume.h"
#include "FatFile.h"
#include "ArduinoFiles.h"
/**
* \file
* \brief FatFileSystem class
*/
//------------------------------------------------------------------------------
/**
* \class FatFileSystem
* \brief Integration class for the FatLib library.
*/
class FatFileSystem : public FatVolume {
public:
/**
* Initialize an FatFileSystem object.
* \param[in] blockDev Device block driver.
* \param[in] part partition to initialize.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin(BlockDriver* blockDev, uint8_t part = 0) {
m_blockDev = blockDev;
vwd()->close();
return (part ? init(part) : init(1) || init(0))
&& vwd()->openRoot(this) && FatFile::setCwd(vwd());
}
#if ENABLE_ARDUINO_FEATURES
/** List the directory contents of the volume working directory to Serial.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \return true for success or false if an error occurred.
*/
bool ls(uint8_t flags = 0) {
return ls(&Serial, flags);
}
/** List the directory contents of a directory to Serial.
*
* \param[in] path directory to list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \return true for success or false if an error occurred.
*/
bool ls(const char* path, uint8_t flags = 0) {
return ls(&Serial, path, flags);
}
/** open a file
*
* \param[in] path location of file to be opened.
* \param[in] oflag open flags.
* \return a File object.
*/
File open(const char *path, oflag_t oflag = FILE_READ) {
File tmpFile;
tmpFile.open(vwd(), path, oflag);
return tmpFile;
}
/** open a file
*
* \param[in] path location of file to be opened.
* \param[in] oflag open flags.
* \return a File object.
*/
File open(const String &path, oflag_t oflag = FILE_READ) {
return open(path.c_str(), oflag );
}
#endif // ENABLE_ARDUINO_FEATURES
/** Change a volume's working directory to root
*
* Changes the volume's working directory to the SD's root directory.
* Optionally set the current working directory to the volume's
* working directory.
*
* \param[in] set_cwd Set the current working directory to this volume's
* working directory if true.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool chdir(bool set_cwd = false) {
vwd()->close();
return vwd()->openRoot(this) && (set_cwd ? FatFile::setCwd(vwd()) : true);
}
/** Change a volume's working directory
*
* Changes the volume working directory to the \a path subdirectory.
* Optionally set the current working directory to the volume's
* working directory.
*
* Example: If the volume's working directory is "/DIR", chdir("SUB")
* will change the volume's working directory from "/DIR" to "/DIR/SUB".
*
* If path is "/", the volume's working directory will be changed to the
* root directory
*
* \param[in] path The name of the subdirectory.
*
* \param[in] set_cwd Set the current working directory to this volume's
* working directory if true.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
//----------------------------------------------------------------------------
bool chdir(const char *path, bool set_cwd = false) {
FatFile dir;
if (path[0] == '/' && path[1] == '\0') {
return chdir(set_cwd);
}
if (!dir.open(vwd(), path, O_RDONLY)) {
goto fail;
}
if (!dir.isDir()) {
goto fail;
}
m_vwd = dir;
if (set_cwd) {
FatFile::setCwd(vwd());
}
return true;
fail:
return false;
}
//----------------------------------------------------------------------------
/** Set the current working directory to a volume's working directory.
*
* This is useful with multiple SD cards.
*
* The current working directory is changed to this
* volume's working directory.
*
* This is like the Windows/DOS \<drive letter>: command.
*/
void chvol() {
FatFile::setCwd(vwd());
}
//----------------------------------------------------------------------------
/**
* Test for the existence of a file.
*
* \param[in] path Path of the file to be tested for.
*
* \return true if the file exists else false.
*/
bool exists(const char* path) {
return vwd()->exists(path);
}
//----------------------------------------------------------------------------
/** List the directory contents of the volume working directory.
*
* \param[in] pr Print stream for list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \return true for success or false if an error occurred.
*/
bool ls(print_t* pr, uint8_t flags = 0) {
return vwd()->ls(pr, flags);
}
//----------------------------------------------------------------------------
/** List the directory contents of a directory.
*
* \param[in] pr Print stream for list.
*
* \param[in] path directory to list.
*
* \param[in] flags The inclusive OR of
*
* LS_DATE - %Print file modification date
*
* LS_SIZE - %Print file size.
*
* LS_R - Recursive list of subdirectories.
*
* \return true for success or false if an error occurred.
*/
bool ls(print_t* pr, const char* path, uint8_t flags) {
FatFile dir;
return dir.open(vwd(), path, O_RDONLY) && dir.ls(pr, flags);
}
//----------------------------------------------------------------------------
/** Make a subdirectory in the volume working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
*
* \param[in] pFlag Create missing parent directories if true.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool mkdir(const char* path, bool pFlag = true) {
FatFile sub;
return sub.mkdir(vwd(), path, pFlag);
}
//----------------------------------------------------------------------------
/** Remove a file from the volume working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the file.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool remove(const char* path) {
return FatFile::remove(vwd(), path);
}
//----------------------------------------------------------------------------
/** Rename a file or subdirectory.
*
* \param[in] oldPath Path name to the file or subdirectory to be renamed.
*
* \param[in] newPath New path name of the file or subdirectory.
*
* The \a newPath object must not exist before the rename call.
*
* The file to be renamed must not be open. The directory entry may be
* moved and file system corruption could occur if the file is accessed by
* a file object that was opened before the rename() call.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rename(const char *oldPath, const char *newPath) {
FatFile file;
if (!file.open(vwd(), oldPath, O_RDONLY)) {
return false;
}
return file.rename(vwd(), newPath);
}
//----------------------------------------------------------------------------
/** Remove a subdirectory from the volume's working directory.
*
* \param[in] path A path with a valid 8.3 DOS name for the subdirectory.
*
* The subdirectory file will be removed only if it is empty.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool rmdir(const char* path) {
FatFile sub;
if (!sub.open(vwd(), path, O_RDONLY)) {
return false;
}
return sub.rmdir();
}
//----------------------------------------------------------------------------
/** Truncate a file to a specified length. The current file position
* will be maintained if it is less than or equal to \a length otherwise
* it will be set to end of file.
*
* \param[in] path A path with a valid 8.3 DOS name for the file.
* \param[in] length The desired length for the file.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool truncate(const char* path, uint32_t length) {
FatFile file;
if (!file.open(vwd(), path, O_WRONLY)) {
return false;
}
return file.truncate(length);
}
/** \return a pointer to the FatVolume object. */
FatVolume* vol() {
return this;
}
/** \return a pointer to the volume working directory. */
FatFile* vwd() {
return &m_vwd;
}
/** Wipe all data from the volume. You must reinitialize the volume before
* accessing it again.
* \param[in] pr print stream for status dots.
* \return true for success else false.
*/
bool wipe(print_t* pr = 0) {
vwd()->close();
return FatVolume::wipe(pr);
}
private:
FatFile m_vwd;
};
#endif // FatFileSystem_h

View file

@ -0,0 +1,36 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatLib_h
#define FatLib_h
#include "ArduinoFiles.h"
#include "FatFileSystem.h"
#include "FatLibConfig.h"
#include "FatVolume.h"
#include "FatFile.h"
#include "StdioStream.h"
//------------------------------------------------------------------------------
/** FatFileSystem version YYYYMMDD */
#define FAT_LIB_VERSION 20150131
#endif // FatLib_h

View file

@ -0,0 +1,146 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* \file
* \brief configuration definitions
*/
#ifndef FatLibConfig_h
#define FatLibConfig_h
#include <stdint.h>
// Allow this file to override defaults.
#include "../SdFatConfig.h"
#ifdef __AVR__
#include <avr/io.h>
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN).
* Long File Name are limited to a maximum length of 255 characters.
*
* This implementation allows 7-bit characters in the range
* 0X20 to 0X7E. The following characters are not allowed:
*
* < (less than)
* > (greater than)
* : (colon)
* " (double quote)
* / (forward slash)
* \ (backslash)
* | (vertical bar or pipe)
* ? (question mark)
* * (asterisk)
*
*/
#ifndef USE_LONG_FILE_NAMES
#define USE_LONG_FILE_NAMES 1
#endif // USE_LONG_FILE_NAMES
//------------------------------------------------------------------------------
/**
* Set USE_SEPARATE_FAT_CACHE non-zero to use a second 512 byte cache
* for FAT table entries. Improves performance for large writes that
* are not a multiple of 512 bytes.
*/
#ifndef USE_SEPARATE_FAT_CACHE
#ifdef __arm__
#define USE_SEPARATE_FAT_CACHE 1
#else // __arm__
#define USE_SEPARATE_FAT_CACHE 0
#endif // __arm__
#endif // USE_SEPARATE_FAT_CACHE
//------------------------------------------------------------------------------
/**
* Set USE_MULTI_BLOCK_IO non-zero to use multi-block SD read/write.
*
* Don't use mult-block read/write on small AVR boards.
*/
#ifndef USE_MULTI_BLOCK_IO
#if defined(RAMEND) && RAMEND < 3000
#define USE_MULTI_BLOCK_IO 0
#else // RAMEND
#define USE_MULTI_BLOCK_IO 1
#endif // RAMEND
#endif // USE_MULTI_BLOCK_IO
//------------------------------------------------------------------------------
/**
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
* updated. This will increase the speed of the freeClusterCount() call
* after the first call. Extra flash will be required.
*/
#ifndef MAINTAIN_FREE_CLUSTER_COUNT
#define MAINTAIN_FREE_CLUSTER_COUNT 0
#endif // MAINTAIN_FREE_CLUSTER_COUNT
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE non-zero to close a file in its destructor.
*
* Causes use of lots of heap in ARM.
*/
#ifndef DESTRUCTOR_CLOSES_FILE
#define DESTRUCTOR_CLOSES_FILE 0
#endif // DESTRUCTOR_CLOSES_FILE
//------------------------------------------------------------------------------
/**
* Call flush for endl if ENDL_CALLS_FLUSH is non-zero
*
* The standard for iostreams is to call flush. This is very costly for
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
*
* SdFat has a single 512 byte buffer for I/O so it must write the current
* data block to the SD, read the directory block from the SD, update the
* directory entry, write the directory block to the SD and read the data
* block back into the buffer.
*
* The SD flash memory controller is not designed for this many rewrites
* so performance may be reduced by more than a factor of 100.
*
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
* all data to be written to the SD.
*/
#ifndef ENDL_CALLS_FLUSH
#define ENDL_CALLS_FLUSH 0
#endif // ENDL_CALLS_FLUSH
//------------------------------------------------------------------------------
/**
* Allow FAT12 volumes if FAT12_SUPPORT is non-zero.
* FAT12 has not been well tested.
*/
#ifndef FAT12_SUPPORT
#define FAT12_SUPPORT 0
#endif // FAT12_SUPPORT
//------------------------------------------------------------------------------
/**
* Enable Extra features for Arduino.
*/
// #define ENABLE_ARDUINO_FEATURES 0 ////////////////////////FIX THIS /////////////////
#ifndef ENABLE_ARDUINO_FEATURES
#include <Arduino.h>
#if defined(ARDUINO) || defined(PLATFORM_ID) || defined(DOXYGEN)
#define ENABLE_ARDUINO_FEATURES 1
#else // #if defined(ARDUINO) || defined(DOXYGEN)
#define ENABLE_ARDUINO_FEATURES 0
#endif // defined(ARDUINO) || defined(DOXYGEN)
#endif // ENABLE_ARDUINO_FEATURES
#endif // FatLibConfig_h

View file

@ -0,0 +1,882 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatStructs_h
#define FatStructs_h
/**
* \file
* \brief FAT file structures
*/
/*
* mostly from Microsoft document fatgen103.doc
* http://www.microsoft.com/whdc/system/platform/firmware/fatgen.mspx
*/
//------------------------------------------------------------------------------
/** Value for byte 510 of boot block or MBR */
const uint8_t BOOTSIG0 = 0X55;
/** Value for byte 511 of boot block or MBR */
const uint8_t BOOTSIG1 = 0XAA;
/** Value for bootSignature field int FAT/FAT32 boot sector */
const uint8_t EXTENDED_BOOT_SIG = 0X29;
//------------------------------------------------------------------------------
/**
* \struct partitionTable
* \brief MBR partition table entry
*
* A partition table entry for a MBR formatted storage device.
* The MBR partition table has four entries.
*/
struct partitionTable {
/**
* Boot Indicator . Indicates whether the volume is the active
* partition. Legal values include: 0X00. Do not use for booting.
* 0X80 Active partition.
*/
uint8_t boot;
/**
* Head part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t beginHead;
/**
* Sector part of Cylinder-head-sector address of the first block in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned beginSector : 6;
/** High bits cylinder for first block in partition. */
unsigned beginCylinderHigh : 2;
/**
* Combine beginCylinderLow with beginCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t beginCylinderLow;
/**
* Partition type. See defines that begin with PART_TYPE_ for
* some Microsoft partition types.
*/
uint8_t type;
/**
* head part of cylinder-head-sector address of the last sector in the
* partition. Legal values are 0-255. Only used in old PC BIOS.
*/
uint8_t endHead;
/**
* Sector part of cylinder-head-sector address of the last sector in
* the partition. Legal values are 1-63. Only used in old PC BIOS.
*/
unsigned endSector : 6;
/** High bits of end cylinder */
unsigned endCylinderHigh : 2;
/**
* Combine endCylinderLow with endCylinderHigh. Legal values
* are 0-1023. Only used in old PC BIOS.
*/
uint8_t endCylinderLow;
/** Logical block address of the first block in the partition. */
uint32_t firstSector;
/** Length of the partition, in blocks. */
uint32_t totalSectors;
} __attribute__((packed));
/** Type name for partitionTable */
typedef struct partitionTable part_t;
//------------------------------------------------------------------------------
/**
* \struct masterBootRecord
*
* \brief Master Boot Record
*
* The first block of a storage device that is formatted with a MBR.
*/
struct masterBootRecord {
/** Code Area for master boot program. */
uint8_t codeArea[440];
/** Optional Windows NT disk signature. May contain boot code. */
uint32_t diskSignature;
/** Usually zero but may be more boot code. */
uint16_t usuallyZero;
/** Partition tables. */
part_t part[4];
/** First MBR signature byte. Must be 0X55 */
uint8_t mbrSig0;
/** Second MBR signature byte. Must be 0XAA */
uint8_t mbrSig1;
} __attribute__((packed));
/** Type name for masterBootRecord */
typedef struct masterBootRecord mbr_t;
//------------------------------------------------------------------------------
/**
* \struct biosParmBlock
*
* \brief BIOS parameter block
*
* The BIOS parameter block describes the physical layout of a FAT volume.
*/
struct biosParmBlock {
/**
* Count of bytes per sector. This value may take on only the
* following values: 512, 1024, 2048 or 4096
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128.
*/
uint8_t sectorsPerCluster;
/**
* Number of sectors before the first FAT.
* This value must not be zero.
*/
uint16_t reservedSectorCount;
/** The count of FAT data structures on the volume. This field should
* always contain the value 2 for any FAT volume of any type.
*/
uint8_t fatCount;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t rootDirEntryCount;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be nonzero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (nonremovable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrtack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be nonzero.
*/
uint32_t totalSectors32;
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
uint32_t sectorsPerFat32;
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced in bits 0-3.
* Bits 8-15 -- Reserved.
*/
uint16_t fat32Flags;
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
uint16_t fat32Version;
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
uint32_t fat32RootCluster;
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
uint16_t fat32FSInfo;
/**
* If nonzero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
uint16_t fat32BackBootBlock;
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
uint8_t fat32Reserved[12];
} __attribute__((packed));
/** Type name for biosParmBlock */
typedef struct biosParmBlock bpb_t;
//------------------------------------------------------------------------------
/**
* \struct fat_boot
*
* \brief Boot sector for a FAT12/FAT16 volume.
*
*/
struct fat_boot {
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next non-executable bytes.
*/
uint8_t jump[3];
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
char oemId[8];
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
*/
uint8_t sectorsPerCluster;
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. The value of this field is always 1.
*/
uint16_t reservedSectorCount;
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
uint8_t fatCount;
/**
* For FAT12 and FAT16 volumes, this field contains the count of
* 32-byte directory entries in the root directory. For FAT32 volumes,
* this field must be set to 0. For FAT12 and FAT16 volumes, this
* value should always specify a count that when multiplied by 32
* results in a multiple of bytesPerSector. FAT16 volumes should
* use the value 512.
*/
uint16_t rootDirEntryCount;
/**
* This field is the old 16-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then totalSectors32
* must be non-zero. For FAT32 volumes, this field must be 0. For
* FAT12 and FAT16 volumes, this field contains the sector count, and
* totalSectors32 is 0 if the total sector count fits
* (is less than 0x10000).
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* Count of sectors occupied by one FAT on FAT12/FAT16 volumes.
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* This field is the new 32-bit total count of sectors on the volume.
* This count includes the count of all sectors in all four regions
* of the volume. This field can be 0; if it is 0, then
* totalSectors16 must be non-zero.
*/
uint32_t totalSectors32;
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
uint32_t volumeSerialNumber;
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
char volumeLabel[11];
/**
* A field with a value of either FAT, FAT12 or FAT16,
* depending on the disk format.
*/
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[448];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
} __attribute__((packed));
/** Type name for FAT Boot Sector */
typedef struct fat_boot fat_boot_t;
//------------------------------------------------------------------------------
/**
* \struct fat32_boot
*
* \brief Boot sector for a FAT32 volume.
*
*/
struct fat32_boot {
/**
* The first three bytes of the boot sector must be valid,
* executable x 86-based CPU instructions. This includes a
* jump instruction that skips the next non-executable bytes.
*/
uint8_t jump[3];
/**
* This is typically a string of characters that identifies
* the operating system that formatted the volume.
*/
char oemId[8];
/**
* The size of a hardware sector. Valid decimal values for this
* field are 512, 1024, 2048, and 4096. For most disks used in
* the United States, the value of this field is 512.
*/
uint16_t bytesPerSector;
/**
* Number of sectors per allocation unit. This value must be a
* power of 2 that is greater than 0. The legal values are
* 1, 2, 4, 8, 16, 32, 64, and 128. 128 should be avoided.
*/
uint8_t sectorsPerCluster;
/**
* The number of sectors preceding the start of the first FAT,
* including the boot sector. Must not be zero
*/
uint16_t reservedSectorCount;
/**
* The number of copies of the FAT on the volume.
* The value of this field is always 2.
*/
uint8_t fatCount;
/**
* FAT12/FAT16 only. For FAT32 volumes, this field must be set to 0.
*/
uint16_t rootDirEntryCount;
/**
* For FAT32 volumes, this field must be 0.
*/
uint16_t totalSectors16;
/**
* This dates back to the old MS-DOS 1.x media determination and is
* no longer usually used for anything. 0xF8 is the standard value
* for fixed (non-removable) media. For removable media, 0xF0 is
* frequently used. Legal values are 0xF0 or 0xF8-0xFF.
*/
uint8_t mediaType;
/**
* On FAT32 volumes this field must be 0, and sectorsPerFat32
* contains the FAT size count.
*/
uint16_t sectorsPerFat16;
/** Sectors per track for interrupt 0x13. Not used otherwise. */
uint16_t sectorsPerTrack;
/** Number of heads for interrupt 0x13. Not used otherwise. */
uint16_t headCount;
/**
* Count of hidden sectors preceding the partition that contains this
* FAT volume. This field is generally only relevant for media
* visible on interrupt 0x13.
*/
uint32_t hidddenSectors;
/**
* Contains the total number of sectors in the FAT32 volume.
*/
uint32_t totalSectors32;
/**
* Count of sectors occupied by one FAT on FAT32 volumes.
*/
uint32_t sectorsPerFat32;
/**
* This field is only defined for FAT32 media and does not exist on
* FAT12 and FAT16 media.
* Bits 0-3 -- Zero-based number of active FAT.
* Only valid if mirroring is disabled.
* Bits 4-6 -- Reserved.
* Bit 7 -- 0 means the FAT is mirrored at runtime into all FATs.
* -- 1 means only one FAT is active; it is the one referenced
* in bits 0-3.
* Bits 8-15 -- Reserved.
*/
uint16_t fat32Flags;
/**
* FAT32 version. High byte is major revision number.
* Low byte is minor revision number. Only 0.0 define.
*/
uint16_t fat32Version;
/**
* Cluster number of the first cluster of the root directory for FAT32.
* This usually 2 but not required to be 2.
*/
uint32_t fat32RootCluster;
/**
* Sector number of FSINFO structure in the reserved area of the
* FAT32 volume. Usually 1.
*/
uint16_t fat32FSInfo;
/**
* If non-zero, indicates the sector number in the reserved area
* of the volume of a copy of the boot record. Usually 6.
* No value other than 6 is recommended.
*/
uint16_t fat32BackBootBlock;
/**
* Reserved for future expansion. Code that formats FAT32 volumes
* should always set all of the bytes of this field to 0.
*/
uint8_t fat32Reserved[12];
/**
* Related to the BIOS physical drive number. Floppy drives are
* identified as 0x00 and physical hard disks are identified as
* 0x80, regardless of the number of physical disk drives.
* Typically, this value is set prior to issuing an INT 13h BIOS
* call to specify the device to access. The value is only
* relevant if the device is a boot device.
*/
uint8_t driveNumber;
/** used by Windows NT - should be zero for FAT */
uint8_t reserved1;
/** 0X29 if next three fields are valid */
uint8_t bootSignature;
/**
* A random serial number created when formatting a disk,
* which helps to distinguish between disks.
* Usually generated by combining date and time.
*/
uint32_t volumeSerialNumber;
/**
* A field once used to store the volume label. The volume label
* is now stored as a special file in the root directory.
*/
char volumeLabel[11];
/**
* A text field with a value of FAT32.
*/
char fileSystemType[8];
/** X86 boot code */
uint8_t bootCode[420];
/** must be 0X55 */
uint8_t bootSectorSig0;
/** must be 0XAA */
uint8_t bootSectorSig1;
} __attribute__((packed));
/** Type name for FAT32 Boot Sector */
typedef struct fat32_boot fat32_boot_t;
//------------------------------------------------------------------------------
/** Lead signature for a FSINFO sector */
const uint32_t FSINFO_LEAD_SIG = 0x41615252;
/** Struct signature for a FSINFO sector */
const uint32_t FSINFO_STRUCT_SIG = 0x61417272;
/**
* \struct fat32_fsinfo
*
* \brief FSINFO sector for a FAT32 volume.
*
*/
struct fat32_fsinfo {
/** must be 0X52, 0X52, 0X61, 0X41 */
uint32_t leadSignature;
/** must be zero */
uint8_t reserved1[480];
/** must be 0X72, 0X72, 0X41, 0X61 */
uint32_t structSignature;
/**
* Contains the last known free cluster count on the volume.
* If the value is 0xFFFFFFFF, then the free count is unknown
* and must be computed. Any other value can be used, but is
* not necessarily correct. It should be range checked at least
* to make sure it is <= volume cluster count.
*/
uint32_t freeCount;
/**
* This is a hint for the FAT driver. It indicates the cluster
* number at which the driver should start looking for free clusters.
* If the value is 0xFFFFFFFF, then there is no hint and the driver
* should start looking at cluster 2.
*/
uint32_t nextFree;
/** must be zero */
uint8_t reserved2[12];
/** must be 0X00, 0X00, 0X55, 0XAA */
uint8_t tailSignature[4];
} __attribute__((packed));
/** Type name for FAT32 FSINFO Sector */
typedef struct fat32_fsinfo fat32_fsinfo_t;
//------------------------------------------------------------------------------
// End Of Chain values for FAT entries
/** FAT12 end of chain value used by Microsoft. */
const uint16_t FAT12EOC = 0XFFF;
/** Minimum value for FAT12 EOC. Use to test for EOC. */
const uint16_t FAT12EOC_MIN = 0XFF8;
/** FAT16 end of chain value used by Microsoft. */
const uint16_t FAT16EOC = 0XFFFF;
/** Minimum value for FAT16 EOC. Use to test for EOC. */
const uint16_t FAT16EOC_MIN = 0XFFF8;
/** FAT32 end of chain value used by Microsoft. */
const uint32_t FAT32EOC = 0X0FFFFFFF;
/** Minimum value for FAT32 EOC. Use to test for EOC. */
const uint32_t FAT32EOC_MIN = 0X0FFFFFF8;
/** Mask a for FAT32 entry. Entries are 28 bits. */
const uint32_t FAT32MASK = 0X0FFFFFFF;
//------------------------------------------------------------------------------
/**
* \struct directoryEntry
* \brief FAT short directory entry
*
* Short means short 8.3 name, not the entry size.
*
* Date Format. A FAT directory entry date stamp is a 16-bit field that is
* basically a date relative to the MS-DOS epoch of 01/01/1980. Here is the
* format (bit 0 is the LSB of the 16-bit word, bit 15 is the MSB of the
* 16-bit word):
*
* Bits 9-15: Count of years from 1980, valid value range 0-127
* inclusive (1980-2107).
*
* Bits 5-8: Month of year, 1 = January, valid value range 1-12 inclusive.
*
* Bits 0-4: Day of month, valid value range 1-31 inclusive.
*
* Time Format. A FAT directory entry time stamp is a 16-bit field that has
* a granularity of 2 seconds. Here is the format (bit 0 is the LSB of the
* 16-bit word, bit 15 is the MSB of the 16-bit word).
*
* Bits 11-15: Hours, valid value range 0-23 inclusive.
*
* Bits 5-10: Minutes, valid value range 0-59 inclusive.
*
* Bits 0-4: 2-second count, valid value range 0-29 inclusive (0 - 58 seconds).
*
* The valid time range is from Midnight 00:00:00 to 23:59:58.
*/
struct directoryEntry {
/** Short 8.3 name.
*
* The first eight bytes contain the file name with blank fill.
* The last three bytes contain the file extension with blank fill.
*/
uint8_t name[11];
/** Entry attributes.
*
* The upper two bits of the attribute byte are reserved and should
* always be set to 0 when a file is created and never modified or
* looked at after that. See defines that begin with DIR_ATT_.
*/
uint8_t attributes;
/**
* Reserved for use by Windows NT. Set value to 0 when a file is
* created and never modify or look at it after that.
*/
uint8_t reservedNT;
/**
* The granularity of the seconds part of creationTime is 2 seconds
* so this field is a count of tenths of a second and its valid
* value range is 0-199 inclusive. (WHG note - seems to be hundredths)
*/
uint8_t creationTimeTenths;
/** Time file was created. */
uint16_t creationTime;
/** Date file was created. */
uint16_t creationDate;
/**
* Last access date. Note that there is no last access time, only
* a date. This is the date of last read or write. In the case of
* a write, this should be set to the same date as lastWriteDate.
*/
uint16_t lastAccessDate;
/**
* High word of this entry's first cluster number (always 0 for a
* FAT12 or FAT16 volume).
*/
uint16_t firstClusterHigh;
/** Time of last write. File creation is considered a write. */
uint16_t lastWriteTime;
/** Date of last write. File creation is considered a write. */
uint16_t lastWriteDate;
/** Low word of this entry's first cluster number. */
uint16_t firstClusterLow;
/** 32-bit unsigned holding this file's size in bytes. */
uint32_t fileSize;
} __attribute__((packed));
/** Type name for directoryEntry */
typedef struct directoryEntry dir_t;
//------------------------------------------------------------------------------
// Definitions for directory entries
//
/** escape for name[0] = 0XE5 */
const uint8_t DIR_NAME_0XE5 = 0X05;
/** name[0] value for entry that is free after being "deleted" */
const uint8_t DIR_NAME_DELETED = 0XE5;
/** name[0] value for entry that is free and no allocated entries follow */
const uint8_t DIR_NAME_FREE = 0X00;
/** file is read-only */
const uint8_t DIR_ATT_READ_ONLY = 0X01;
/** File should e hidden in directory listings */
const uint8_t DIR_ATT_HIDDEN = 0X02;
/** Entry is for a system file */
const uint8_t DIR_ATT_SYSTEM = 0X04;
/** Directory entry contains the volume label */
const uint8_t DIR_ATT_VOLUME_ID = 0X08;
/** Entry is for a directory */
const uint8_t DIR_ATT_DIRECTORY = 0X10;
/** Old DOS archive bit for backup support */
const uint8_t DIR_ATT_ARCHIVE = 0X20;
/** Test value for long name entry. Test is
(d->attributes & DIR_ATT_LONG_NAME_MASK) == DIR_ATT_LONG_NAME. */
const uint8_t DIR_ATT_LONG_NAME = 0X0F;
/** Test mask for long name entry */
const uint8_t DIR_ATT_LONG_NAME_MASK = 0X3F;
/** defined attribute bits */
const uint8_t DIR_ATT_DEFINED_BITS = 0X3F;
/** Mask for file/subdirectory tests */
const uint8_t DIR_ATT_FILE_TYPE_MASK = (DIR_ATT_VOLUME_ID | DIR_ATT_DIRECTORY);
/** Filename base-name is all lower case */
const uint8_t DIR_NT_LC_BASE = 0X08;
/** Filename extension is all lower case.*/
const uint8_t DIR_NT_LC_EXT = 0X10;
/** Directory entry is for a file
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file else false.
*/
static inline uint8_t DIR_IS_FILE(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == 0;
}
/** Directory entry is for a file or subdirectory
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a normal file or subdirectory else false.
*/
static inline uint8_t DIR_IS_FILE_OR_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_VOLUME_ID) == 0;
}
/** Directory entry is part of a long name
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for part of a long name else false.
*/
static inline uint8_t DIR_IS_LONG_NAME(const dir_t* dir) {
return dir->attributes == DIR_ATT_LONG_NAME;
}
/** Directory entry is hidden
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is hidden else false.
*/
static inline uint8_t DIR_IS_HIDDEN(const dir_t* dir) {
return dir->attributes & DIR_ATT_HIDDEN;
}
/** Directory entry is for a subdirectory
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is for a subdirectory else false.
*/
static inline uint8_t DIR_IS_SUBDIR(const dir_t* dir) {
return (dir->attributes & DIR_ATT_FILE_TYPE_MASK) == DIR_ATT_DIRECTORY;
}
/** Directory entry is system type
* \param[in] dir Pointer to a directory entry.
*
* \return true if the entry is system else false.
*/
static inline uint8_t DIR_IS_SYSTEM(const dir_t* dir) {
return dir->attributes & DIR_ATT_SYSTEM;
}
/** date field for FAT directory entry
* \param[in] year [1980,2107]
* \param[in] month [1,12]
* \param[in] day [1,31]
*
* \return Packed date for dir_t entry.
*/
static inline uint16_t FAT_DATE(uint16_t year, uint8_t month, uint8_t day) {
return (year - 1980) << 9 | month << 5 | day;
}
/** year part of FAT directory date field
* \param[in] fatDate Date in packed dir format.
*
* \return Extracted year [1980,2107]
*/
static inline uint16_t FAT_YEAR(uint16_t fatDate) {
return 1980 + (fatDate >> 9);
}
/** month part of FAT directory date field
* \param[in] fatDate Date in packed dir format.
*
* \return Extracted month [1,12]
*/
static inline uint8_t FAT_MONTH(uint16_t fatDate) {
return (fatDate >> 5) & 0XF;
}
/** day part of FAT directory date field
* \param[in] fatDate Date in packed dir format.
*
* \return Extracted day [1,31]
*/
static inline uint8_t FAT_DAY(uint16_t fatDate) {
return fatDate & 0X1F;
}
/** time field for FAT directory entry
* \param[in] hour [0,23]
* \param[in] minute [0,59]
* \param[in] second [0,59]
*
* \return Packed time for dir_t entry.
*/
static inline uint16_t FAT_TIME(uint8_t hour, uint8_t minute, uint8_t second) {
return hour << 11 | minute << 5 | second >> 1;
}
/** hour part of FAT directory time field
* \param[in] fatTime Time in packed dir format.
*
* \return Extracted hour [0,23]
*/
static inline uint8_t FAT_HOUR(uint16_t fatTime) {
return fatTime >> 11;
}
/** minute part of FAT directory time field
* \param[in] fatTime Time in packed dir format.
*
* \return Extracted minute [0,59]
*/
static inline uint8_t FAT_MINUTE(uint16_t fatTime) {
return (fatTime >> 5) & 0X3F;
}
/** second part of FAT directory time field
* \note second/2 is stored in packed time.
*
* \param[in] fatTime Time in packed dir format.
*
* \return Extracted second [0,58]
*/
static inline uint8_t FAT_SECOND(uint16_t fatTime) {
return 2*(fatTime & 0X1F);
}
/** Default date for file timestamps is 1 Jan 2000 */
const uint16_t FAT_DEFAULT_DATE = ((2000 - 1980) << 9) | (1 << 5) | 1;
/** Default time for file timestamp is 1 am */
const uint16_t FAT_DEFAULT_TIME = (1 << 11);
//------------------------------------------------------------------------------
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME1_DIM = 5;
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME2_DIM = 6;
/** Dimension of first name field in long directory entry */
const uint8_t LDIR_NAME3_DIM = 2;
/**
* \struct longDirectoryEntry
* \brief FAT long directory entry
*/
struct longDirectoryEntry {
/**
* The order of this entry in the sequence of long dir entries
* associated with the short dir entry at the end of the long dir set.
*
* If masked with 0X40 (LAST_LONG_ENTRY), this indicates the
* entry is the last long dir entry in a set of long dir entries.
* All valid sets of long dir entries must begin with an entry having
* this mask.
*/
uint8_t ord;
/** Characters 1-5 of the long-name sub-component in this entry. */
uint16_t name1[LDIR_NAME1_DIM];
/** Attributes - must be ATTR_LONG_NAME */
uint8_t attr;
/**
* If zero, indicates a directory entry that is a sub-component of a
* long name. NOTE: Other values reserved for future extensions.
*
* Non-zero implies other directory entry types.
*/
uint8_t type;
/**
* Checksum of name in the short dir entry at the end of the
* long dir set.
*/
uint8_t chksum;
/** Characters 6-11 of the long-name sub-component in this entry. */
uint16_t name2[LDIR_NAME2_DIM];
/** Must be ZERO. This is an artifact of the FAT "first cluster" */
uint16_t mustBeZero;
/** Characters 12 and 13 of the long-name sub-component in this entry. */
uint16_t name3[LDIR_NAME3_DIM];
} __attribute__((packed));
/** Type name for longDirectoryEntry */
typedef struct longDirectoryEntry ldir_t;
/**
* Ord mast that indicates the entry is the last long dir entry in a
* set of long dir entries. All valid sets of long dir entries must
* begin with an entry having this mask.
*/
const uint8_t LDIR_ORD_LAST_LONG_ENTRY = 0X40;
#endif // FatStructs_h

View file

@ -0,0 +1,625 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "FatVolume.h"
//------------------------------------------------------------------------------
cache_t* FatCache::read(uint32_t lbn, uint8_t option) {
if (m_lbn != lbn) {
if (!sync()) {
DBG_FAIL_MACRO;
goto fail;
}
if (!(option & CACHE_OPTION_NO_READ)) {
if (!m_vol->readBlock(lbn, m_block.data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
m_status = 0;
m_lbn = lbn;
}
m_status |= option & CACHE_STATUS_MASK;
return &m_block;
fail:
return 0;
}
//------------------------------------------------------------------------------
bool FatCache::sync() {
if (m_status & CACHE_STATUS_DIRTY) {
if (!m_vol->writeBlock(m_lbn, m_block.data)) {
DBG_FAIL_MACRO;
goto fail;
}
// mirror second FAT
if (m_status & CACHE_STATUS_MIRROR_FAT) {
uint32_t lbn = m_lbn + m_vol->blocksPerFat();
if (!m_vol->writeBlock(lbn, m_block.data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
m_status &= ~CACHE_STATUS_DIRTY;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool FatVolume::allocateCluster(uint32_t current, uint32_t* next) {
uint32_t find;
bool setStart;
if (m_allocSearchStart < current) {
// Try to keep file contiguous. Start just after current cluster.
find = current;
setStart = false;
} else {
find = m_allocSearchStart;
setStart = true;
}
while (1) {
find++;
if (find > m_lastCluster) {
if (setStart) {
// Can't find space, checked all clusters.
DBG_FAIL_MACRO;
goto fail;
}
find = m_allocSearchStart;
setStart = true;
continue;
}
if (find == current) {
// Can't find space, already searched clusters after current.
DBG_FAIL_MACRO;
goto fail;
}
uint32_t f;
int8_t fg = fatGet(find, &f);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
if (fg && f == 0) {
break;
}
}
if (setStart) {
m_allocSearchStart = find;
}
// Mark end of chain.
if (!fatPutEOC(find)) {
DBG_FAIL_MACRO;
goto fail;
}
if (current) {
// Link clusters.
if (!fatPut(current, find)) {
DBG_FAIL_MACRO;
goto fail;
}
}
updateFreeClusterCount(-1);
*next = find;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
// find a contiguous group of clusters
bool FatVolume::allocContiguous(uint32_t count,
uint32_t* firstCluster, uint32_t startCluster) {
// flag to save place to start next search
bool setStart;
// start of group
uint32_t bgnCluster;
// end of group
uint32_t endCluster;
if (startCluster != 0) {
bgnCluster = startCluster;
setStart = false;
} else {
// Start at cluster after last allocated cluster.
bgnCluster = m_allocSearchStart + 1;
setStart = true;
}
endCluster = bgnCluster;
// search the FAT for free clusters
while (1) {
if (endCluster > m_lastCluster) {
// Can't find space.
DBG_FAIL_MACRO;
goto fail;
}
uint32_t f;
int8_t fg = fatGet(endCluster, &f);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
if (f || fg == 0) {
if (startCluster) {
DBG_FAIL_MACRO;
goto fail;
}
// don't update search start if unallocated clusters before endCluster.
if (bgnCluster != endCluster) {
setStart = false;
}
// cluster in use try next cluster as bgnCluster
bgnCluster = endCluster + 1;
} else if ((endCluster - bgnCluster + 1) == count) {
// done - found space
break;
}
endCluster++;
}
// Remember possible next free cluster.
if (setStart) {
m_allocSearchStart = endCluster;
}
// mark end of chain
if (!fatPutEOC(endCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
// link clusters
while (endCluster > bgnCluster) {
if (!fatPut(endCluster - 1, endCluster)) {
DBG_FAIL_MACRO;
goto fail;
}
endCluster--;
}
// Maintain count of free clusters.
updateFreeClusterCount(-count);
// return first cluster number to caller
*firstCluster = bgnCluster;
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
uint32_t FatVolume::clusterFirstBlock(uint32_t cluster) const {
return m_dataStartBlock + ((cluster - 2) << m_clusterSizeShift);
}
//------------------------------------------------------------------------------
// Fetch a FAT entry - return -1 error, 0 EOC, else 1.
int8_t FatVolume::fatGet(uint32_t cluster, uint32_t* value) {
uint32_t lba;
uint32_t next;
cache_t* pc;
// error if reserved cluster of beyond FAT
if (cluster < 2 || cluster > m_lastCluster) {
DBG_FAIL_MACRO;
goto fail;
}
if (fatType() == 32) {
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
next = pc->fat32[cluster & 0X7F] & FAT32MASK;
goto done;
}
if (fatType() == 16) {
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
next = pc->fat16[cluster & 0XFF];
goto done;
}
if (FAT12_SUPPORT && fatType() == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = m_fatStartBlock + (index >> 9);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
index &= 0X1FF;
uint16_t tmp = pc->data[index];
index++;
if (index == 512) {
pc = cacheFetchFat(lba + 1, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
index = 0;
}
tmp |= pc->data[index] << 8;
next = cluster & 1 ? tmp >> 4 : tmp & 0XFFF;
goto done;
} else {
DBG_FAIL_MACRO;
goto fail;
}
done:
if (isEOC(next)) {
return 0;
}
*value = next;
return 1;
fail:
return -1;
}
//------------------------------------------------------------------------------
// Store a FAT entry
bool FatVolume::fatPut(uint32_t cluster, uint32_t value) {
uint32_t lba;
cache_t* pc;
// error if reserved cluster of beyond FAT
if (cluster < 2 || cluster > m_lastCluster) {
DBG_FAIL_MACRO;
goto fail;
}
if (fatType() == 32) {
lba = m_fatStartBlock + (cluster >> 7);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
pc->fat32[cluster & 0X7F] = value;
return true;
}
if (fatType() == 16) {
lba = m_fatStartBlock + ((cluster >> 8) & 0XFF);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
pc->fat16[cluster & 0XFF] = value;
return true;
}
if (FAT12_SUPPORT && fatType() == 12) {
uint16_t index = cluster;
index += index >> 1;
lba = m_fatStartBlock + (index >> 9);
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
index &= 0X1FF;
uint8_t tmp = value;
if (cluster & 1) {
tmp = (pc->data[index] & 0XF) | tmp << 4;
}
pc->data[index] = tmp;
index++;
if (index == 512) {
lba++;
index = 0;
pc = cacheFetchFat(lba, FatCache::CACHE_FOR_WRITE);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
}
tmp = value >> 4;
if (!(cluster & 1)) {
tmp = ((pc->data[index] & 0XF0)) | tmp >> 4;
}
pc->data[index] = tmp;
return true;
} else {
DBG_FAIL_MACRO;
goto fail;
}
fail:
return false;
}
//------------------------------------------------------------------------------
// free a cluster chain
bool FatVolume::freeChain(uint32_t cluster) {
uint32_t next = 0;
int8_t fg;
do {
fg = fatGet(cluster, &next);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
// free cluster
if (!fatPut(cluster, 0)) {
DBG_FAIL_MACRO;
goto fail;
}
// Add one to count of free clusters.
updateFreeClusterCount(1);
if (cluster <= m_allocSearchStart) {
m_allocSearchStart = cluster - 1;
}
cluster = next;
} while (fg);
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
int32_t FatVolume::freeClusterCount() {
#if MAINTAIN_FREE_CLUSTER_COUNT
if (m_freeClusterCount >= 0) {
return m_freeClusterCount;
}
#endif // MAINTAIN_FREE_CLUSTER_COUNT
uint32_t free = 0;
uint32_t lba;
uint32_t todo = m_lastCluster + 1;
uint16_t n;
if (FAT12_SUPPORT && fatType() == 12) {
for (unsigned i = 2; i < todo; i++) {
uint32_t c;
int8_t fg = fatGet(i, &c);
if (fg < 0) {
DBG_FAIL_MACRO;
goto fail;
}
if (fg && c == 0) {
free++;
}
}
} else if (fatType() == 16 || fatType() == 32) {
lba = m_fatStartBlock;
while (todo) {
cache_t* pc = cacheFetchFat(lba++, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
n = fatType() == 16 ? 256 : 128;
if (todo < n) {
n = todo;
}
if (fatType() == 16) {
for (uint16_t i = 0; i < n; i++) {
if (pc->fat16[i] == 0) {
free++;
}
}
} else {
for (uint16_t i = 0; i < n; i++) {
if (pc->fat32[i] == 0) {
free++;
}
}
}
todo -= n;
}
} else {
// invalid FAT type
DBG_FAIL_MACRO;
goto fail;
}
setFreeClusterCount(free);
return free;
fail:
return -1;
}
//------------------------------------------------------------------------------
bool FatVolume::init(uint8_t part) {
uint32_t clusterCount;
uint32_t totalBlocks;
uint32_t volumeStartBlock = 0;
fat32_boot_t* fbs;
cache_t* pc;
uint8_t tmp;
m_fatType = 0;
m_allocSearchStart = 1;
m_cache.init(this);
#if USE_SEPARATE_FAT_CACHE
m_fatCache.init(this);
#endif // USE_SEPARATE_FAT_CACHE
// if part == 0 assume super floppy with FAT boot sector in block zero
// if part > 0 assume mbr volume with partition table
if (part) {
if (part > 4) {
DBG_FAIL_MACRO;
goto fail;
}
pc = cacheFetchData(0, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
part_t* p = &pc->mbr.part[part - 1];
if ((p->boot & 0X7F) != 0 || p->firstSector == 0) {
// not a valid partition
DBG_FAIL_MACRO;
goto fail;
}
volumeStartBlock = p->firstSector;
}
pc = cacheFetchData(volumeStartBlock, FatCache::CACHE_FOR_READ);
if (!pc) {
DBG_FAIL_MACRO;
goto fail;
}
fbs = &(pc->fbs32);
if (fbs->bytesPerSector != 512 ||
fbs->fatCount != 2 ||
fbs->reservedSectorCount == 0) {
// not valid FAT volume
DBG_FAIL_MACRO;
goto fail;
}
m_blocksPerCluster = fbs->sectorsPerCluster;
m_clusterBlockMask = m_blocksPerCluster - 1;
// determine shift that is same as multiply by m_blocksPerCluster
m_clusterSizeShift = 0;
for (tmp = 1; m_blocksPerCluster != tmp; tmp <<= 1, m_clusterSizeShift++) {
if (tmp == 0) {
DBG_FAIL_MACRO;
goto fail;
}
}
m_blocksPerFat = fbs->sectorsPerFat16 ?
fbs->sectorsPerFat16 : fbs->sectorsPerFat32;
m_fatStartBlock = volumeStartBlock + fbs->reservedSectorCount;
// count for FAT16 zero for FAT32
m_rootDirEntryCount = fbs->rootDirEntryCount;
// directory start for FAT16 dataStart for FAT32
m_rootDirStart = m_fatStartBlock + 2 * m_blocksPerFat;
// data start for FAT16 and FAT32
m_dataStartBlock = m_rootDirStart + ((32 * fbs->rootDirEntryCount + 511)/512);
// total blocks for FAT16 or FAT32
totalBlocks = fbs->totalSectors16 ?
fbs->totalSectors16 : fbs->totalSectors32;
// total data blocks
clusterCount = totalBlocks - (m_dataStartBlock - volumeStartBlock);
// divide by cluster size to get cluster count
clusterCount >>= m_clusterSizeShift;
m_lastCluster = clusterCount + 1;
// Indicate unknown number of free clusters.
setFreeClusterCount(-1);
// FAT type is determined by cluster count
if (clusterCount < 4085) {
m_fatType = 12;
if (!FAT12_SUPPORT) {
DBG_FAIL_MACRO;
goto fail;
}
} else if (clusterCount < 65525) {
m_fatType = 16;
} else {
m_rootDirStart = fbs->fat32RootCluster;
m_fatType = 32;
}
return true;
fail:
return false;
}
//------------------------------------------------------------------------------
bool FatVolume::wipe(print_t* pr) {
cache_t* cache;
uint16_t count;
uint32_t lbn;
if (!fatType()) {
DBG_FAIL_MACRO;
goto fail;
}
cache = cacheClear();
if (!cache) {
DBG_FAIL_MACRO;
goto fail;
}
memset(cache->data, 0, 512);
// Zero root.
if (fatType() == 32) {
lbn = clusterFirstBlock(m_rootDirStart);
count = m_blocksPerCluster;
} else {
lbn = m_rootDirStart;
count = m_rootDirEntryCount/16;
}
for (uint32_t n = 0; n < count; n++) {
if (!writeBlock(lbn + n, cache->data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
// Clear FATs.
count = 2*m_blocksPerFat;
lbn = m_fatStartBlock;
for (uint32_t nb = 0; nb < count; nb++) {
if (pr && (nb & 0XFF) == 0) {
pr->write('.');
}
if (!writeBlock(lbn + nb, cache->data)) {
DBG_FAIL_MACRO;
goto fail;
}
}
// Reserve first two clusters.
if (fatType() == 32) {
cache->fat32[0] = 0x0FFFFFF8;
cache->fat32[1] = 0x0FFFFFFF;
} else if (fatType() == 16) {
cache->fat16[0] = 0XFFF8;
cache->fat16[1] = 0XFFFF;
} else if (FAT12_SUPPORT && fatType() == 12) {
cache->fat32[0] = 0XFFFFF8;
} else {
DBG_FAIL_MACRO;
goto fail;
}
if (!writeBlock(m_fatStartBlock, cache->data) ||
!writeBlock(m_fatStartBlock + m_blocksPerFat, cache->data)) {
DBG_FAIL_MACRO;
goto fail;
}
if (fatType() == 32) {
// Reserve root cluster.
if (!fatPutEOC(m_rootDirStart) || !cacheSync()) {
DBG_FAIL_MACRO;
goto fail;
}
}
if (pr) {
pr->write('\r');
pr->write('\n');
}
m_fatType = 0;
return true;
fail:
m_fatType = 0;
return false;
}

View file

@ -0,0 +1,396 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FatVolume_h
#define FatVolume_h
/**
* \file
* \brief FatVolume class
*/
#include <stddef.h>
#include "FatLibConfig.h"
#include "FatStructs.h"
#include "../BlockDriver.h"
//------------------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
/** Macro for debug. */
#define DEBUG_MODE 0
#if DEBUG_MODE
#define DBG_FAIL_MACRO Serial.print(F(__FILE__)); Serial.println(__LINE__);
#define DBG_PRINT_IF(b) if (b) {Serial.println(F(#b)); DBG_FAIL_MACRO;}
#define DBG_HALT_IF(b) if (b) {Serial.println(F(#b));\
DBG_FAIL_MACRO; while (1);}
#else // DEBUG_MODE
#define DBG_FAIL_MACRO
#define DBG_PRINT_IF(b)
#define DBG_HALT_IF(b)
#endif // DEBUG_MODE
#endif // DOXYGEN_SHOULD_SKIP_THIS
//------------------------------------------------------------------------------
#if ENABLE_ARDUINO_FEATURES
/** Use Print for Arduino */
typedef Print print_t;
#else // ENABLE_ARDUINO_FEATURES
/**
* \class CharWriter
* \brief Character output - often serial port.
*/
class CharWriter {
public:
virtual size_t write(char c) = 0;
virtual size_t write(const char* s) = 0;
};
typedef CharWriter print_t;
#endif // ENABLE_ARDUINO_FEATURES
//------------------------------------------------------------------------------
// Forward declaration of FatVolume.
class FatVolume;
//------------------------------------------------------------------------------
/**
* \brief Cache for an raw data block.
*/
union cache_t {
/** Used to access cached file data blocks. */
uint8_t data[512];
/** Used to access cached FAT16 entries. */
uint16_t fat16[256];
/** Used to access cached FAT32 entries. */
uint32_t fat32[128];
/** Used to access cached directory entries. */
dir_t dir[16];
/** Used to access a cached Master Boot Record. */
mbr_t mbr;
/** Used to access to a cached FAT boot sector. */
fat_boot_t fbs;
/** Used to access to a cached FAT32 boot sector. */
fat32_boot_t fbs32;
/** Used to access to a cached FAT32 FSINFO sector. */
fat32_fsinfo_t fsinfo;
};
//==============================================================================
/**
* \class FatCache
* \brief Block cache.
*/
class FatCache {
public:
/** Cached block is dirty */
static const uint8_t CACHE_STATUS_DIRTY = 1;
/** Cashed block is FAT entry and must be mirrored in second FAT. */
static const uint8_t CACHE_STATUS_MIRROR_FAT = 2;
/** Cache block status bits */
static const uint8_t CACHE_STATUS_MASK
= CACHE_STATUS_DIRTY | CACHE_STATUS_MIRROR_FAT;
/** Sync existing block but do not read new block. */
static const uint8_t CACHE_OPTION_NO_READ = 4;
/** Cache block for read. */
static const uint8_t CACHE_FOR_READ = 0;
/** Cache block for write. */
static const uint8_t CACHE_FOR_WRITE = CACHE_STATUS_DIRTY;
/** Reserve cache block for write - do not read from block device. */
static const uint8_t CACHE_RESERVE_FOR_WRITE
= CACHE_STATUS_DIRTY | CACHE_OPTION_NO_READ;
/** \return Cache block address. */
cache_t* block() {
return &m_block;
}
/** Set current block dirty. */
void dirty() {
m_status |= CACHE_STATUS_DIRTY;
}
/** Initialize the cache.
* \param[in] vol FatVolume that owns this FatCache.
*/
void init(FatVolume *vol) {
m_vol = vol;
invalidate();
}
/** Invalidate current cache block. */
void invalidate() {
m_status = 0;
m_lbn = 0XFFFFFFFF;
}
/** \return dirty status */
bool isDirty() {
return m_status & CACHE_STATUS_DIRTY;
}
/** \return Logical block number for cached block. */
uint32_t lbn() {
return m_lbn;
}
/** Read a block into the cache.
* \param[in] lbn Block to read.
* \param[in] option mode for cached block.
* \return Address of cached block. */
cache_t* read(uint32_t lbn, uint8_t option);
/** Write current block if dirty.
* \return true for success else false.
*/
bool sync();
private:
uint8_t m_status;
FatVolume* m_vol;
uint32_t m_lbn;
cache_t m_block;
};
//==============================================================================
/**
* \class FatVolume
* \brief Access FAT16 and FAT32 volumes on raw file devices.
*/
class FatVolume {
public:
/** Create an instance of FatVolume
*/
FatVolume() : m_fatType(0) {}
/** \return The volume's cluster size in blocks. */
uint8_t blocksPerCluster() const {
return m_blocksPerCluster;
}
/** \return The number of blocks in one FAT. */
uint32_t blocksPerFat() const {
return m_blocksPerFat;
}
/** Clear the cache and returns a pointer to the cache. Not for normal apps.
* \return A pointer to the cache buffer or zero if an error occurs.
*/
cache_t* cacheClear() {
if (!cacheSync()) {
return 0;
}
m_cache.invalidate();
return m_cache.block();
}
/** \return The total number of clusters in the volume. */
uint32_t clusterCount() const {
return m_lastCluster - 1;
}
/** \return The shift count required to multiply by blocksPerCluster. */
uint8_t clusterSizeShift() const {
return m_clusterSizeShift;
}
/** \return The logical block number for the start of file data. */
uint32_t dataStartBlock() const {
return m_dataStartBlock;
}
/** \return The sector number for the start of file data. */
uint32_t dataStartSector() const {
return m_dataStartBlock;
}
/** \return The number of File Allocation Tables. */
uint8_t fatCount() {
return 2;
}
/** \return The logical block number for the start of the first FAT. */
uint32_t fatStartBlock() const {
return m_fatStartBlock;
}
/** \return The sector number for the start of the first FAT. */
uint32_t fatStartSector() const {
return m_fatStartBlock;
}
/** \return The FAT type of the volume. Values are 12, 16 or 32. */
uint8_t fatType() const {
return m_fatType;
}
/** Volume free space in clusters.
*
* \return Count of free clusters for success or -1 if an error occurs.
*/
int32_t freeClusterCount();
/** Initialize a FAT volume. Try partition one first then try super
* floppy format.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool init() {
return init(1) || init(0);
}
/** Initialize a FAT volume.
* \param[in] part The partition to be used. Legal values for \a part are
* 1-4 to use the corresponding partition on a device formatted with
* a MBR, Master Boot Record, or zero if the device is formatted as
* a super floppy with the FAT boot sector in block zero.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool init(uint8_t part);
/** \return The cluster number of last cluster in the volume. */
uint32_t lastCluster() const {
return m_lastCluster;
}
/** \return The number of entries in the root directory for FAT16 volumes. */
uint16_t rootDirEntryCount() const {
return m_rootDirEntryCount;
}
/** \return The logical block number for the start of the root directory
on FAT16 volumes or the first cluster number on FAT32 volumes. */
uint32_t rootDirStart() const {
return m_rootDirStart;
}
/** \return The volume's cluster size in sectors. */
uint8_t sectorsPerCluster() const {
return m_blocksPerCluster;
}
/** \return The number of blocks in the volume */
uint32_t volumeBlockCount() const {
return blocksPerCluster()*clusterCount();
}
/** \return The number of sectors in the volume */
uint32_t volumeSectorCount() const {
return sectorsPerCluster()*clusterCount();
}
/** Wipe all data from the volume.
* \param[in] pr print stream for status dots.
* \return true for success else false.
*/
bool wipe(print_t* pr = 0);
/** Debug access to FAT table
*
* \param[in] n cluster number.
* \param[out] v value of entry
* \return -1 error, 0 EOC, else 1.
*/
int8_t dbgFat(uint32_t n, uint32_t* v) {
return fatGet(n, v);
}
//------------------------------------------------------------------------------
private:
// Allow FatFile and FatCache access to FatVolume private functions.
friend class FatCache; ///< Allow access to FatVolume.
friend class FatFile; ///< Allow access to FatVolume.
friend class FatFileSystem; ///< Allow access to FatVolume.
//------------------------------------------------------------------------------
BlockDriver* m_blockDev; // block device
uint8_t m_blocksPerCluster; // Cluster size in blocks.
uint8_t m_clusterBlockMask; // Mask to extract block of cluster.
uint8_t m_clusterSizeShift; // Cluster count to block count shift.
uint8_t m_fatType; // Volume type (12, 16, OR 32).
uint16_t m_rootDirEntryCount; // Number of entries in FAT16 root dir.
uint32_t m_allocSearchStart; // Start cluster for alloc search.
uint32_t m_blocksPerFat; // FAT size in blocks
uint32_t m_dataStartBlock; // First data block number.
uint32_t m_fatStartBlock; // Start block for first FAT.
uint32_t m_lastCluster; // Last cluster number in FAT.
uint32_t m_rootDirStart; // Start block for FAT16, cluster for FAT32.
//------------------------------------------------------------------------------
// block I/O functions.
bool readBlock(uint32_t block, uint8_t* dst) {
return m_blockDev->readBlock(block, dst);
}
bool syncBlocks() {
return m_blockDev->syncBlocks();
}
bool writeBlock(uint32_t block, const uint8_t* src) {
return m_blockDev->writeBlock(block, src);
}
#if USE_MULTI_BLOCK_IO
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
return m_blockDev->readBlocks(block, dst, nb);
}
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb) {
return m_blockDev->writeBlocks(block, src, nb);
}
#endif // USE_MULTI_BLOCK_IO
#if MAINTAIN_FREE_CLUSTER_COUNT
int32_t m_freeClusterCount; // Count of free clusters in volume.
void setFreeClusterCount(int32_t value) {
m_freeClusterCount = value;
}
void updateFreeClusterCount(int32_t change) {
if (m_freeClusterCount >= 0) {
m_freeClusterCount += change;
}
}
#else // MAINTAIN_FREE_CLUSTER_COUNT
void setFreeClusterCount(int32_t value) {
(void)value;
}
void updateFreeClusterCount(int32_t change) {
(void)change;
}
#endif // MAINTAIN_FREE_CLUSTER_COUNT
// block caches
FatCache m_cache;
#if USE_SEPARATE_FAT_CACHE
FatCache m_fatCache;
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
return m_fatCache.read(blockNumber,
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
bool cacheSync() {
return m_cache.sync() && m_fatCache.sync() && syncBlocks();
}
#else //
cache_t* cacheFetchFat(uint32_t blockNumber, uint8_t options) {
return cacheFetchData(blockNumber,
options | FatCache::CACHE_STATUS_MIRROR_FAT);
}
bool cacheSync() {
return m_cache.sync() && syncBlocks();
}
#endif // USE_SEPARATE_FAT_CACHE
cache_t* cacheFetchData(uint32_t blockNumber, uint8_t options) {
return m_cache.read(blockNumber, options);
}
void cacheInvalidate() {
m_cache.invalidate();
}
bool cacheSyncData() {
return m_cache.sync();
}
cache_t *cacheAddress() {
return m_cache.block();
}
uint32_t cacheBlockNumber() {
return m_cache.lbn();
}
void cacheDirty() {
m_cache.dirty();
}
//------------------------------------------------------------------------------
bool allocateCluster(uint32_t current, uint32_t* next);
bool allocContiguous(uint32_t count,
uint32_t* firstCluster, uint32_t startCluster = 0);
uint8_t blockOfCluster(uint32_t position) const {
return (position >> 9) & m_clusterBlockMask;
}
uint32_t clusterFirstBlock(uint32_t cluster) const;
int8_t fatGet(uint32_t cluster, uint32_t* value);
bool fatPut(uint32_t cluster, uint32_t value);
bool fatPutEOC(uint32_t cluster) {
return fatPut(cluster, 0x0FFFFFFF);
}
bool freeChain(uint32_t cluster);
bool isEOC(uint32_t cluster) const {
return cluster > m_lastCluster;
}
};
#endif // FatVolume

View file

@ -0,0 +1,460 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "FmtNumber.h"
// Use Stimmer div/mod 10 on avr
#ifdef __AVR__
#include <avr/pgmspace.h>
#define USE_STIMMER
#endif // __AVR__
//------------------------------------------------------------------------------
// Stimmer div/mod 10 for AVR
// this code fragment works out i/10 and i%10 by calculating
// i*(51/256)*(256/255)/2 == i*51/510 == i/10
// by "j.k" I mean 32.8 fixed point, j is integer part, k is fractional part
// j.k = ((j+1.0)*51.0)/256.0
// (we add 1 because we will be using the floor of the result later)
// divmod10_asm16 and divmod10_asm32 are public domain code by Stimmer.
// http://forum.arduino.cc/index.php?topic=167414.msg1293679#msg1293679
#define divmod10_asm16(in32, mod8, tmp8) \
asm volatile( \
" ldi %2,51 \n\t" \
" mul %A0,%2 \n\t" \
" clr %A0 \n\t" \
" add r0,%2 \n\t" \
" adc %A0,r1 \n\t" \
" mov %1,r0 \n\t" \
" mul %B0,%2 \n\t" \
" clr %B0 \n\t" \
" add %A0,r0 \n\t" \
" adc %B0,r1 \n\t" \
" clr r1 \n\t" \
" add %1,%A0 \n\t" \
" adc %A0,%B0 \n\t" \
" adc %B0,r1 \n\t" \
" add %1,%B0 \n\t" \
" adc %A0,r1 \n\t" \
" adc %B0,r1 \n\t" \
" lsr %B0 \n\t" \
" ror %A0 \n\t" \
" ror %1 \n\t" \
" ldi %2,10 \n\t" \
" mul %1,%2 \n\t" \
" mov %1,r1 \n\t" \
" clr r1 \n\t" \
:"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
#define divmod10_asm32(in32, mod8, tmp8) \
asm volatile( \
" ldi %2,51 \n\t" \
" mul %A0,%2 \n\t" \
" clr %A0 \n\t" \
" add r0,%2 \n\t" \
" adc %A0,r1 \n\t" \
" mov %1,r0 \n\t" \
" mul %B0,%2 \n\t" \
" clr %B0 \n\t" \
" add %A0,r0 \n\t" \
" adc %B0,r1 \n\t" \
" mul %C0,%2 \n\t" \
" clr %C0 \n\t" \
" add %B0,r0 \n\t" \
" adc %C0,r1 \n\t" \
" mul %D0,%2 \n\t" \
" clr %D0 \n\t" \
" add %C0,r0 \n\t" \
" adc %D0,r1 \n\t" \
" clr r1 \n\t" \
" add %1,%A0 \n\t" \
" adc %A0,%B0 \n\t" \
" adc %B0,%C0 \n\t" \
" adc %C0,%D0 \n\t" \
" adc %D0,r1 \n\t" \
" add %1,%B0 \n\t" \
" adc %A0,%C0 \n\t" \
" adc %B0,%D0 \n\t" \
" adc %C0,r1 \n\t" \
" adc %D0,r1 \n\t" \
" add %1,%D0 \n\t" \
" adc %A0,r1 \n\t" \
" adc %B0,r1 \n\t" \
" adc %C0,r1 \n\t" \
" adc %D0,r1 \n\t" \
" lsr %D0 \n\t" \
" ror %C0 \n\t" \
" ror %B0 \n\t" \
" ror %A0 \n\t" \
" ror %1 \n\t" \
" ldi %2,10 \n\t" \
" mul %1,%2 \n\t" \
" mov %1,r1 \n\t" \
" clr r1 \n\t" \
:"+r"(in32), "=d"(mod8), "=d"(tmp8) : : "r0")
//------------------------------------------------------------------------------
/*
// C++ code is based on this version of divmod10 by robtillaart.
// http://forum.arduino.cc/index.php?topic=167414.msg1246851#msg1246851
// from robtillaart post:
// The code is based upon the divu10() code from the book Hackers Delight1.
// My insight was that the error formula in divu10() was in fact modulo 10
// but not always. Sometimes it was 10 more.
void divmod10(uint32_t in, uint32_t &div, uint32_t &mod)
{
// q = in * 0.8;
uint32_t q = (in >> 1) + (in >> 2);
q = q + (q >> 4);
q = q + (q >> 8);
q = q + (q >> 16); // not needed for 16 bit version
// q = q / 8; ==> q = in *0.1;
q = q >> 3;
// determine error
uint32_t r = in - ((q << 3) + (q << 1)); // r = in - q*10;
div = q + (r > 9);
if (r > 9) mod = r - 10;
else mod = r;
}
// Hackers delight function is here:
// http://www.hackersdelight.org/hdcodetxt/divuc.c.txt
// Code below uses 8/10 = 0.1100 1100 1100 1100 1100 1100 1100 1100.
// 15 ops including the multiply, or 17 elementary ops.
unsigned divu10(unsigned n) {
unsigned q, r;
q = (n >> 1) + (n >> 2);
q = q + (q >> 4);
q = q + (q >> 8);
q = q + (q >> 16);
q = q >> 3;
r = n - q*10;
return q + ((r + 6) >> 4);
// return q + (r > 9);
}
*/
//------------------------------------------------------------------------------
#ifndef DOXYGEN_SHOULD_SKIP_THIS
#ifdef __AVR__
static const float m[] PROGMEM = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
static const float p[] PROGMEM = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
#else // __AVR__
static const float m[] = {1e-1, 1e-2, 1e-4, 1e-8, 1e-16, 1e-32};
static const float p[] = {1e+1, 1e+2, 1e+4, 1e+8, 1e+16, 1e+32};
#endif // __AVR__
#endif // DOXYGEN_SHOULD_SKIP_THIS
// scale float v by power of ten. return v*10^n
float scale10(float v, int8_t n) {
const float *s;
if (n < 0) {
n = -n;
s = m;
} else {
s = p;
}
n &= 63;
for (uint8_t i = 0; n; n >>= 1, i++) {
#ifdef __AVR__
if (n & 1) {
v *= pgm_read_float(&s[i]);
}
#else // __AVR__
if (n & 1) {
v *= s[i];
}
#endif // __AVR__
}
return v;
}
//------------------------------------------------------------------------------
// Format 16-bit unsigned
char* fmtDec(uint16_t n, char* p) {
while (n > 9) {
#ifdef USE_STIMMER
uint8_t tmp8, r;
divmod10_asm16(n, r, tmp8);
#else // USE_STIMMER
uint16_t t = n;
n = (n >> 1) + (n >> 2);
n = n + (n >> 4);
n = n + (n >> 8);
// n = n + (n >> 16); // no code for 16-bit n
n = n >> 3;
uint8_t r = t - (((n << 2) + n) << 1);
if (r > 9) {
n++;
r -= 10;
}
#endif // USE_STIMMER
*--p = r + '0';
}
*--p = n + '0';
return p;
}
//------------------------------------------------------------------------------
// format 32-bit unsigned
char* fmtDec(uint32_t n, char* p) {
while (n >> 16) {
#ifdef USE_STIMMER
uint8_t tmp8, r;
divmod10_asm32(n, r, tmp8);
#else // USE_STIMMER
uint32_t t = n;
n = (n >> 1) + (n >> 2);
n = n + (n >> 4);
n = n + (n >> 8);
n = n + (n >> 16);
n = n >> 3;
uint8_t r = t - (((n << 2) + n) << 1);
if (r > 9) {
n++;
r -= 10;
}
#endif // USE_STIMMER
*--p = r + '0';
}
return fmtDec((uint16_t)n, p);
}
//------------------------------------------------------------------------------
char* fmtFloat(float value, char* p, uint8_t prec) {
char sign = value < 0 ? '-' : 0;
if (sign) {
value = -value;
}
if (isnan(value)) {
*--p = 'n';
*--p = 'a';
*--p = 'n';
return p;
}
if (isinf(value)) {
*--p = 'f';
*--p = 'n';
*--p = 'i';
return p;
}
if (value > 4294967040.0) {
*--p = 'f';
*--p = 'v';
*--p = 'o';
return p;
}
if (prec > 9) {
prec = 9;
}
value += scale10(0.5, -prec);
uint32_t whole = value;
if (prec) {
char* tmp = p - prec;
uint32_t fraction = scale10(value - whole, prec);
p = fmtDec(fraction, p);
while (p > tmp) {
*--p = '0';
}
*--p = '.';
}
p = fmtDec(whole, p);
if (sign) {
*--p = sign;
}
return p;
}
//------------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] ptr Pointer to last char in buffer.
* \param[in] prec Number of digits after decimal point.
* \param[in] expChar Use exp format if non zero.
* \return Pointer to first character of result.
*/
char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar) {
bool neg = value < 0;
if (neg) {
value = -value;
}
// check for nan inf ovf
if (isnan(value)) {
*--ptr = 'n';
*--ptr = 'a';
*--ptr = 'n';
return ptr;
}
if (isinf(value)) {
*--ptr = 'f';
*--ptr = 'n';
*--ptr = 'i';
return ptr;
}
if (!expChar && value > 4294967040.0) {
*--ptr = 'f';
*--ptr = 'v';
*--ptr = 'o';
return ptr;
}
if (prec > 9) {
prec = 9;
}
float round = scale10(0.5, -prec);
if (expChar) {
int8_t exp = 0;
bool expNeg = false;
if (value) {
while (value > 10.0) {
value *= 0.1;
exp++;
}
while (value < 1.0) {
value *= 10.0;
exp--;
}
value += round;
if (value > 10.0) {
value *= 0.1;
exp++;
}
expNeg = exp < 0;
if (expNeg) {
exp = -exp;
}
}
ptr = fmtDec((uint16_t)exp, ptr);
if (exp < 10) {
*--ptr = '0';
}
*--ptr = expNeg ? '-' : '+';
*--ptr = expChar;
} else {
// round value
value += round;
}
uint32_t whole = value;
if (prec) {
char* tmp = ptr - prec;
uint32_t fraction = scale10(value - whole, prec);
ptr = fmtDec(fraction, ptr);
while (ptr > tmp) {
*--ptr = '0';
}
*--ptr = '.';
}
ptr = fmtDec(whole, ptr);
if (neg) {
*--ptr = '-';
}
return ptr;
}
//------------------------------------------------------------------------------
char* fmtHex(uint32_t n, char* p) {
do {
uint8_t h = n & 0XF;
*--p = h + (h < 10 ? '0' : 'A' - 10);
n >>= 4;
} while (n);
return p;
}
//------------------------------------------------------------------------------
float scanFloat(const char* str, char** ptr) {
int16_t const EXP_LIMIT = 100;
bool digit = false;
bool dot = false;
uint32_t fract = 0;
int fracExp = 0;
uint8_t nd = 0;
bool neg;
int c;
float v;
const char* successPtr = str;
if (ptr) {
*ptr = const_cast<char*>(str);
}
while (isSpace((c = *str++))) {}
neg = c == '-';
if (c == '-' || c == '+') {
c = *str++;
}
// Skip leading zeros
while (c == '0') {
c = *str++;
digit = true;
}
for (;;) {
if (isDigit(c)) {
digit = true;
if (nd < 9) {
fract = 10*fract + c - '0';
nd++;
if (dot) {
fracExp--;
}
} else {
if (!dot) {
fracExp++;
}
}
} else if (c == '.') {
if (dot) {
goto fail;
}
dot = true;
} else {
if (!digit) {
goto fail;
}
break;
}
successPtr = str;
c = *str++;
}
if (c == 'e' || c == 'E') {
int exp = 0;
c = *str++;
bool expNeg = c == '-';
if (c == '-' || c == '+') {
c = *str++;
}
while (isDigit(c)) {
if (exp > EXP_LIMIT) {
goto fail;
}
exp = 10*exp + c - '0';
successPtr = str;
c = *str++;
}
fracExp += expNeg ? -exp : exp;
}
if (ptr) {
*ptr = const_cast<char*>(successPtr);
}
v = scale10(static_cast<float>(fract), fracExp);
return neg ? -v : v;
fail:
return 0;
}

View file

@ -0,0 +1,43 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FmtNumber_h
#define FmtNumber_h
// #include <ctype.h>
inline bool isDigit(char c) {
return '0' <= c && c <= '9';
}
inline bool isSpace(char c) {
return c == ' ' || (0X9 <= c && c <= 0XD);
}
#include <math.h>
#include <stdint.h>
char* fmtDec(uint16_t n, char* p);
char* fmtDec(uint32_t n, char* p);
char* fmtFloat(float value, char* p, uint8_t prec);
char* fmtFloat(float value, char* ptr, uint8_t prec, char expChar);
char* fmtHex(uint32_t n, char* p);
float scale10(float v, int8_t n);
float scanFloat(const char* str, char** ptr);
#endif // FmtNumber_h

View file

@ -0,0 +1,508 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "StdioStream.h"
#include "FmtNumber.h"
//------------------------------------------------------------------------------
int StdioStream::fclose() {
int rtn = 0;
if (!m_status) {
return EOF;
}
if (m_status & S_SWR) {
if (!flushBuf()) {
rtn = EOF;
}
}
if (!FatFile::close()) {
rtn = EOF;
}
m_r = 0;
m_w = 0;
m_status = 0;
return rtn;
}
//------------------------------------------------------------------------------
int StdioStream::fflush() {
if ((m_status & (S_SWR | S_SRW)) && !(m_status & S_SRD)) {
if (flushBuf() && FatFile::sync()) {
return 0;
}
}
return EOF;
}
//------------------------------------------------------------------------------
char* StdioStream::fgets(char* str, size_t num, size_t* len) {
char* s = str;
size_t n;
if (num-- == 0) {
return 0;
}
while (num) {
if ((n = m_r) == 0) {
if (!fillBuf()) {
if (s == str) {
return 0;
}
break;
}
n = m_r;
}
if (n > num) {
n = num;
}
uint8_t* end = reinterpret_cast<uint8_t*>(memchr(m_p, '\n', n));
if (end != 0) {
n = ++end - m_p;
memcpy(s, m_p, n);
m_r -= n;
m_p = end;
s += n;
break;
}
memcpy(s, m_p, n);
m_r -= n;
m_p += n;
s += n;
num -= n;
}
*s = 0;
if (len) {
*len = s - str;
}
return str;
}
//------------------------------------------------------------------------------
bool StdioStream::fopen(const char* path, const char* mode) {
oflag_t oflag;
uint8_t m;
switch (*mode++) {
case 'a':
m = O_WRONLY;
oflag = O_CREAT | O_APPEND;
m_status = S_SWR;
break;
case 'r':
m = O_RDONLY;
oflag = 0;
m_status = S_SRD;
break;
case 'w':
m = O_WRONLY;
oflag = O_CREAT | O_TRUNC;
m_status = S_SWR;
break;
default:
goto fail;
}
while (*mode) {
switch (*mode++) {
case '+':
m_status = S_SRW;
m = O_RDWR;
break;
case 'b':
break;
case 'x':
oflag |= O_EXCL;
break;
default:
goto fail;
}
}
oflag |= m;
if (!FatFile::open(path, oflag)) {
goto fail;
}
m_r = 0;
m_w = 0;
m_p = m_buf;
return true;
fail:
m_status = 0;
return false;
}
//------------------------------------------------------------------------------
int StdioStream::fputs(const char* str) {
size_t len = strlen(str);
return fwrite(str, 1, len) == len ? len : EOF;
}
//------------------------------------------------------------------------------
size_t StdioStream::fread(void* ptr, size_t size, size_t count) {
uint8_t* dst = reinterpret_cast<uint8_t*>(ptr);
size_t total = size*count;
if (total == 0) {
return 0;
}
size_t need = total;
while (need > m_r) {
memcpy(dst, m_p, m_r);
dst += m_r;
m_p += m_r;
need -= m_r;
if (!fillBuf()) {
return (total - need)/size;
}
}
memcpy(dst, m_p, need);
m_r -= need;
m_p += need;
return count;
}
//------------------------------------------------------------------------------
int StdioStream::fseek(int32_t offset, int origin) {
int32_t pos;
if (m_status & S_SWR) {
if (!flushBuf()) {
goto fail;
}
}
switch (origin) {
case SEEK_CUR:
pos = ftell();
if (pos < 0) {
goto fail;
}
pos += offset;
if (!FatFile::seekCur(pos)) {
goto fail;
}
break;
case SEEK_SET:
if (!FatFile::seekSet(offset)) {
goto fail;
}
break;
case SEEK_END:
if (!FatFile::seekEnd(offset)) {
goto fail;
}
break;
default:
goto fail;
}
m_r = 0;
m_p = m_buf;
return 0;
fail:
return EOF;
}
//------------------------------------------------------------------------------
int32_t StdioStream::ftell() {
uint32_t pos = FatFile::curPosition();
if (m_status & S_SRD) {
if (m_r > pos) {
return -1L;
}
pos -= m_r;
} else if (m_status & S_SWR) {
pos += m_p - m_buf;
}
return pos;
}
//------------------------------------------------------------------------------
size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
return write(ptr, count*size) < 0 ? EOF : count;
}
//------------------------------------------------------------------------------
int StdioStream::write(const void* buf, size_t count) {
const uint8_t* src = static_cast<const uint8_t*>(buf);
size_t todo = count;
while (todo > m_w) {
memcpy(m_p, src, m_w);
m_p += m_w;
src += m_w;
todo -= m_w;
if (!flushBuf()) {
return EOF;
}
}
memcpy(m_p, src, todo);
m_p += todo;
m_w -= todo;
return count;
}
//------------------------------------------------------------------------------
#if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
size_t StdioStream::print(const __FlashStringHelper *str) {
const char *p = (const char*)str;
uint8_t c;
while ((c = pgm_read_byte(p))) {
if (putc(c) < 0) {
return 0;
}
p++;
}
return p - (const char*)str;
}
#endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
//------------------------------------------------------------------------------
int StdioStream::printDec(float value, uint8_t prec) {
char buf[24];
char *ptr = fmtFloat(value, buf + sizeof(buf), prec);
return write(ptr, buf + sizeof(buf) - ptr);
}
//------------------------------------------------------------------------------
int StdioStream::printDec(signed char n) {
if (n < 0) {
if (fputc('-') < 0) {
return -1;
}
n = -n;
}
return printDec((unsigned char)n);
}
//------------------------------------------------------------------------------
int StdioStream::printDec(int16_t n) {
int s;
uint8_t rtn = 0;
if (n < 0) {
if (fputc('-') < 0) {
return -1;
}
n = -n;
rtn++;
}
if ((s = printDec((uint16_t)n)) < 0) {
return s;
}
return rtn;
}
//------------------------------------------------------------------------------
int StdioStream::printDec(uint16_t n) {
#define NEW_WAY
#ifdef NEW_WAY
char buf[5];
char *ptr = fmtDec(n, buf + sizeof(buf));
uint8_t len = buf + sizeof(buf) - ptr;
return write(ptr, len);
#else
uint8_t len;
if (n < 100) {
len = n < 10 ? 1 : 2;
} else {
len = n < 1000 ? 3 : n < 10000 ? 4 : 5;
}
char* str = fmtSpace(len);
if (!str) {
return -1;
}
fmtDec(n, str);
return len;
#endif
}
//------------------------------------------------------------------------------
int StdioStream::printDec(int32_t n) {
uint8_t s = 0;
if (n < 0) {
if (fputc('-') < 0) {
return -1;
}
n = -n;
s = 1;
}
int rtn = printDec((uint32_t)n);
return rtn > 0 ? rtn + s : -1;
}
//------------------------------------------------------------------------------
int StdioStream::printDec(uint32_t n) {
#ifdef NEW_WAY
char buf[10];
char *ptr = fmtDec(n, buf + sizeof(buf));
uint8_t len = buf + sizeof(buf) - ptr;
return write(ptr, len);
#else
uint8_t len;
if (n < 0X10000) {
return printDec((uint16_t)n);
}
if (n < 10000000) {
len = n < 100000 ? 5 : n < 1000000 ? 6 : 7;
} else {
len = n < 100000000 ? 8 : n < 1000000000 ? 9 : 10;
}
char* str = fmtSpace(len);
if (!str) {
return -1;
}
fmtDec(n, str);
return len;
#endif
}
//------------------------------------------------------------------------------
int StdioStream::printHex(uint32_t n) {
#ifdef NEW_WAY
char buf[8];
char *ptr = fmtHex(n, buf + sizeof(buf));
uint8_t len = buf + sizeof(buf) - ptr;
return write(ptr, len);
#else
size_t len;
if (n < 0X10000) {
len = n < 0X10 ? 1 : n < 0X100 ? 2 : n < 0X1000 ? 3 : 4;
} else {
len = n < 0X100000 ? 5 : n < 0X1000000 ? 6 : n < 0X10000000 ? 7 : 8;
}
char* str = fmtSpace(len);
if (!str) {
return -1;
}
do {
uint8_t h = n & 0XF;
*str-- = h + (h < 10 ? '0' : 'A' - 10);
n >>= 4;
} while (n);
return len;
#endif
}
//------------------------------------------------------------------------------
bool StdioStream::rewind() {
if (m_status & S_SWR) {
if (!flushBuf()) {
return false;
}
}
FatFile::seekSet(0);
m_r = 0;
return true;
}
//------------------------------------------------------------------------------
int StdioStream::ungetc(int c) {
// error if EOF.
if (c == EOF) {
return EOF;
}
// error if not reading.
if ((m_status & S_SRD) == 0) {
return EOF;
}
// error if no space.
if (m_p == m_buf) {
return EOF;
}
m_r++;
m_status &= ~S_EOF;
return *--m_p = (uint8_t)c;
}
//==============================================================================
// private
//------------------------------------------------------------------------------
int StdioStream::fillGet() {
if (!fillBuf()) {
return EOF;
}
m_r--;
return *m_p++;
}
//------------------------------------------------------------------------------
// private
bool StdioStream::fillBuf() {
if (!(m_status &
S_SRD)) { // check for S_ERR and S_EOF ??/////////////////
if (!(m_status & S_SRW)) {
m_status |= S_ERR;
return false;
}
if (m_status & S_SWR) {
if (!flushBuf()) {
return false;
}
m_status &= ~S_SWR;
m_status |= S_SRD;
m_w = 0;
}
}
m_p = m_buf + UNGETC_BUF_SIZE;
int nr = FatFile::read(m_p, sizeof(m_buf) - UNGETC_BUF_SIZE);
if (nr <= 0) {
m_status |= nr < 0 ? S_ERR : S_EOF;
m_r = 0;
return false;
}
m_r = nr;
return true;
}
//------------------------------------------------------------------------------
// private
bool StdioStream::flushBuf() {
if (!(m_status &
S_SWR)) { // check for S_ERR ??////////////////////////
if (!(m_status & S_SRW)) {
m_status |= S_ERR;
return false;
}
m_status &= ~S_SRD;
m_status |= S_SWR;
m_r = 0;
m_w = sizeof(m_buf);
m_p = m_buf;
return true;
}
uint8_t n = m_p - m_buf;
m_p = m_buf;
m_w = sizeof(m_buf);
if (FatFile::write(m_buf, n) == n) {
return true;
}
m_status |= S_ERR;
return false;
}
//------------------------------------------------------------------------------
int StdioStream::flushPut(uint8_t c) {
if (!flushBuf()) {
return EOF;
}
m_w--;
return *m_p++ = c;
}
//------------------------------------------------------------------------------
char* StdioStream::fmtSpace(uint8_t len) {
if (m_w < len) {
if (!flushBuf() || m_w < len) {
return 0;
}
}
if (len > m_w) {
return 0;
}
m_p += len;
m_w -= len;
return reinterpret_cast<char*>(m_p);
}

View file

@ -0,0 +1,667 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef StdioStream_h
#define StdioStream_h
/**
* \file
* \brief StdioStream class
*/
#include <limits.h>
#include "FatFile.h"
//------------------------------------------------------------------------------
/** Total size of stream buffer. The entire buffer is used for output.
* During input UNGETC_BUF_SIZE of this space is reserved for ungetc.
*/
const uint8_t STREAM_BUF_SIZE = 64;
/** Amount of buffer allocated for ungetc during input. */
const uint8_t UNGETC_BUF_SIZE = 2;
//------------------------------------------------------------------------------
// Get rid of any macros defined in <stdio.h>.
#include <stdio.h>
#undef clearerr
#undef fclose
#undef feof
#undef ferror
#undef fflush
#undef fgetc
#undef fgetpos
#undef fgets
#undef fopen
#undef fprintf
#undef fputc
#undef fputs
#undef fread
#undef freopen
#undef fscanf
#undef fseek
#undef fsetpos
#undef ftell
#undef fwrite
#undef getc
#undef getchar
#undef gets
#undef perror
//#undef printf // NOLINT
#undef putc
#undef putchar
#undef puts
#undef remove
#undef rename
#undef rewind
#undef scanf
#undef setbuf
#undef setvbuf
//#undef sprintf // NOLINT
#undef sscanf
#undef tmpfile
#undef tmpnam
#undef ungetc
#undef vfprintf
#undef vprintf
#undef vsprintf
// make sure needed macros are defined
#ifndef EOF
/** End-of-file return value. */
#define EOF (-1)
#endif // EOF
#ifndef NULL
/** Null pointer */
#define NULL 0
#endif // NULL
#ifndef SEEK_CUR
/** Seek relative to current position. */
#define SEEK_CUR 1
#endif // SEEK_CUR
#ifndef SEEK_END
/** Seek relative to end-of-file. */
#define SEEK_END 2
#endif // SEEK_END
#ifndef SEEK_SET
/** Seek relative to start-of-file. */
#define SEEK_SET 0
#endif // SEEK_SET
//------------------------------------------------------------------------------
/** \class StdioStream
* \brief StdioStream implements a minimal stdio stream.
*
* StdioStream does not support subdirectories or long file names.
*/
class StdioStream : private FatFile {
public:
/** Constructor
*
*/
StdioStream() {
m_w = m_r = 0;
m_p = m_buf;
m_status = 0;
}
//----------------------------------------------------------------------------
/** Clear the stream's end-of-file and error indicators. */
void clearerr() {
m_status &= ~(S_ERR | S_EOF);
}
//----------------------------------------------------------------------------
/** Close a stream.
*
* A successful call to the fclose function causes the stream to be
* flushed and the associated file to be closed. Any unwritten buffered
* data is written to the file; any unread buffered data is discarded.
* Whether or not the call succeeds, the stream is disassociated from
* the file.
*
* \return zero if the stream was successfully closed, or EOF if any any
* errors are detected.
*/
int fclose();
//----------------------------------------------------------------------------
/** Test the stream's end-of-file indicator.
* \return non-zero if and only if the end-of-file indicator is set.
*/
int feof() {
return (m_status & S_EOF) != 0;
}
//----------------------------------------------------------------------------
/** Test the stream's error indicator.
* \return return non-zero if and only if the error indicator is set.
*/
int ferror() {
return (m_status & S_ERR) != 0;
}
//----------------------------------------------------------------------------
/** Flush the stream.
*
* If stream is an output stream or an update stream in which the most
* recent operation was not input, any unwritten data is written to the
* file; otherwise the call is an error since any buffered input data
* would be lost.
*
* \return sets the error indicator for the stream and returns EOF if an
* error occurs, otherwise it returns zero.
*/
int fflush();
//----------------------------------------------------------------------------
/** Get a byte from the stream.
*
* \return If the end-of-file indicator for the stream is set, or if the
* stream is at end-of-file, the end-of-file indicator for the stream is
* set and the fgetc function returns EOF. Otherwise, the fgetc function
* returns the next character from the input stream.
*/
int fgetc() {
return m_r-- == 0 ? fillGet() : *m_p++;
}
//----------------------------------------------------------------------------
/** Get a string from a stream.
*
* The fgets function reads at most one less than the number of
* characters specified by num from the stream into the array pointed
* to by str. No additional characters are read after a new-line
* character (which is retained) or after end-of-file. A null character
* is written immediately after the last character read into the array.
*
* \param[out] str Pointer to an array of where the string is copied.
*
* \param[in] num Maximum number of characters including the null
* character.
*
* \param[out] len If len is not null and fgets is successful, the
* length of the string is returned.
*
* \return str if successful. If end-of-file is encountered and no
* characters have been read into the array, the contents of the array
* remain unchanged and a null pointer is returned. If a read error
* occurs during the operation, the array contents are indeterminate
* and a null pointer is returned.
*/
char* fgets(char* str, size_t num, size_t* len = 0);
//----------------------------------------------------------------------------
/** Open a stream.
*
* Open a file and associates the stream with it.
*
* \param[in] path file to be opened.
*
* \param[in] mode a string that indicates the open mode.
*
* <table>
* <tr>
* <td>"r" or "rb"</td>
* <td>Open a file for reading. The file must exist.</td>
* </tr>
* <tr>
* <td>"w" or "wb"</td>
* <td>Truncate an existing to zero length or create an empty file
* for writing.</td>
* </tr>
* <tr>
* <td>"wx" or "wbx"</td>
* <td>Create a file for writing. Fails if the file already exists.</td>
* </tr>
* <tr>
* <td>"a" or "ab"</td>
* <td>Append; open or create file for writing at end-of-file.</td>
* </tr>
* <tr>
* <td>"r+" or "rb+" or "r+b"</td>
* <td>Open a file for update (reading and writing).</td>
* </tr>
* <tr>
* <td>"w+" or "w+b" or "wb+"</td>
* <td>Truncate an existing to zero length or create a file for update.</td>
* </tr>
* <tr>
* <td>"w+x" or "w+bx" or "wb+x"</td>
* <td>Create a file for update. Fails if the file already exists.</td>
* </tr>
* <tr>
* <td>"a+" or "a+b" or "ab+"</td>
* <td>Append; open or create a file for update, writing at end-of-file.</td>
* </tr>
* </table>
* The character 'b' shall have no effect, but is allowed for ISO C
* standard conformance.
*
* Opening a file with append mode causes all subsequent writes to the
* file to be forced to the then current end-of-file, regardless of
* intervening calls to the fseek function.
*
* When a file is opened with update mode, both input and output may be
* performed on the associated stream. However, output shall not be
* directly followed by input without an intervening call to the fflush
* function or to a file positioning function (fseek, or rewind), and
* input shall not be directly followed by output without an intervening
* call to a file positioning function, unless the input operation
* encounters end-of-file.
*
* \return true for success or false for failure.
*/
bool fopen(const char* path, const char * mode);
//----------------------------------------------------------------------------
/** Write a byte to a stream.
*
* \param[in] c the byte to be written (converted to an unsigned char).
*
* \return Upon successful completion, fputc() returns the value it
* has written. Otherwise, it returns EOF and sets the error indicator for
* the stream.
*/
int fputc(int c) {
return m_w-- == 0 ? flushPut(c) : *m_p++ = c;
}
//----------------------------------------------------------------------------
/** Write a string to a stream.
*
* \param[in] str a pointer to the string to be written.
*
* \return for success, fputs() returns a non-negative
* number. Otherwise, it returns EOF and sets the error indicator for
* the stream.
*/
int fputs(const char* str);
//----------------------------------------------------------------------------
/** Binary input.
*
* Reads an array of up to count elements, each one with a size of size
* bytes.
* \param[out] ptr pointer to area of at least (size*count) bytes where
* the data will be stored.
*
* \param[in] size the size, in bytes, of each element to be read.
*
* \param[in] count the number of elements to be read.
*
* \return number of elements successfully read, which may be less than
* count if a read error or end-of-file is encountered. If size or count
* is zero, fread returns zero and the contents of the array and the
* state of the stream remain unchanged.
*/
size_t fread(void* ptr, size_t size, size_t count);
//----------------------------------------------------------------------------
/** Set the file position for the stream.
*
* \param[in] offset number of offset from the origin.
*
* \param[in] origin position used as reference for the offset. It is
* specified by one of the following constants.
*
* SEEK_SET - Beginning of file.
*
* SEEK_CUR - Current position of the file pointer.
*
* SEEK_END - End of file.
*
* \return zero for success. Otherwise, it returns non-zero and sets the
* error indicator for the stream.
*/
int fseek(int32_t offset, int origin);
//----------------------------------------------------------------------------
/** Get the current position in a stream.
*
* \return If successful, ftell return the current value of the position
* indicator. On failure, ftell returns 1L.
*/
int32_t ftell();
//----------------------------------------------------------------------------
/** Binary output.
*
* Writes an array of up to count elements, each one with a size of size
* bytes.
* \param[in] ptr pointer to (size*count) bytes of data to be written.
*
* \param[in] size the size, in bytes, of each element to be written.
*
* \param[in] count the number of elements to be written.
*
* \return number of elements successfully written. if this number is
* less than count, an error has occurred. If size or count is zero,
* fwrite returns zero.
*/
size_t fwrite(const void * ptr, size_t size, size_t count);
//----------------------------------------------------------------------------
/** Get a byte from the stream.
*
* getc and fgetc are equivalent but getc is in-line so it is faster but
* require more flash memory.
*
* \return If the end-of-file indicator for the stream is set, or if the
* stream is at end-of-file, the end-of-file indicator for the stream is
* set and the fgetc function returns EOF. Otherwise, the fgetc function
* returns the next character from the input stream.
*/
inline __attribute__((always_inline))
int getc() {
return m_r-- == 0 ? fillGet() : *m_p++;
}
//----------------------------------------------------------------------------
/** Write a byte to a stream.
*
* putc and fputc are equivalent but putc is in-line so it is faster but
* require more flash memory.
*
* \param[in] c the byte to be written (converted to an unsigned char).
*
* \return Upon successful completion, fputc() returns the value it
* has written. Otherwise, it returns EOF and sets the error indicator for
* the stream.
*/
inline __attribute__((always_inline))
int putc(int c) {
return m_w-- == 0 ? flushPut(c) : *m_p++ = c;
}
//----------------------------------------------------------------------------
/** Write a CR/LF.
*
* \return two, the number of bytes written, for success or -1 for failure.
*/
inline __attribute__((always_inline))
int putCRLF() {
if (m_w < 2) {
if (!flushBuf()) {
return -1;
}
}
*m_p++ = '\r';
*m_p++ = '\n';
m_w -= 2;
return 2;
}
//----------------------------------------------------------------------------
/** Write a character.
* \param[in] c the character to write.
* \return the number of bytes written.
*/
size_t print(char c) {
return putc(c) < 0 ? 0 : 1;
}
//----------------------------------------------------------------------------
/** Write a string.
*
* \param[in] str the string to be written.
*
* \return the number of bytes written.
*/
size_t print(const char* str) {
int n = fputs(str);
return n < 0 ? 0 : n;
}
//----------------------------------------------------------------------------
#if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
/** Print a string stored in flash memory.
*
* \param[in] str the string to print.
*
* \return the number of bytes written.
*/
size_t print(const __FlashStringHelper *str);
#endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
//----------------------------------------------------------------------------
/** Print a floating point number.
*
* \param[in] prec Number of digits after decimal point.
*
* \param[in] val the number to be printed.
*
* \return the number of bytes written.
*/
size_t print(double val, uint8_t prec = 2) {
return print(static_cast<float>(val), prec);
}
//----------------------------------------------------------------------------
/** Print a floating point number.
*
* \param[in] prec Number of digits after decimal point.
*
* \param[in] val the number to be printed.
*
* \return the number of bytes written.
*/
size_t print(float val, uint8_t prec = 2) {
int n = printDec(val, prec);
return n > 0 ? n : 0;
}
//----------------------------------------------------------------------------
/** Print a number.
*
* \param[in] val the number to be printed.
*
* \return the number of bytes written.
*/
template <typename T>
size_t print(T val) {
int n = printDec(val);
return n > 0 ? n : 0;
}
//----------------------------------------------------------------------------
/** Write a CR/LF.
*
* \return two, the number of bytes written, for success or zero for failure.
*/
size_t println() {
return putCRLF() > 0 ? 2 : 0;
}
//----------------------------------------------------------------------------
/** Print a floating point number followed by CR/LF.
*
* \param[in] val the number to be printed.
*
* \param[in] prec Number of digits after decimal point.
*
* \return the number of bytes written.
*/
size_t println(double val, uint8_t prec = 2) {
return println(static_cast<float>(val), prec);
}
//----------------------------------------------------------------------------
/** Print a floating point number followed by CR/LF.
*
* \param[in] val the number to be printed.
*
* \param[in] prec Number of digits after decimal point.
*
* \return the number of bytes written.
*/
size_t println(float val, uint8_t prec = 2) {
int n = printDec(val, prec);
return n > 0 && putCRLF() > 0 ? n + 2 : 0;
}
//----------------------------------------------------------------------------
/** Print an item followed by CR/LF
*
* \param[in] val the item to be printed.
*
* \return the number of bytes written.
*/
template <typename T>
size_t println(T val) {
int n = print(val);
return putCRLF() > 0 ? n + 2 : 0;
}
//----------------------------------------------------------------------------
/** Print a char as a number.
* \param[in] n number to be printed.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(char n) {
if (CHAR_MIN == 0) {
return printDec((unsigned char)n);
} else {
return printDec((signed char)n);
}
}
//----------------------------------------------------------------------------
/** print a signed 8-bit integer
* \param[in] n number to be printed.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(signed char n);
//----------------------------------------------------------------------------
/** Print an unsigned 8-bit number.
* \param[in] n number to be print.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(unsigned char n) {
return printDec((uint16_t)n);
}
//----------------------------------------------------------------------------
/** Print a int16_t
* \param[in] n number to be printed.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(int16_t n);
//----------------------------------------------------------------------------
/** print a uint16_t.
* \param[in] n number to be printed.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(uint16_t n);
//----------------------------------------------------------------------------
/** Print a signed 32-bit integer.
* \param[in] n number to be printed.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(int32_t n);
//----------------------------------------------------------------------------
/** Write an unsigned 32-bit number.
* \param[in] n number to be printed.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(uint32_t n);
//----------------------------------------------------------------------------
/** Print a double.
* \param[in] value The number to be printed.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(double value, uint8_t prec) {
return printDec(static_cast<float>(value), prec);
}
//----------------------------------------------------------------------------
/** Print a float.
* \param[in] value The number to be printed.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printDec(float value, uint8_t prec);
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(double value, char term, uint8_t prec = 2) {
return printField(static_cast<float>(value), term, prec) > 0;
}
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \param[in] prec Number of digits after decimal point.
* \return The number of bytes written or -1 if an error occurs.
*/
int printField(float value, char term, uint8_t prec = 2) {
int rtn = printDec(value, prec);
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
}
//----------------------------------------------------------------------------
/** Print a number followed by a field terminator.
* \param[in] value The number to be printed.
* \param[in] term The field terminator.
* \return The number of bytes written or -1 if an error occurs.
*/
template <typename T>
int printField(T value, char term) {
int rtn = printDec(value);
return rtn < 0 || putc(term) < 0 ? -1 : rtn + 1;
}
//----------------------------------------------------------------------------
/** Print HEX
* \param[in] n number to be printed as HEX.
*
* \return The number of bytes written or -1 if an error occurs.
*/
int printHex(uint32_t n);
//----------------------------------------------------------------------------
/** Print HEX with CRLF
* \param[in] n number to be printed as HEX.
*
* \return The number of bytes written or -1 if an error occurs.
*/
int printHexln(uint32_t n) {
int rtn = printHex(n);
return rtn < 0 || putCRLF() != 2 ? -1 : rtn + 2;
}
//----------------------------------------------------------------------------
/** Set position of a stream to the beginning.
*
* The rewind function sets the file position to the beginning of the
* file. It is equivalent to fseek(0L, SEEK_SET) except that the error
* indicator for the stream is also cleared.
*
* \return true for success or false for failure.
*/
bool rewind();
//----------------------------------------------------------------------------
/** Push a byte back into an input stream.
*
* \param[in] c the byte (converted to an unsigned char) to be pushed back.
*
* One character of push-back is guaranteed. If the ungetc function is
* called too many times without an intervening read or file positioning
* operation on that stream, the operation may fail.
*
* A successful intervening call to a file positioning function (fseek,
* fsetpos, or rewind) discards any pushed-back characters for the stream.
*
* \return Upon successful completion, ungetc() returns the byte pushed
* back after conversion. Otherwise it returns EOF.
*/
int ungetc(int c);
//============================================================================
private:
bool fillBuf();
int fillGet();
bool flushBuf();
int flushPut(uint8_t c);
char* fmtSpace(uint8_t len);
int write(const void* buf, size_t count);
//----------------------------------------------------------------------------
// S_SRD and S_WR are never simultaneously asserted
static const uint8_t S_SRD = 0x01; // OK to read
static const uint8_t S_SWR = 0x02; // OK to write
static const uint8_t S_SRW = 0x04; // open for reading & writing
static const uint8_t S_EOF = 0x10; // found EOF
static const uint8_t S_ERR = 0x20; // found error
//----------------------------------------------------------------------------
uint8_t m_status;
uint8_t* m_p;
uint8_t m_r;
uint8_t m_w;
uint8_t m_buf[STREAM_BUF_SIZE];
};
//------------------------------------------------------------------------------
#endif // StdioStream_h

View file

@ -0,0 +1,172 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef bufstream_h
#define bufstream_h
/**
* \file
* \brief \ref ibufstream and \ref obufstream classes
*/
#include <string.h>
#include "iostream.h"
//==============================================================================
/**
* \class ibufstream
* \brief parse a char string
*/
class ibufstream : public istream {
public:
/** Constructor */
ibufstream() : m_buf(0), m_len(0) {}
/** Constructor
* \param[in] str pointer to string to be parsed
* Warning: The string will not be copied so must stay in scope.
*/
explicit ibufstream(const char* str) {
init(str);
}
/** Initialize an ibufstream
* \param[in] str pointer to string to be parsed
* Warning: The string will not be copied so must stay in scope.
*/
void init(const char* str) {
m_buf = str;
m_len = strlen(m_buf);
m_pos = 0;
clear();
}
protected:
/// @cond SHOW_PROTECTED
int16_t getch() {
if (m_pos < m_len) {
return m_buf[m_pos++];
}
setstate(eofbit);
return -1;
}
void getpos(FatPos_t *pos) {
pos->position = m_pos;
}
bool seekoff(off_type off, seekdir way) {
(void)off;
(void)way;
return false;
}
bool seekpos(pos_type pos) {
if (pos < m_len) {
m_pos = pos;
return true;
}
return false;
}
void setpos(FatPos_t *pos) {
m_pos = pos->position;
}
pos_type tellpos() {
return m_pos;
}
/// @endcond
private:
const char* m_buf;
size_t m_len;
size_t m_pos;
};
//==============================================================================
/**
* \class obufstream
* \brief format a char string
*/
class obufstream : public ostream {
public:
/** constructor */
obufstream() : m_in(0) {}
/** Constructor
* \param[in] buf buffer for formatted string
* \param[in] size buffer size
*/
obufstream(char *buf, size_t size) {
init(buf, size);
}
/** Initialize an obufstream
* \param[in] buf buffer for formatted string
* \param[in] size buffer size
*/
void init(char *buf, size_t size) {
m_buf = buf;
buf[0] = '\0';
m_size = size;
m_in = 0;
}
/** \return a pointer to the buffer */
char* buf() {
return m_buf;
}
/** \return the length of the formatted string */
size_t length() {
return m_in;
}
protected:
/// @cond SHOW_PROTECTED
void putch(char c) {
if (m_in >= (m_size - 1)) {
setstate(badbit);
return;
}
m_buf[m_in++] = c;
m_buf[m_in] = '\0';
}
void putstr(const char *str) {
while (*str) {
putch(*str++);
}
}
bool seekoff(off_type off, seekdir way) {
(void)off;
(void)way;
return false;
}
bool seekpos(pos_type pos) {
if (pos > m_in) {
return false;
}
m_in = pos;
m_buf[m_in] = '\0';
return true;
}
bool sync() {
return true;
}
pos_type tellpos() {
return m_in;
}
/// @endcond
private:
char *m_buf;
size_t m_size;
size_t m_in;
};
#endif // bufstream_h

View file

@ -0,0 +1,172 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "fstream.h"
//==============================================================================
/// @cond SHOW_PROTECTED
int16_t FatStreamBase::getch() {
uint8_t c;
int8_t s = read(&c, 1);
if (s != 1) {
if (s < 0) {
setstate(badbit);
} else {
setstate(eofbit);
}
return -1;
}
if (c != '\r' || (getmode() & ios::binary)) {
return c;
}
s = read(&c, 1);
if (s == 1 && c == '\n') {
return c;
}
if (s == 1) {
seekCur(-1);
}
return '\r';
}
//------------------------------------------------------------------------------
void FatStreamBase::open(const char* path, ios::openmode mode) {
oflag_t oflag;
switch (mode & (app | in | out | trunc)) {
case app | in:
case app | in | out:
oflag = O_RDWR | O_APPEND | O_CREAT;
break;
case app:
case app | out:
oflag = O_WRONLY | O_APPEND | O_CREAT;
break;
case in:
oflag = O_RDONLY;
break;
case in | out:
oflag = O_RDWR;
break;
case in | out | trunc:
oflag = O_RDWR | O_TRUNC | O_CREAT;
break;
case out:
case out | trunc:
oflag = O_WRONLY | O_TRUNC | O_CREAT;
break;
default:
goto fail;
}
if (mode & ios::ate) {
oflag |= O_AT_END;
}
if (!FatFile::open(path, oflag)) {
goto fail;
}
setmode(mode);
clear();
return;
fail:
FatFile::close();
setstate(failbit);
return;
}
//------------------------------------------------------------------------------
void FatStreamBase::putch(char c) {
if (c == '\n' && !(getmode() & ios::binary)) {
write('\r');
}
write(c);
if (getWriteError()) {
setstate(badbit);
}
}
//------------------------------------------------------------------------------
void FatStreamBase::putstr(const char* str) {
size_t n = 0;
while (1) {
char c = str[n];
if (c == '\0' || (c == '\n' && !(getmode() & ios::binary))) {
if (n > 0) {
write(str, n);
}
if (c == '\0') {
break;
}
write('\r');
str += n;
n = 0;
}
n++;
}
if (getWriteError()) {
setstate(badbit);
}
}
//------------------------------------------------------------------------------
/** Internal do not use
* \param[in] off
* \param[in] way
*/
bool FatStreamBase::seekoff(off_type off, seekdir way) {
pos_type pos;
switch (way) {
case beg:
pos = off;
break;
case cur:
pos = curPosition() + off;
break;
case end:
pos = fileSize() + off;
break;
default:
return false;
}
return seekpos(pos);
}
//------------------------------------------------------------------------------
/** Internal do not use
* \param[in] pos
*/
bool FatStreamBase::seekpos(pos_type pos) {
return seekSet(pos);
}
//------------------------------------------------------------------------------
int FatStreamBase::write(const void* buf, size_t n) {
return FatFile::write(buf, n);
}
//------------------------------------------------------------------------------
void FatStreamBase::write(char c) {
write(&c, 1);
}
/// @endcond

View file

@ -0,0 +1,320 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef fstream_h
#define fstream_h
/**
* \file
* \brief \ref fstream, \ref ifstream, and \ref ofstream classes
*/
#include "FatFile.h"
#include "iostream.h"
//==============================================================================
/**
* \class FatStreamBase
* \brief Base class for C++ style streams
*/
class FatStreamBase : protected FatFile, virtual public ios {
protected:
/// @cond SHOW_PROTECTED
int16_t getch();
void putch(char c);
void putstr(const char *str);
void open(const char* path, ios::openmode mode);
/** Internal do not use
* \return mode
*/
ios::openmode getmode() {
return m_mode;
}
/** Internal do not use
* \param[in] mode
*/
void setmode(ios::openmode mode) {
m_mode = mode;
}
bool seekoff(off_type off, seekdir way);
bool seekpos(pos_type pos);
int write(const void* buf, size_t n);
void write(char c);
/// @endcond
private:
ios::openmode m_mode;
};
//==============================================================================
/**
* \class fstream
* \brief file input/output stream.
*/
class fstream : public iostream, FatStreamBase {
public:
using iostream::peek;
fstream() {}
/** Constructor with open
*
* \param[in] path path to open
* \param[in] mode open mode
*/
explicit fstream(const char* path, openmode mode = in | out) {
open(path, mode);
}
#if DESTRUCTOR_CLOSES_FILE
~fstream() {}
#endif // DESTRUCTOR_CLOSES_FILE
/** Clear state and writeError
* \param[in] state new state for stream
*/
void clear(iostate state = goodbit) {
ios::clear(state);
FatFile::clearWriteError();
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {
FatFile::close();
}
/** Open a fstream
* \param[in] path file to open
* \param[in] mode open mode
*
* Valid open modes are (at end, ios::ate, and/or ios::binary may be added):
*
* ios::in - Open file for reading.
*
* ios::out or ios::out | ios::trunc - Truncate to 0 length, if existent,
* or create a file for writing only.
*
* ios::app or ios::out | ios::app - Append; open or create file for
* writing at end-of-file.
*
* ios::in | ios::out - Open file for update (reading and writing).
*
* ios::in | ios::out | ios::trunc - Truncate to zero length, if existent,
* or create file for update.
*
* ios::in | ios::app or ios::in | ios::out | ios::app - Append; open or
* create text file for update, writing at end of file.
*/
void open(const char* path, openmode mode = in | out) {
FatStreamBase::open(path, mode);
}
/** \return True if stream is open else false. */
bool is_open() {
return FatFile::isOpen();
}
protected:
/// @cond SHOW_PROTECTED
/** Internal - do not use
* \return
*/
int16_t getch() {
return FatStreamBase::getch();
}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {
FatFile::getpos(pos);
}
/** Internal - do not use
* \param[in] c
*/
void putch(char c) {
FatStreamBase::putch(c);
}
/** Internal - do not use
* \param[in] str
*/
void putstr(const char *str) {
FatStreamBase::putstr(str);
}
/** Internal - do not use
* \param[in] pos
*/
bool seekoff(off_type off, seekdir way) {
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {
return FatStreamBase::seekpos(pos);
}
void setpos(FatPos_t* pos) {
FatFile::setpos(pos);
}
bool sync() {
return FatStreamBase::sync();
}
pos_type tellpos() {
return FatStreamBase::curPosition();
}
/// @endcond
};
//==============================================================================
/**
* \class ifstream
* \brief file input stream.
*/
class ifstream : public istream, FatStreamBase {
public:
using istream::peek;
ifstream() {}
/** Constructor with open
* \param[in] path file to open
* \param[in] mode open mode
*/
explicit ifstream(const char* path, openmode mode = in) {
open(path, mode);
}
#if DESTRUCTOR_CLOSES_FILE
~ifstream() {}
#endif // DESTRUCTOR_CLOSES_FILE
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {
FatFile::close();
}
/** \return True if stream is open else false. */
bool is_open() {
return FatFile::isOpen();
}
/** Open an ifstream
* \param[in] path file to open
* \param[in] mode open mode
*
* \a mode See fstream::open() for valid modes.
*/
void open(const char* path, openmode mode = in) {
FatStreamBase::open(path, mode | in);
}
protected:
/// @cond SHOW_PROTECTED
/** Internal - do not use
* \return
*/
int16_t getch() {
return FatStreamBase::getch();
}
/** Internal - do not use
* \param[out] pos
*/
void getpos(FatPos_t* pos) {
FatFile::getpos(pos);
}
/** Internal - do not use
* \param[in] pos
*/
bool seekoff(off_type off, seekdir way) {
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {
return FatStreamBase::seekpos(pos);
}
void setpos(FatPos_t* pos) {
FatFile::setpos(pos);
}
pos_type tellpos() {
return FatStreamBase::curPosition();
}
/// @endcond
};
//==============================================================================
/**
* \class ofstream
* \brief file output stream.
*/
class ofstream : public ostream, FatStreamBase {
public:
ofstream() {}
/** Constructor with open
* \param[in] path file to open
* \param[in] mode open mode
*/
explicit ofstream(const char* path, ios::openmode mode = out) {
open(path, mode);
}
#if DESTRUCTOR_CLOSES_FILE
~ofstream() {}
#endif // DESTRUCTOR_CLOSES_FILE
/** Clear state and writeError
* \param[in] state new state for stream
*/
void clear(iostate state = goodbit) {
ios::clear(state);
FatFile::clearWriteError();
}
/** Close a file and force cached data and directory information
* to be written to the storage device.
*/
void close() {
FatFile::close();
}
/** Open an ofstream
* \param[in] path file to open
* \param[in] mode open mode
*
* \a mode See fstream::open() for valid modes.
*/
void open(const char* path, openmode mode = out) {
FatStreamBase::open(path, mode | out);
}
/** \return True if stream is open else false. */
bool is_open() {
return FatFile::isOpen();
}
protected:
/// @cond SHOW_PROTECTED
/**
* Internal do not use
* \param[in] c
*/
void putch(char c) {
FatStreamBase::putch(c);
}
void putstr(const char* str) {
FatStreamBase::putstr(str);
}
bool seekoff(off_type off, seekdir way) {
return FatStreamBase::seekoff(off, way);
}
bool seekpos(pos_type pos) {
return FatStreamBase::seekpos(pos);
}
/**
* Internal do not use
* \param[in] b
*/
bool sync() {
return FatStreamBase::sync();
}
pos_type tellpos() {
return FatStreamBase::curPosition();
}
/// @endcond
};
//------------------------------------------------------------------------------
#endif // fstream_h

View file

@ -0,0 +1,423 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ios_h
#define ios_h
#include "FatFile.h"
/**
* \file
* \brief \ref ios_base and \ref ios classes
*/
//==============================================================================
/**
* \class ios_base
* \brief Base class for all streams
*/
class ios_base {
public:
/** typedef for iostate bitmask */
typedef unsigned char iostate;
// State flags.
/** iostate for no flags */
static const iostate goodbit = 0x00;
/** iostate bad bit for a nonrecoverable error. */
static const iostate badbit = 0X01;
/** iostate bit for end of file reached */
static const iostate eofbit = 0x02;
/** iostate fail bit for nonfatal error */
static const iostate failbit = 0X04;
/**
* unsigned size that can represent maximum file size.
* (violates spec - should be signed)
*/
typedef uint32_t streamsize;
/** type for absolute seek position */
typedef uint32_t pos_type;
/** type for relative seek offset */
typedef int32_t off_type;
/** enumerated type for the direction of relative seeks */
enum seekdir {
/** seek relative to the beginning of the stream */
beg,
/** seek relative to the current stream position */
cur,
/** seek relative to the end of the stream */
end
};
/** type for format flags */
typedef unsigned int fmtflags;
/** left adjust fields */
static const fmtflags left = 0x0001;
/** right adjust fields */
static const fmtflags right = 0x0002;
/** fill between sign/base prefix and number */
static const fmtflags internal = 0x0004;
/** base 10 flag*/
static const fmtflags dec = 0x0008;
/** base 16 flag */
static const fmtflags hex = 0x0010;
/** base 8 flag */
static const fmtflags oct = 0x0020;
// static const fmtflags fixed = 0x0040;
// static const fmtflags scientific = 0x0080;
/** use strings true/false for bool */
static const fmtflags boolalpha = 0x0100;
/** use prefix 0X for hex and 0 for oct */
static const fmtflags showbase = 0x0200;
/** always show '.' for floating numbers */
static const fmtflags showpoint = 0x0400;
/** show + sign for nonnegative numbers */
static const fmtflags showpos = 0x0800;
/** skip initial white space */
static const fmtflags skipws = 0x1000;
// static const fmtflags unitbuf = 0x2000;
/** use uppercase letters in number representations */
static const fmtflags uppercase = 0x4000;
/** mask for adjustfield */
static const fmtflags adjustfield = left | right | internal;
/** mask for basefield */
static const fmtflags basefield = dec | hex | oct;
// static const fmtflags floatfield = scientific | fixed;
//----------------------------------------------------------------------------
/** typedef for iostream open mode */
typedef uint8_t openmode;
// Openmode flags.
/** seek to end before each write */
static const openmode app = 0X4;
/** open and seek to end immediately after opening */
static const openmode ate = 0X8;
/** perform input and output in binary mode (as opposed to text mode) */
static const openmode binary = 0X10;
/** open for input */
static const openmode in = 0X20;
/** open for output */
static const openmode out = 0X40;
/** truncate an existing stream when opening */
static const openmode trunc = 0X80;
//----------------------------------------------------------------------------
ios_base() : m_fill(' '), m_fmtflags(dec | right | skipws)
, m_precision(2), m_width(0) {}
/** \return fill character */
char fill() {
return m_fill;
}
/** Set fill character
* \param[in] c new fill character
* \return old fill character
*/
char fill(char c) {
char r = m_fill;
m_fill = c;
return r;
}
/** \return format flags */
fmtflags flags() const {
return m_fmtflags;
}
/** set format flags
* \param[in] fl new flag
* \return old flags
*/
fmtflags flags(fmtflags fl) {
fmtflags tmp = m_fmtflags;
m_fmtflags = fl;
return tmp;
}
/** \return precision */
int precision() const {
return m_precision;
}
/** set precision
* \param[in] n new precision
* \return old precision
*/
int precision(unsigned int n) {
int r = m_precision;
m_precision = n;
return r;
}
/** set format flags
* \param[in] fl new flags to be or'ed in
* \return old flags
*/
fmtflags setf(fmtflags fl) {
fmtflags r = m_fmtflags;
m_fmtflags |= fl;
return r;
}
/** modify format flags
* \param[in] mask flags to be removed
* \param[in] fl flags to be set after mask bits have been cleared
* \return old flags
*/
fmtflags setf(fmtflags fl, fmtflags mask) {
fmtflags r = m_fmtflags;
m_fmtflags &= ~mask;
m_fmtflags |= fl;
return r;
}
/** clear format flags
* \param[in] fl flags to be cleared
* \return old flags
*/
void unsetf(fmtflags fl) {
m_fmtflags &= ~fl;
}
/** \return width */
unsigned width() {
return m_width;
}
/** set width
* \param[in] n new width
* \return old width
*/
unsigned width(unsigned n) {
unsigned r = m_width;
m_width = n;
return r;
}
protected:
/** \return current number base */
uint8_t flagsToBase() {
uint8_t f = flags() & basefield;
return f == oct ? 8 : f != hex ? 10 : 16;
}
private:
char m_fill;
fmtflags m_fmtflags;
unsigned char m_precision;
unsigned int m_width;
};
//------------------------------------------------------------------------------
/** function for boolalpha manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& boolalpha(ios_base& str) {
str.setf(ios_base::boolalpha);
return str;
}
/** function for dec manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& dec(ios_base& str) {
str.setf(ios_base::dec, ios_base::basefield);
return str;
}
/** function for hex manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& hex(ios_base& str) {
str.setf(ios_base::hex, ios_base::basefield);
return str;
}
/** function for internal manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& internal(ios_base& str) {
str.setf(ios_base::internal, ios_base::adjustfield);
return str;
}
/** function for left manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& left(ios_base& str) {
str.setf(ios_base::left, ios_base::adjustfield);
return str;
}
/** function for noboolalpha manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& noboolalpha(ios_base& str) {
str.unsetf(ios_base::boolalpha);
return str;
}
/** function for noshowbase manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& noshowbase(ios_base& str) {
str.unsetf(ios_base::showbase);
return str;
}
/** function for noshowpoint manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& noshowpoint(ios_base& str) {
str.unsetf(ios_base::showpoint);
return str;
}
/** function for noshowpos manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& noshowpos(ios_base& str) {
str.unsetf(ios_base::showpos);
return str;
}
/** function for noskipws manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& noskipws(ios_base& str) {
str.unsetf(ios_base::skipws);
return str;
}
/** function for nouppercase manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& nouppercase(ios_base& str) {
str.unsetf(ios_base::uppercase);
return str;
}
/** function for oct manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& oct(ios_base& str) {
str.setf(ios_base::oct, ios_base::basefield);
return str;
}
/** function for right manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& right(ios_base& str) {
str.setf(ios_base::right, ios_base::adjustfield);
return str;
}
/** function for showbase manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& showbase(ios_base& str) {
str.setf(ios_base::showbase);
return str;
}
/** function for showpos manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& showpos(ios_base& str) {
str.setf(ios_base::showpos);
return str;
}
/** function for showpoint manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& showpoint(ios_base& str) {
str.setf(ios_base::showpoint);
return str;
}
/** function for skipws manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& skipws(ios_base& str) {
str.setf(ios_base::skipws);
return str;
}
/** function for uppercase manipulator
* \param[in] str The stream
* \return The stream
*/
inline ios_base& uppercase(ios_base& str) {
str.setf(ios_base::uppercase);
return str;
}
//==============================================================================
/**
* \class ios
* \brief Error and state information for all streams
*/
class ios : public ios_base {
public:
/** Create ios with no error flags set */
ios() : m_iostate(0) {}
/** \return null pointer if fail() is true. */
operator const void*() const {
return !fail() ? reinterpret_cast<const void*>(this) : 0;
}
/** \return true if fail() else false. */
bool operator!() const {
return fail();
}
/** \return The iostate flags for this file. */
iostate rdstate() const {
return m_iostate;
}
/** \return True if no iostate flags are set else false. */
bool good() const {
return m_iostate == goodbit;
}
/** \return true if end of file has been reached else false.
*
* Warning: An empty file returns false before the first read.
*
* Moral: eof() is only useful in combination with fail(), to find out
* whether EOF was the cause for failure
*/
bool eof() const {
return m_iostate & eofbit;
}
/** \return true if any iostate bit other than eof are set else false. */
bool fail() const {
return m_iostate & (failbit | badbit);
}
/** \return true if bad bit is set else false. */
bool bad() const {
return m_iostate & badbit;
}
/** Clear iostate bits.
*
* \param[in] state The flags you want to set after clearing all flags.
**/
void clear(iostate state = goodbit) {
m_iostate = state;
}
/** Set iostate bits.
*
* \param[in] state Bitts to set.
**/
void setstate(iostate state) {
m_iostate |= state;
}
private:
iostate m_iostate;
};
#endif // ios_h

View file

@ -0,0 +1,158 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef iostream_h
#define iostream_h
/**
* \file
* \brief \ref iostream class
*/
#include "istream.h"
#include "ostream.h"
/** Skip white space
* \param[in] is the Stream
* \return The stream
*/
inline istream& ws(istream& is) {
is.skipWhite();
return is;
}
/** insert endline
* \param[in] os The Stream
* \return The stream
*/
inline ostream& endl(ostream& os) {
os.put('\n');
#if ENDL_CALLS_FLUSH
os.flush();
#endif // ENDL_CALLS_FLUSH
return os;
}
/** flush manipulator
* \param[in] os The stream
* \return The stream
*/
inline ostream& flush(ostream& os) {
os.flush();
return os;
}
/**
* \struct setfill
* \brief type for setfill manipulator
*/
struct setfill {
/** fill character */
char c;
/** constructor
*
* \param[in] arg new fill character
*/
explicit setfill(char arg) : c(arg) {}
};
/** setfill manipulator
* \param[in] os the stream
* \param[in] arg set setfill object
* \return the stream
*/
inline ostream &operator<< (ostream &os, const setfill &arg) {
os.fill(arg.c);
return os;
}
/** setfill manipulator
* \param[in] obj the stream
* \param[in] arg set setfill object
* \return the stream
*/
inline istream &operator>>(istream &obj, const setfill &arg) {
obj.fill(arg.c);
return obj;
}
//------------------------------------------------------------------------------
/** \struct setprecision
* \brief type for setprecision manipulator
*/
struct setprecision {
/** precision */
unsigned int p;
/** constructor
* \param[in] arg new precision
*/
explicit setprecision(unsigned int arg) : p(arg) {}
};
/** setprecision manipulator
* \param[in] os the stream
* \param[in] arg set setprecision object
* \return the stream
*/
inline ostream &operator<< (ostream &os, const setprecision &arg) {
os.precision(arg.p);
return os;
}
/** setprecision manipulator
* \param[in] is the stream
* \param[in] arg set setprecision object
* \return the stream
*/
inline istream &operator>>(istream &is, const setprecision &arg) {
is.precision(arg.p);
return is;
}
//------------------------------------------------------------------------------
/** \struct setw
* \brief type for setw manipulator
*/
struct setw {
/** width */
unsigned w;
/** constructor
* \param[in] arg new width
*/
explicit setw(unsigned arg) : w(arg) {}
};
/** setw manipulator
* \param[in] os the stream
* \param[in] arg set setw object
* \return the stream
*/
inline ostream &operator<< (ostream &os, const setw &arg) {
os.width(arg.w);
return os;
}
/** setw manipulator
* \param[in] is the stream
* \param[in] arg set setw object
* \return the stream
*/
inline istream &operator>>(istream &is, const setw &arg) {
is.width(arg.w);
return is;
}
//==============================================================================
/**
* \class iostream
* \brief Input/Output stream
*/
class iostream : public istream, public ostream {
};
#endif // iostream_h

View file

@ -0,0 +1,396 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
// #include <ctype.h>
#include <float.h>
#include <ctype.h>
#include "istream.h"
//------------------------------------------------------------------------------
int istream::get() {
int c;
m_gcount = 0;
c = getch();
if (c < 0) {
setstate(failbit);
} else {
m_gcount = 1;
}
return c;
}
//------------------------------------------------------------------------------
istream& istream::get(char& c) {
int tmp = get();
if (tmp >= 0) {
c = tmp;
}
return *this;
}
//------------------------------------------------------------------------------
istream& istream::get(char *str, streamsize n, char delim) {
int c;
FatPos_t pos;
m_gcount = 0;
while ((m_gcount + 1) < n) {
c = getch(&pos);
if (c < 0) {
break;
}
if (c == delim) {
setpos(&pos);
break;
}
str[m_gcount++] = c;
}
if (n > 0) {
str[m_gcount] = '\0';
}
if (m_gcount == 0) {
setstate(failbit);
}
return *this;
}
//------------------------------------------------------------------------------
void istream::getBool(bool *b) {
if ((flags() & boolalpha) == 0) {
getNumber(b);
return;
}
#ifdef __AVR__
PGM_P truePtr = PSTR("true");
PGM_P falsePtr = PSTR("false");
#else // __AVR__
const char* truePtr = "true";
const char* falsePtr = "false";
#endif // __AVR
const uint8_t true_len = 4;
const uint8_t false_len = 5;
bool trueOk = true;
bool falseOk = true;
uint8_t i = 0;
int c = readSkip();
while (1) {
#ifdef __AVR__
falseOk = falseOk && c == pgm_read_byte(falsePtr + i);
trueOk = trueOk && c == pgm_read_byte(truePtr + i);
#else // __AVR__
falseOk = falseOk && c == falsePtr[i];
trueOk = trueOk && c == truePtr[i];
#endif // __AVR__
if (trueOk == false && falseOk == false) {
break;
}
i++;
if (trueOk && i == true_len) {
*b = true;
return;
}
if (falseOk && i == false_len) {
*b = false;
return;
}
c = getch();
}
setstate(failbit);
}
//------------------------------------------------------------------------------
void istream::getChar(char* ch) {
int16_t c = readSkip();
if (c < 0) {
setstate(failbit);
} else {
*ch = c;
}
}
//------------------------------------------------------------------------------
//
// http://www.exploringbinary.com/category/numbers-in-computers/
//
int16_t const EXP_LIMIT = 100;
static const uint32_t uint32_max = (uint32_t)-1;
bool istream::getDouble(double* value) {
bool got_digit = false;
bool got_dot = false;
bool neg;
int16_t c;
bool expNeg = false;
int16_t exp = 0;
int16_t fracExp = 0;
uint32_t frac = 0;
FatPos_t endPos;
double pow10;
double v;
getpos(&endPos);
c = readSkip();
neg = c == '-';
if (c == '-' || c == '+') {
c = getch();
}
while (1) {
if (isdigit(c)) {
got_digit = true;
if (frac < uint32_max/10) {
frac = frac * 10 + (c - '0');
if (got_dot) {
fracExp--;
}
} else {
if (!got_dot) {
fracExp++;
}
}
} else if (!got_dot && c == '.') {
got_dot = true;
} else {
break;
}
if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) {
goto fail;
}
c = getch(&endPos);
}
if (!got_digit) {
goto fail;
}
if (c == 'e' || c == 'E') {
c = getch();
expNeg = c == '-';
if (c == '-' || c == '+') {
c = getch();
}
while (isdigit(c)) {
if (exp > EXP_LIMIT) {
goto fail;
}
exp = exp * 10 + (c - '0');
c = getch(&endPos);
}
}
v = static_cast<double>(frac);
exp = expNeg ? fracExp - exp : fracExp + exp;
expNeg = exp < 0;
if (expNeg) {
exp = -exp;
}
pow10 = 10.0;
while (exp) {
if (exp & 1) {
if (expNeg) {
// check for underflow
if (v < FLT_MIN * pow10 && frac != 0) {
goto fail;
}
v /= pow10;
} else {
// check for overflow
if (v > FLT_MAX / pow10) {
goto fail;
}
v *= pow10;
}
}
pow10 *= pow10;
exp >>= 1;
}
setpos(&endPos);
*value = neg ? -v : v;
return true;
fail:
// error restore position to last good place
setpos(&endPos);
setstate(failbit);
return false;
}
//------------------------------------------------------------------------------
istream& istream::getline(char *str, streamsize n, char delim) {
FatPos_t pos;
int c;
m_gcount = 0;
if (n > 0) {
str[0] = '\0';
}
while (1) {
c = getch(&pos);
if (c < 0) {
break;
}
if (c == delim) {
m_gcount++;
break;
}
if ((m_gcount + 1) >= n) {
setpos(&pos);
setstate(failbit);
break;
}
str[m_gcount++] = c;
str[m_gcount] = '\0';
}
if (m_gcount == 0) {
setstate(failbit);
}
return *this;
}
//------------------------------------------------------------------------------
bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) {
int16_t c;
int8_t any = 0;
int8_t have_zero = 0;
uint8_t neg;
uint32_t val = 0;
uint32_t cutoff;
uint8_t cutlim;
FatPos_t endPos;
uint8_t f = flags() & basefield;
uint8_t base = f == oct ? 8 : f != hex ? 10 : 16;
getpos(&endPos);
c = readSkip();
neg = c == '-' ? 1 : 0;
if (c == '-' || c == '+') {
c = getch();
}
if (base == 16 && c == '0') { // TESTSUITE
c = getch(&endPos);
if (c == 'X' || c == 'x') {
c = getch();
// remember zero in case no hex digits follow x/X
have_zero = 1;
} else {
any = 1;
}
}
// set values for overflow test
cutoff = neg ? negMax : posMax;
cutlim = cutoff % base;
cutoff /= base;
while (1) {
if (isdigit(c)) {
c -= '0';
} else if (isalpha(c)) {
c -= isupper(c) ? 'A' - 10 : 'a' - 10;
} else {
break;
}
if (c >= base) {
break;
}
if (val > cutoff || (val == cutoff && c > cutlim)) {
// indicate overflow error
any = -1;
break;
}
val = val * base + c;
c = getch(&endPos);
any = 1;
}
setpos(&endPos);
if (any > 0 || (have_zero && any >= 0)) {
*num = neg ? -val : val;
return true;
}
setstate(failbit);
return false;
}
//------------------------------------------------------------------------------
void istream::getStr(char *str) {
FatPos_t pos;
uint16_t i = 0;
uint16_t m = width() ? width() - 1 : 0XFFFE;
if (m != 0) {
getpos(&pos);
int c = readSkip();
while (i < m) {
if (c < 0) {
break;
}
if (isspace(c)) {
setpos(&pos);
break;
}
str[i++] = c;
c = getch(&pos);
}
}
str[i] = '\0';
if (i == 0) {
setstate(failbit);
}
width(0);
}
//------------------------------------------------------------------------------
istream& istream::ignore(streamsize n, int delim) {
int c;
m_gcount = 0;
while (m_gcount < n) {
c = getch();
if (c < 0) {
break;
}
m_gcount++;
if (c == delim) {
break;
}
}
return *this;
}
//------------------------------------------------------------------------------
int istream::peek() {
int16_t c;
FatPos_t pos;
m_gcount = 0;
getpos(&pos);
c = getch();
if (c < 0) {
if (!bad()) {
setstate(eofbit);
}
} else {
setpos(&pos);
}
return c;
}
//------------------------------------------------------------------------------
int16_t istream::readSkip() {
int16_t c;
do {
c = getch();
} while (isspace(c) && (flags() & skipws));
return c;
}
//------------------------------------------------------------------------------
/** used to implement ws() */
void istream::skipWhite() {
int c;
FatPos_t pos;
do {
c = getch(&pos);
} while (isspace(c));
setpos(&pos);
}

View file

@ -0,0 +1,384 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef istream_h
#define istream_h
/**
* \file
* \brief \ref istream class
*/
#include "ios.h"
/**
* \class istream
* \brief Input Stream
*/
class istream : public virtual ios {
public:
istream() {}
/** call manipulator
* \param[in] pf function to call
* \return the stream
*/
istream& operator>>(istream& (*pf)(istream& str)) {
return pf(*this);
}
/** call manipulator
* \param[in] pf function to call
* \return the stream
*/
istream& operator>>(ios_base& (*pf)(ios_base& str)) {
pf(*this);
return *this;
}
/** call manipulator
* \param[in] pf function to call
* \return the stream
*/
istream& operator>>(ios& (*pf)(ios& str)) {
pf(*this);
return *this;
}
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(char *str) {
getStr(str);
return *this;
}
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(char& ch) {
getChar(&ch);
return *this;
}
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(signed char *str) {
getStr(reinterpret_cast<char*>(str));
return *this;
}
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(signed char& ch) {
getChar(reinterpret_cast<char*>(&ch));
return *this;
}
/**
* Extract a character string
* \param[out] str location to store the string.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(unsigned char *str) {
getStr(reinterpret_cast<char*>(str));
return *this;
}
/**
* Extract a character
* \param[out] ch location to store the character.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(unsigned char& ch) {
getChar(reinterpret_cast<char*>(&ch));
return *this;
}
/**
* Extract a value of type bool.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>>(bool& arg) {
getBool(&arg);
return *this;
}
/**
* Extract a value of type short.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(short& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type unsigned short.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(unsigned short& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type int.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(int& arg) {
getNumber(&arg);
return *this;
}
/**
* Extract a value of type unsigned int.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(unsigned int& arg) {
getNumber(&arg);
return *this;
}
/**
* Extract a value of type long.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(long& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type unsigned long.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>>(unsigned long& arg) { // NOLINT
getNumber(&arg);
return *this;
}
/**
* Extract a value of type double.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>> (double& arg) {
getDouble(&arg);
return *this;
}
/**
* Extract a value of type float.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream &operator>> (float& arg) {
double v;
getDouble(&v);
arg = v;
return *this;
}
/**
* Extract a value of type void*.
* \param[out] arg location to store the value.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& operator>> (void*& arg) {
uint32_t val;
getNumber(&val);
arg = reinterpret_cast<void*>(val);
return *this;
}
/**
* \return The number of characters extracted by the last unformatted
* input function.
*/
streamsize gcount() const {
return m_gcount;
}
/**
* Extract a character if one is available.
*
* \return The character or -1 if a failure occurs. A failure is indicated
* by the stream state.
*/
int get();
/**
* Extract a character if one is available.
*
* \param[out] ch location to receive the extracted character.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
istream& get(char& ch);
/**
* Extract characters.
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
* \param[in] delim Delimiter
*
* Characters are extracted until extraction fails, n is less than 1,
* n-1 characters are extracted, or the next character equals
* \a delim (delim is not extracted). If no characters are extracted
* failbit is set. If end-of-file occurs the eofbit is set.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
istream& get(char *str, streamsize n, char delim = '\n');
/**
* Extract characters
*
* \param[out] str Location to receive extracted characters.
* \param[in] n Size of str.
* \param[in] delim Delimiter
*
* Characters are extracted until extraction fails,
* the next character equals \a delim (delim is extracted), or n-1
* characters are extracted.
*
* The failbit is set if no characters are extracted or n-1 characters
* are extracted. If end-of-file occurs the eofbit is set.
*
* \return always returns *this. A failure is indicated by the stream state.
*/
istream& getline(char *str, streamsize n, char delim = '\n');
/**
* Extract characters and discard them.
*
* \param[in] n maximum number of characters to ignore.
* \param[in] delim Delimiter.
*
* Characters are extracted until extraction fails, \a n characters
* are extracted, or the next input character equals \a delim
* (the delimiter is extracted). If end-of-file occurs the eofbit is set.
*
* Failures are indicated by the state of the stream.
*
* \return *this
*
*/
istream& ignore(streamsize n = 1, int delim = -1);
/**
* Return the next available character without consuming it.
*
* \return The character if the stream state is good else -1;
*
*/
int peek();
// istream& read(char *str, streamsize count);
// streamsize readsome(char *str, streamsize count);
/**
* \return the stream position
*/
pos_type tellg() {
return tellpos();
}
/**
* Set the stream position
* \param[in] pos The absolute position in which to move the read pointer.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& seekg(pos_type pos) {
if (!seekpos(pos)) {
setstate(failbit);
}
return *this;
}
/**
* Set the stream position.
*
* \param[in] off An offset to move the read pointer relative to way.
* \a off is a signed 32-bit int so the offset is limited to +- 2GB.
* \param[in] way One of ios::beg, ios::cur, or ios::end.
* \return Is always *this. Failure is indicated by the state of *this.
*/
istream& seekg(off_type off, seekdir way) {
if (!seekoff(off, way)) {
setstate(failbit);
}
return *this;
}
void skipWhite();
protected:
/// @cond SHOW_PROTECTED
/**
* Internal - do not use
* \return
*/
virtual int16_t getch() = 0;
/**
* Internal - do not use
* \param[out] pos
* \return
*/
int16_t getch(FatPos_t* pos) {
getpos(pos);
return getch();
}
/**
* Internal - do not use
* \param[out] pos
*/
virtual void getpos(FatPos_t* pos) = 0;
/**
* Internal - do not use
* \param[in] pos
*/
virtual bool seekoff(off_type off, seekdir way) = 0;
virtual bool seekpos(pos_type pos) = 0;
virtual void setpos(FatPos_t* pos) = 0;
virtual pos_type tellpos() = 0;
/// @endcond
private:
void getBool(bool *b);
void getChar(char* ch);
bool getDouble(double* value);
template <typename T> void getNumber(T* value);
bool getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num);
void getStr(char *str);
int16_t readSkip();
size_t m_gcount;
};
//------------------------------------------------------------------------------
template <typename T>
void istream::getNumber(T* value) {
uint32_t tmp;
if ((T)-1 < 0) {
// number is signed, max positive value
uint32_t const m = ((uint32_t)-1) >> (33 - sizeof(T) * 8);
// max absolute value of negative number is m + 1.
if (getNumber(m, m + 1, &tmp)) {
*value = (T)tmp;
}
} else {
// max unsigned value for T
uint32_t const m = (T)-1;
if (getNumber(m, m, &tmp)) {
*value = (T)tmp;
}
}
}
#endif // istream_h

View file

@ -0,0 +1,196 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include <string.h>
#include "ostream.h"
#ifndef PSTR
#define PSTR(x) x
#endif
//------------------------------------------------------------------------------
void ostream::do_fill(unsigned len) {
for (; len < width(); len++) {
putch(fill());
}
width(0);
}
//------------------------------------------------------------------------------
void ostream::fill_not_left(unsigned len) {
if ((flags() & adjustfield) != left) {
do_fill(len);
}
}
//------------------------------------------------------------------------------
char* ostream::fmtNum(uint32_t n, char *ptr, uint8_t base) {
char a = flags() & uppercase ? 'A' - 10 : 'a' - 10;
do {
uint32_t m = n;
n /= base;
char c = m - base * n;
*--ptr = c < 10 ? c + '0' : c + a;
} while (n);
return ptr;
}
//------------------------------------------------------------------------------
void ostream::putBool(bool b) {
if (flags() & boolalpha) {
if (b) {
putPgm(PSTR("true"));
} else {
putPgm(PSTR("false"));
}
} else {
putChar(b ? '1' : '0');
}
}
//------------------------------------------------------------------------------
void ostream::putChar(char c) {
fill_not_left(1);
putch(c);
do_fill(1);
}
//------------------------------------------------------------------------------
void ostream::putDouble(double n) {
uint8_t nd = precision();
double round = 0.5;
char sign;
char buf[13]; // room for sign, 10 digits, '.', and zero byte
char *end = buf + sizeof(buf) - 1;
char *str = end;
// terminate string
*end = '\0';
// get sign and make nonnegative
if (n < 0.0) {
sign = '-';
n = -n;
} else {
sign = flags() & showpos ? '+' : '\0';
}
// check for larger than uint32_t
if (n > 4.0E9) {
putPgm(PSTR("BIG FLT"));
return;
}
// round up and separate int and fraction parts
for (uint8_t i = 0; i < nd; ++i) {
round *= 0.1;
}
n += round;
uint32_t intPart = n;
double fractionPart = n - intPart;
// format intPart and decimal point
if (nd || (flags() & showpoint)) {
*--str = '.';
}
str = fmtNum(intPart, str, 10);
// calculate length for fill
uint8_t len = sign ? 1 : 0;
len += nd + end - str;
// extract adjust field
fmtflags adj = flags() & adjustfield;
if (adj == internal) {
if (sign) {
putch(sign);
}
do_fill(len);
} else {
// do fill for internal or right
fill_not_left(len);
if (sign) {
*--str = sign;
}
}
putstr(str);
// output fraction
while (nd-- > 0) {
fractionPart *= 10.0;
int digit = static_cast<int>(fractionPart);
putch(digit + '0');
fractionPart -= digit;
}
// do fill if not done above
do_fill(len);
}
//------------------------------------------------------------------------------
void ostream::putNum(int32_t n) {
bool neg = n < 0 && flagsToBase() == 10;
if (neg) {
n = -n;
}
putNum(n, neg);
}
//------------------------------------------------------------------------------
void ostream::putNum(uint32_t n, bool neg) {
char buf[13];
char* end = buf + sizeof(buf) - 1;
char* num;
char* str;
uint8_t base = flagsToBase();
*end = '\0';
str = num = fmtNum(n, end, base);
if (base == 10) {
if (neg) {
*--str = '-';
} else if (flags() & showpos) {
*--str = '+';
}
} else if (flags() & showbase) {
if (flags() & hex) {
*--str = flags() & uppercase ? 'X' : 'x';
}
*--str = '0';
}
uint8_t len = end - str;
fmtflags adj = flags() & adjustfield;
if (adj == internal) {
while (str < num) {
putch(*str++);
}
}
if (adj != left) {
do_fill(len);
}
putstr(str);
do_fill(len);
}
//------------------------------------------------------------------------------
void ostream::putPgm(const char* str) {
int n;
for (n = 0; pgm_read_byte(&str[n]); n++) {}
fill_not_left(n);
for (uint8_t c; (c = pgm_read_byte(str)); str++) {
putch(c);
}
do_fill(n);
}
//------------------------------------------------------------------------------
void ostream::putStr(const char *str) {
unsigned n = strlen(str);
fill_not_left(n);
putstr(str);
do_fill(n);
}

View file

@ -0,0 +1,276 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef ostream_h
#define ostream_h
/**
* \file
* \brief \ref ostream class
*/
#include "ios.h"
//==============================================================================
/**
* \class ostream
* \brief Output Stream
*/
class ostream : public virtual ios {
public:
ostream() {}
/** call manipulator
* \param[in] pf function to call
* \return the stream
*/
ostream& operator<< (ostream& (*pf)(ostream& str)) {
return pf(*this);
}
/** call manipulator
* \param[in] pf function to call
* \return the stream
*/
ostream& operator<< (ios_base& (*pf)(ios_base& str)) {
pf(*this);
return *this;
}
/** Output bool
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (bool arg) {
putBool(arg);
return *this;
}
/** Output string
* \param[in] arg string to output
* \return the stream
*/
ostream &operator<< (const char *arg) {
putStr(arg);
return *this;
}
/** Output string
* \param[in] arg string to output
* \return the stream
*/
ostream &operator<< (const signed char *arg) {
putStr((const char*)arg);
return *this;
}
/** Output string
* \param[in] arg string to output
* \return the stream
*/
ostream &operator<< (const unsigned char *arg) {
putStr((const char*)arg);
return *this;
}
/** Output character
* \param[in] arg character to output
* \return the stream
*/
ostream &operator<< (char arg) {
putChar(arg);
return *this;
}
/** Output character
* \param[in] arg character to output
* \return the stream
*/
ostream &operator<< (signed char arg) {
putChar(static_cast<char>(arg));
return *this;
}
/** Output character
* \param[in] arg character to output
* \return the stream
*/
ostream &operator<< (unsigned char arg) {
putChar(static_cast<char>(arg));
return *this;
}
/** Output double
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (double arg) {
putDouble(arg);
return *this;
}
/** Output float
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (float arg) {
putDouble(arg);
return *this;
}
/** Output signed short
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (short arg) { // NOLINT
putNum((int32_t)arg);
return *this;
}
/** Output unsigned short
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (unsigned short arg) { // NOLINT
putNum((uint32_t)arg);
return *this;
}
/** Output signed int
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (int arg) {
putNum((int32_t)arg);
return *this;
}
/** Output unsigned int
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (unsigned int arg) {
putNum((uint32_t)arg);
return *this;
}
/** Output signed long
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (long arg) { // NOLINT
putNum((int32_t)arg);
return *this;
}
/** Output unsigned long
* \param[in] arg value to output
* \return the stream
*/
ostream &operator<< (unsigned long arg) { // NOLINT
putNum((uint32_t)arg);
return *this;
}
/** Output pointer
* \param[in] arg value to output
* \return the stream
*/
ostream& operator<< (const void* arg) {
putNum(reinterpret_cast<uint32_t>(arg));
return *this;
}
#if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
/** Output a string from flash using the Arduino F() macro.
* \param[in] arg pointing to flash string
* \return the stream
*/
ostream &operator<< (const __FlashStringHelper *arg) {
putPgm(reinterpret_cast<const char*>(arg));
return *this;
}
#endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
/**
* Puts a character in a stream.
*
* The unformatted output function inserts the element \a ch.
* It returns *this.
*
* \param[in] ch The character
* \return A reference to the ostream object.
*/
ostream& put(char ch) {
putch(ch);
return *this;
}
// ostream& write(char *str, streamsize count);
/**
* Flushes the buffer associated with this stream. The flush function
* calls the sync function of the associated file.
* \return A reference to the ostream object.
*/
ostream& flush() {
if (!sync()) {
setstate(badbit);
}
return *this;
}
/**
* \return the stream position
*/
pos_type tellp() {
return tellpos();
}
/**
* Set the stream position
* \param[in] pos The absolute position in which to move the write pointer.
* \return Is always *this. Failure is indicated by the state of *this.
*/
ostream& seekp(pos_type pos) {
if (!seekpos(pos)) {
setstate(failbit);
}
return *this;
}
/**
* Set the stream position.
*
* \param[in] off An offset to move the write pointer relative to way.
* \a off is a signed 32-bit int so the offset is limited to +- 2GB.
* \param[in] way One of ios::beg, ios::cur, or ios::end.
* \return Is always *this. Failure is indicated by the state of *this.
*/
ostream& seekp(off_type off, seekdir way) {
if (!seekoff(off, way)) {
setstate(failbit);
}
return *this;
}
protected:
/// @cond SHOW_PROTECTED
/** Put character with binary/text conversion
* \param[in] ch character to write
*/
virtual void putch(char ch) = 0;
virtual void putstr(const char *str) = 0;
virtual bool seekoff(off_type pos, seekdir way) = 0;
virtual bool seekpos(pos_type pos) = 0;
virtual bool sync() = 0;
virtual pos_type tellpos() = 0;
/// @endcond
private:
void do_fill(unsigned len);
void fill_not_left(unsigned len);
char* fmtNum(uint32_t n, char *ptr, uint8_t base);
void putBool(bool b);
void putChar(char c);
void putDouble(double n);
void putNum(uint32_t n, bool neg = false);
void putNum(int32_t n);
void putPgm(const char* str);
void putStr(const char* str);
};
#endif // ostream_h

View file

@ -0,0 +1,61 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef FreeStack_h
#define FreeStack_h
/**
* \file
* \brief FreeStack() function.
*/
#if defined(__AVR__) || defined(DOXYGEN)
/** boundary between stack and heap. */
extern char *__brkval;
/** End of bss section.*/
extern char __bss_end;
/** Amount of free stack space.
* \return The number of free bytes.
*/
static int FreeStack() {
char* sp = reinterpret_cast<char*>(SP);
return __brkval ? sp - __brkval : sp - &__bss_end;
// char top;
// return __brkval ? &top - __brkval : &top - &__bss_end;
}
#elif defined(PLATFORM_ID) // Particle board
static int FreeStack() {
return System.freeMemory();
}
#elif defined(__arm__)
extern "C" char* sbrk(int incr);
static int FreeStack() {
char top = 't';
return &top - reinterpret_cast<char*>(sbrk(0));
}
#else
#warning FreeStack is not defined for this system.
static int FreeStack() {
return 0;
}
#endif
#endif // FreeStack_h

View file

@ -0,0 +1,71 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SysCall.h"
#if defined(UDR0) || defined(DOXYGEN)
#include "MinimumSerial.h"
const uint16_t MIN_2X_BAUD = F_CPU/(4*(2*0XFFF + 1)) + 1;
//------------------------------------------------------------------------------
int MinimumSerial::available() {
return UCSR0A & (1 << RXC0) ? 1 : 0;
}
//------------------------------------------------------------------------------
void MinimumSerial::begin(uint32_t baud) {
uint16_t baud_setting;
// don't worry, the compiler will squeeze out F_CPU != 16000000UL
if ((F_CPU != 16000000UL || baud != 57600) && baud > MIN_2X_BAUD) {
// Double the USART Transmission Speed
UCSR0A = 1 << U2X0;
baud_setting = (F_CPU / 4 / baud - 1) / 2;
} else {
// hardcoded exception for compatibility with the bootloader shipped
// with the Duemilanove and previous boards and the firmware on the 8U2
// on the Uno and Mega 2560.
UCSR0A = 0;
baud_setting = (F_CPU / 8 / baud - 1) / 2;
}
// assign the baud_setting
UBRR0H = baud_setting >> 8;
UBRR0L = baud_setting;
// enable transmit and receive
UCSR0B |= (1 << TXEN0) | (1 << RXEN0);
}
//------------------------------------------------------------------------------
void MinimumSerial::flush() {
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
}
//------------------------------------------------------------------------------
int MinimumSerial::read() {
if (UCSR0A & (1 << RXC0)) {
return UDR0;
}
return -1;
}
//------------------------------------------------------------------------------
size_t MinimumSerial::write(uint8_t b) {
while (((1 << UDRIE0) & UCSR0B) || !(UCSR0A & (1 << UDRE0))) {}
UDR0 = b;
return 1;
}
#endif // defined(UDR0) || defined(DOXYGEN)

View file

@ -0,0 +1,67 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* \file
* \brief Minimal AVR Serial driver.
*/
#ifndef MinimumSerial_h
#define MinimumSerial_h
#include "SysCall.h"
//==============================================================================
/**
* \class MinimumSerial
* \brief mini serial class for the %SdFat library.
*/
class MinimumSerial : public Print {
public:
/** \return true for hardware serial */
operator bool() { return true; }
/**
* \return one if data is available.
*/
int available();
/**
* Set baud rate for serial port zero and enable in non interrupt mode.
* Do not call this function if you use another serial library.
* \param[in] baud rate
*/
void begin(uint32_t baud);
/** Wait for write done. */
void flush();
/**
* Unbuffered read
* \return -1 if no character is available or an available character.
*/
int read();
/**
* Unbuffered write
*
* \param[in] b byte to write.
* \return 1
*/
size_t write(uint8_t b);
using Print::write;
};
#endif // MinimumSerial_h

View file

@ -0,0 +1,485 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SdInfo_h
#define SdInfo_h
#include <stdint.h>
// Based on the document:
//
// SD Specifications
// Part 1
// Physical Layer
// Simplified Specification
// Version 5.00
// Aug 10, 2016
//
// https://www.sdcard.org/downloads/pls/
//------------------------------------------------------------------------------
// SD card errors
// See the SD Specification for command info.
typedef enum {
SD_CARD_ERROR_NONE = 0,
// Basic commands and switch command.
SD_CARD_ERROR_CMD0 = 0X20,
SD_CARD_ERROR_CMD2,
SD_CARD_ERROR_CMD3,
SD_CARD_ERROR_CMD6,
SD_CARD_ERROR_CMD7,
SD_CARD_ERROR_CMD8,
SD_CARD_ERROR_CMD9,
SD_CARD_ERROR_CMD10,
SD_CARD_ERROR_CMD12,
SD_CARD_ERROR_CMD13,
// Read, write, erase, and extension commands.
SD_CARD_ERROR_CMD17 = 0X30,
SD_CARD_ERROR_CMD18,
SD_CARD_ERROR_CMD24,
SD_CARD_ERROR_CMD25,
SD_CARD_ERROR_CMD32,
SD_CARD_ERROR_CMD33,
SD_CARD_ERROR_CMD38,
SD_CARD_ERROR_CMD58,
SD_CARD_ERROR_CMD59,
// Application specific commands.
SD_CARD_ERROR_ACMD6 = 0X40,
SD_CARD_ERROR_ACMD13,
SD_CARD_ERROR_ACMD23,
SD_CARD_ERROR_ACMD41,
// Read/write errors
SD_CARD_ERROR_READ = 0X50,
SD_CARD_ERROR_READ_CRC,
SD_CARD_ERROR_READ_FIFO,
SD_CARD_ERROR_READ_REG,
SD_CARD_ERROR_READ_START,
SD_CARD_ERROR_READ_TIMEOUT,
SD_CARD_ERROR_STOP_TRAN,
SD_CARD_ERROR_WRITE,
SD_CARD_ERROR_WRITE_FIFO,
SD_CARD_ERROR_WRITE_START,
SD_CARD_ERROR_FLASH_PROGRAMMING,
SD_CARD_ERROR_WRITE_TIMEOUT,
// Misc errors.
SD_CARD_ERROR_DMA = 0X60,
SD_CARD_ERROR_ERASE,
SD_CARD_ERROR_ERASE_SINGLE_BLOCK,
SD_CARD_ERROR_ERASE_TIMEOUT,
SD_CARD_ERROR_INIT_NOT_CALLED,
SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED
} sd_error_code_t;
//------------------------------------------------------------------------------
// card types
/** Standard capacity V1 SD card */
const uint8_t SD_CARD_TYPE_SD1 = 1;
/** Standard capacity V2 SD card */
const uint8_t SD_CARD_TYPE_SD2 = 2;
/** High Capacity SD card */
const uint8_t SD_CARD_TYPE_SDHC = 3;
//------------------------------------------------------------------------------
#define SD_SCK_HZ(maxSpeed) SPISettings(maxSpeed, MSBFIRST, SPI_MODE0)
#define SD_SCK_MHZ(maxMhz) SPISettings(1000000UL*maxMhz, MSBFIRST, SPI_MODE0)
// SPI divisor constants
/** Set SCK to max rate of F_CPU/2. */
#define SPI_FULL_SPEED SD_SCK_MHZ(50)
/** Set SCK rate to F_CPU/3 for Due */
#define SPI_DIV3_SPEED SD_SCK_HZ(F_CPU/3)
/** Set SCK rate to F_CPU/4. */
#define SPI_HALF_SPEED SD_SCK_HZ(F_CPU/4)
/** Set SCK rate to F_CPU/6 for Due */
#define SPI_DIV6_SPEED SD_SCK_HZ(F_CPU/6)
/** Set SCK rate to F_CPU/8. */
#define SPI_QUARTER_SPEED SD_SCK_HZ(F_CPU/8)
/** Set SCK rate to F_CPU/16. */
#define SPI_EIGHTH_SPEED SD_SCK_HZ(F_CPU/16)
/** Set SCK rate to F_CPU/32. */
#define SPI_SIXTEENTH_SPEED SD_SCK_HZ(F_CPU/32)
//------------------------------------------------------------------------------
// SD operation timeouts
/** CMD0 retry count */
const uint8_t SD_CMD0_RETRY = 10;
/** command timeout ms */
const uint16_t SD_CMD_TIMEOUT = 300;
/** init timeout ms */
const uint16_t SD_INIT_TIMEOUT = 2000;
/** erase timeout ms */
const uint16_t SD_ERASE_TIMEOUT = 10000;
/** read timeout ms */
const uint16_t SD_READ_TIMEOUT = 1000;
/** write time out ms */
const uint16_t SD_WRITE_TIMEOUT = 2000;
//------------------------------------------------------------------------------
// SD card commands
/** GO_IDLE_STATE - init card in spi mode if CS low */
const uint8_t CMD0 = 0X00;
/** ALL_SEND_CID - Asks any card to send the CID. */
const uint8_t CMD2 = 0X02;
/** SEND_RELATIVE_ADDR - Ask the card to publish a new RCA. */
const uint8_t CMD3 = 0X03;
/** SWITCH_FUNC - Switch Function Command */
const uint8_t CMD6 = 0X06;
/** SELECT/DESELECT_CARD - toggles between the stand-by and transfer states. */
const uint8_t CMD7 = 0X07;
/** SEND_IF_COND - verify SD Memory Card interface operating condition.*/
const uint8_t CMD8 = 0X08;
/** SEND_CSD - read the Card Specific Data (CSD register) */
const uint8_t CMD9 = 0X09;
/** SEND_CID - read the card identification information (CID register) */
const uint8_t CMD10 = 0X0A;
/** STOP_TRANSMISSION - end multiple block read sequence */
const uint8_t CMD12 = 0X0C;
/** SEND_STATUS - read the card status register */
const uint8_t CMD13 = 0X0D;
/** READ_SINGLE_BLOCK - read a single data block from the card */
const uint8_t CMD17 = 0X11;
/** READ_MULTIPLE_BLOCK - read a multiple data blocks from the card */
const uint8_t CMD18 = 0X12;
/** WRITE_BLOCK - write a single data block to the card */
const uint8_t CMD24 = 0X18;
/** WRITE_MULTIPLE_BLOCK - write blocks of data until a STOP_TRANSMISSION */
const uint8_t CMD25 = 0X19;
/** ERASE_WR_BLK_START - sets the address of the first block to be erased */
const uint8_t CMD32 = 0X20;
/** ERASE_WR_BLK_END - sets the address of the last block of the continuous
range to be erased*/
const uint8_t CMD33 = 0X21;
/** ERASE - erase all previously selected blocks */
const uint8_t CMD38 = 0X26;
/** APP_CMD - escape for application specific command */
const uint8_t CMD55 = 0X37;
/** READ_OCR - read the OCR register of a card */
const uint8_t CMD58 = 0X3A;
/** CRC_ON_OFF - enable or disable CRC checking */
const uint8_t CMD59 = 0X3B;
/** SET_BUS_WIDTH - Defines the data bus width for data transfer. */
const uint8_t ACMD6 = 0X06;
/** SD_STATUS - Send the SD Status. */
const uint8_t ACMD13 = 0X0D;
/** SET_WR_BLK_ERASE_COUNT - Set the number of write blocks to be
pre-erased before writing */
const uint8_t ACMD23 = 0X17;
/** SD_SEND_OP_COMD - Sends host capacity support information and
activates the card's initialization process */
const uint8_t ACMD41 = 0X29;
//==============================================================================
// CARD_STATUS
/** The command's argument was out of the allowed range for this card. */
const uint32_t CARD_STATUS_OUT_OF_RANGE = 1UL << 31;
/** A misaligned address which did not match the block length. */
const uint32_t CARD_STATUS_ADDRESS_ERROR = 1UL << 30;
/** The transferred block length is not allowed for this card. */
const uint32_t CARD_STATUS_BLOCK_LEN_ERROR = 1UL << 29;
/** An error in the sequence of erase commands occurred. */
const uint32_t CARD_STATUS_ERASE_SEQ_ERROR = 1UL <<28;
/** An invalid selection of write-blocks for erase occurred. */
const uint32_t CARD_STATUS_ERASE_PARAM = 1UL << 27;
/** Set when the host attempts to write to a protected block. */
const uint32_t CARD_STATUS_WP_VIOLATION = 1UL << 26;
/** When set, signals that the card is locked by the host. */
const uint32_t CARD_STATUS_CARD_IS_LOCKED = 1UL << 25;
/** Set when a sequence or password error has been detected. */
const uint32_t CARD_STATUS_LOCK_UNLOCK_FAILED = 1UL << 24;
/** The CRC check of the previous command failed. */
const uint32_t CARD_STATUS_COM_CRC_ERROR = 1UL << 23;
/** Command not legal for the card state. */
const uint32_t CARD_STATUS_ILLEGAL_COMMAND = 1UL << 22;
/** Card internal ECC was applied but failed to correct the data. */
const uint32_t CARD_STATUS_CARD_ECC_FAILED = 1UL << 21;
/** Internal card controller error */
const uint32_t CARD_STATUS_CC_ERROR = 1UL << 20;
/** A general or an unknown error occurred during the operation. */
const uint32_t CARD_STATUS_ERROR = 1UL << 19;
// bits 19, 18, and 17 reserved.
/** Permanent WP set or attempt to change read only values of CSD. */
const uint32_t CARD_STATUS_CSD_OVERWRITE = 1UL <<16;
/** partial address space was erased due to write protect. */
const uint32_t CARD_STATUS_WP_ERASE_SKIP = 1UL << 15;
/** The command has been executed without using the internal ECC. */
const uint32_t CARD_STATUS_CARD_ECC_DISABLED = 1UL << 14;
/** out of erase sequence command was received. */
const uint32_t CARD_STATUS_ERASE_RESET = 1UL << 13;
/** The state of the card when receiving the command.
* 0 = idle
* 1 = ready
* 2 = ident
* 3 = stby
* 4 = tran
* 5 = data
* 6 = rcv
* 7 = prg
* 8 = dis
* 9-14 = reserved
* 15 = reserved for I/O mode
*/
const uint32_t CARD_STATUS_CURRENT_STATE = 0XF << 9;
/** Shift for current state. */
const uint32_t CARD_STATUS_CURRENT_STATE_SHIFT = 9;
/** Corresponds to buffer empty signaling on the bus. */
const uint32_t CARD_STATUS_READY_FOR_DATA = 1UL << 8;
// bit 7 reserved.
/** Extension Functions may set this bit to get host to deal with events. */
const uint32_t CARD_STATUS_FX_EVENT = 1UL << 6;
/** The card will expect ACMD, or the command has been interpreted as ACMD */
const uint32_t CARD_STATUS_APP_CMD = 1UL << 5;
// bit 4 reserved.
/** Error in the sequence of the authentication process. */
const uint32_t CARD_STATUS_AKE_SEQ_ERROR = 1UL << 3;
// bits 2,1, and 0 reserved for manufacturer test mode.
//==============================================================================
/** status for card in the ready state */
const uint8_t R1_READY_STATE = 0X00;
/** status for card in the idle state */
const uint8_t R1_IDLE_STATE = 0X01;
/** status bit for illegal command */
const uint8_t R1_ILLEGAL_COMMAND = 0X04;
/** start data token for read or write single block*/
const uint8_t DATA_START_BLOCK = 0XFE;
/** stop token for write multiple blocks*/
const uint8_t STOP_TRAN_TOKEN = 0XFD;
/** start data token for write multiple blocks*/
const uint8_t WRITE_MULTIPLE_TOKEN = 0XFC;
/** mask for data response tokens after a write block operation */
const uint8_t DATA_RES_MASK = 0X1F;
/** write data accepted token */
const uint8_t DATA_RES_ACCEPTED = 0X05;
//==============================================================================
/**
* \class CID
* \brief Card IDentification (CID) register.
*/
typedef struct CID {
// byte 0
/** Manufacturer ID */
unsigned char mid;
// byte 1-2
/** OEM/Application ID */
char oid[2];
// byte 3-7
/** Product name */
char pnm[5];
// byte 8
/** Product revision least significant digit */
unsigned char prv_m : 4;
/** Product revision most significant digit */
unsigned char prv_n : 4;
// byte 9-12
/** Product serial number */
uint32_t psn;
// byte 13
/** Manufacturing date year low digit */
unsigned char mdt_year_high : 4;
/** not used */
unsigned char reserved : 4;
// byte 14
/** Manufacturing date month */
unsigned char mdt_month : 4;
/** Manufacturing date year low digit */
unsigned char mdt_year_low : 4;
// byte 15
/** not used always 1 */
unsigned char always1 : 1;
/** CRC7 checksum */
unsigned char crc : 7;
} __attribute__((packed)) cid_t;
//==============================================================================
/**
* \class CSDV1
* \brief CSD register for version 1.00 cards .
*/
typedef struct CSDV1 {
// byte 0
unsigned char reserved1 : 6;
unsigned char csd_ver : 2;
// byte 1
unsigned char taac;
// byte 2
unsigned char nsac;
// byte 3
unsigned char tran_speed;
// byte 4
unsigned char ccc_high;
// byte 5
unsigned char read_bl_len : 4;
unsigned char ccc_low : 4;
// byte 6
unsigned char c_size_high : 2;
unsigned char reserved2 : 2;
unsigned char dsr_imp : 1;
unsigned char read_blk_misalign : 1;
unsigned char write_blk_misalign : 1;
unsigned char read_bl_partial : 1;
// byte 7
unsigned char c_size_mid;
// byte 8
unsigned char vdd_r_curr_max : 3;
unsigned char vdd_r_curr_min : 3;
unsigned char c_size_low : 2;
// byte 9
unsigned char c_size_mult_high : 2;
unsigned char vdd_w_cur_max : 3;
unsigned char vdd_w_curr_min : 3;
// byte 10
unsigned char sector_size_high : 6;
unsigned char erase_blk_en : 1;
unsigned char c_size_mult_low : 1;
// byte 11
unsigned char wp_grp_size : 7;
unsigned char sector_size_low : 1;
// byte 12
unsigned char write_bl_len_high : 2;
unsigned char r2w_factor : 3;
unsigned char reserved3 : 2;
unsigned char wp_grp_enable : 1;
// byte 13
unsigned char reserved4 : 5;
unsigned char write_partial : 1;
unsigned char write_bl_len_low : 2;
// byte 14
unsigned char reserved5: 2;
unsigned char file_format : 2;
unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1;
unsigned char copy : 1;
/** Indicates the file format on the card */
unsigned char file_format_grp : 1;
// byte 15
unsigned char always1 : 1;
unsigned char crc : 7;
} __attribute__((packed)) csd1_t;
//==============================================================================
/**
* \class CSDV2
* \brief CSD register for version 2.00 cards.
*/
typedef struct CSDV2 {
// byte 0
unsigned char reserved1 : 6;
unsigned char csd_ver : 2;
// byte 1
/** fixed to 0X0E */
unsigned char taac;
// byte 2
/** fixed to 0 */
unsigned char nsac;
// byte 3
unsigned char tran_speed;
// byte 4
unsigned char ccc_high;
// byte 5
/** This field is fixed to 9h, which indicates READ_BL_LEN=512 Byte */
unsigned char read_bl_len : 4;
unsigned char ccc_low : 4;
// byte 6
/** not used */
unsigned char reserved2 : 4;
unsigned char dsr_imp : 1;
/** fixed to 0 */
unsigned char read_blk_misalign : 1;
/** fixed to 0 */
unsigned char write_blk_misalign : 1;
/** fixed to 0 - no partial read */
unsigned char read_bl_partial : 1;
// byte 7
/** high part of card size */
unsigned char c_size_high : 6;
/** not used */
unsigned char reserved3 : 2;
// byte 8
/** middle part of card size */
unsigned char c_size_mid;
// byte 9
/** low part of card size */
unsigned char c_size_low;
// byte 10
/** sector size is fixed at 64 KB */
unsigned char sector_size_high : 6;
/** fixed to 1 - erase single is supported */
unsigned char erase_blk_en : 1;
/** not used */
unsigned char reserved4 : 1;
// byte 11
unsigned char wp_grp_size : 7;
/** sector size is fixed at 64 KB */
unsigned char sector_size_low : 1;
// byte 12
/** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_high : 2;
/** fixed value of 2 */
unsigned char r2w_factor : 3;
/** not used */
unsigned char reserved5 : 2;
/** fixed value of 0 - no write protect groups */
unsigned char wp_grp_enable : 1;
// byte 13
unsigned char reserved6 : 5;
/** always zero - no partial block read*/
unsigned char write_partial : 1;
/** write_bl_len fixed for 512 byte blocks */
unsigned char write_bl_len_low : 2;
// byte 14
unsigned char reserved7: 2;
/** Do not use always 0 */
unsigned char file_format : 2;
unsigned char tmp_write_protect : 1;
unsigned char perm_write_protect : 1;
unsigned char copy : 1;
/** Do not use always 0 */
unsigned char file_format_grp : 1;
// byte 15
/** not used always 1 */
unsigned char always1 : 1;
/** checksum */
unsigned char crc : 7;
} __attribute__((packed)) csd2_t;
//==============================================================================
/**
* \class csd_t
* \brief Union of old and new style CSD register.
*/
union csd_t {
csd1_t v1;
csd2_t v2;
};
//-----------------------------------------------------------------------------
inline uint32_t sdCardCapacity(csd_t* csd) {
if (csd->v1.csd_ver == 0) {
uint8_t read_bl_len = csd->v1.read_bl_len;
uint16_t c_size = (csd->v1.c_size_high << 10)
| (csd->v1.c_size_mid << 2) | csd->v1.c_size_low;
uint8_t c_size_mult = (csd->v1.c_size_mult_high << 1)
| csd->v1.c_size_mult_low;
return (uint32_t)(c_size + 1) << (c_size_mult + read_bl_len - 7);
} else if (csd->v2.csd_ver == 1) {
uint32_t c_size = 0X10000L * csd->v2.c_size_high + 0X100L
* (uint32_t)csd->v2.c_size_mid + csd->v2.c_size_low;
return (c_size + 1) << 10;
} else {
return 0;
}
}
#endif // SdInfo_h

View file

@ -0,0 +1,802 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SdSpiCard.h"
//==============================================================================
// debug trace macro
#define SD_TRACE(m, b)
// #define SD_TRACE(m, b) Serial.print(m);Serial.println(b);
#define SD_CS_DBG(m)
// #define SD_CS_DBG(m) Serial.println(F(m));
#define DBG_PROFILE_STATS 0
#if DBG_PROFILE_STATS
#define DBG_TAG_LIST\
DBG_TAG(DBG_CMD0_TIME, "CMD0 time")\
DBG_TAG(DBG_ACMD41_TIME, "ACMD41 time")\
DBG_TAG(DBG_CMD_BUSY, "cmd busy")\
DBG_TAG(DBG_ERASE_BUSY, "erase busy")\
DBG_TAG(DBG_WAIT_READ, "wait read")\
DBG_TAG(DBG_WRITE_FLASH, "write flash")\
DBG_TAG(DBG_WRITE_BUSY, "write busy")\
DBG_TAG(DBG_WRITE_STOP, "write stop")\
DBG_TAG(DBG_ACMD41_COUNT, "ACMD41 count")\
DBG_TAG(DBG_CMD0_COUNT, "CMD0 count")
#define DBG_TIME_DIM DBG_ACMD41_COUNT
enum DbgTag {
#define DBG_TAG(tag, str) tag,
DBG_TAG_LIST
DBG_COUNT_DIM
#undef DBG_TAG
};
static uint32_t dbgCount[DBG_COUNT_DIM];
static uint32_t dbgBgnTime[DBG_TIME_DIM];
static uint32_t dbgMaxTime[DBG_TIME_DIM];
static uint32_t dbgMinTime[DBG_TIME_DIM];
static uint32_t dbgTotalTime[DBG_TIME_DIM];
//------------------------------------------------------------------------------
static void dbgBeginTime(DbgTag tag) {
dbgBgnTime[tag] = micros();
}
//------------------------------------------------------------------------------
static void dbgClearStats() {
for (int i = 0; i < DBG_COUNT_DIM; i++) {
dbgCount[i] = 0;
if (i < DBG_TIME_DIM) {
dbgMaxTime[i] = 0;
dbgMinTime[i] = 9999999;
dbgTotalTime[i] = 0;
}
}
}
//------------------------------------------------------------------------------
static void dbgEndTime(DbgTag tag) {
uint32_t m = micros() - dbgBgnTime[tag];
dbgTotalTime[tag] += m;
if (m > dbgMaxTime[tag]) {
dbgMaxTime[tag] = m;
}
if (m < dbgMinTime[tag]) {
dbgMinTime[tag] = m;
}
dbgCount[tag]++;
}
//------------------------------------------------------------------------------
static void dbgEventCount(DbgTag tag) {
dbgCount[tag]++;
}
//------------------------------------------------------------------------------
static void dbgPrintTagText(uint8_t tag) {
#define DBG_TAG(e, m) case e: Serial.print(F(m)); break;
switch (tag) {
DBG_TAG_LIST
}
#undef DBG_TAG
}
//------------------------------------------------------------------------------
static void dbgPrintStats() {
Serial.println();
Serial.println(F("======================="));
Serial.println(F("item,event,min,max,avg"));
Serial.println(F("tag,count,usec,usec,usec"));
for (int i = 0; i < DBG_COUNT_DIM; i++) {
if (dbgCount[i]) {
dbgPrintTagText(i);
Serial.print(',');
Serial.print(dbgCount[i]);
if (i < DBG_TIME_DIM) {
Serial.print(',');
Serial.print(dbgMinTime[i]);
Serial.print(',');
Serial.print(dbgMaxTime[i]);
Serial.print(',');
Serial.print(dbgTotalTime[i]/dbgCount[i]);
}
Serial.println();
}
}
Serial.println(F("======================="));
Serial.println();
}
#undef DBG_TAG_LIST
#define DBG_BEGIN_TIME(tag) dbgBeginTime(tag)
#define DBG_END_TIME(tag) dbgEndTime(tag)
#define DBG_EVENT_COUNT(tag) dbgEventCount(tag)
#else // DBG_PROFILE_STATS
#define DBG_BEGIN_TIME(tag)
#define DBG_END_TIME(tag)
#define DBG_EVENT_COUNT(tag)
static void dbgClearStats() {}
static void dbgPrintStats() {}
#endif // DBG_PROFILE_STATS
//==============================================================================
#if USE_SD_CRC
// CRC functions
//------------------------------------------------------------------------------
static uint8_t CRC7(const uint8_t* data, uint8_t n) {
uint8_t crc = 0;
for (uint8_t i = 0; i < n; i++) {
uint8_t d = data[i];
for (uint8_t j = 0; j < 8; j++) {
crc <<= 1;
if ((d & 0x80) ^ (crc & 0x80)) {
crc ^= 0x09;
}
d <<= 1;
}
}
return (crc << 1) | 1;
}
//------------------------------------------------------------------------------
#if USE_SD_CRC == 1
// Shift based CRC-CCITT
// uses the x^16,x^12,x^5,x^1 polynomial.
static uint16_t CRC_CCITT(const uint8_t *data, size_t n) {
uint16_t crc = 0;
for (size_t i = 0; i < n; i++) {
crc = (uint8_t)(crc >> 8) | (crc << 8);
crc ^= data[i];
crc ^= (uint8_t)(crc & 0xff) >> 4;
crc ^= crc << 12;
crc ^= (crc & 0xff) << 5;
}
return crc;
}
#elif USE_SD_CRC > 1 // CRC_CCITT
//------------------------------------------------------------------------------
// Table based CRC-CCITT
// uses the x^16,x^12,x^5,x^1 polynomial.
#ifdef __AVR__
static const uint16_t crctab[] PROGMEM = {
#else // __AVR__
static const uint16_t crctab[] = {
#endif // __AVR__
0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50A5, 0x60C6, 0x70E7,
0x8108, 0x9129, 0xA14A, 0xB16B, 0xC18C, 0xD1AD, 0xE1CE, 0xF1EF,
0x1231, 0x0210, 0x3273, 0x2252, 0x52B5, 0x4294, 0x72F7, 0x62D6,
0x9339, 0x8318, 0xB37B, 0xA35A, 0xD3BD, 0xC39C, 0xF3FF, 0xE3DE,
0x2462, 0x3443, 0x0420, 0x1401, 0x64E6, 0x74C7, 0x44A4, 0x5485,
0xA56A, 0xB54B, 0x8528, 0x9509, 0xE5EE, 0xF5CF, 0xC5AC, 0xD58D,
0x3653, 0x2672, 0x1611, 0x0630, 0x76D7, 0x66F6, 0x5695, 0x46B4,
0xB75B, 0xA77A, 0x9719, 0x8738, 0xF7DF, 0xE7FE, 0xD79D, 0xC7BC,
0x48C4, 0x58E5, 0x6886, 0x78A7, 0x0840, 0x1861, 0x2802, 0x3823,
0xC9CC, 0xD9ED, 0xE98E, 0xF9AF, 0x8948, 0x9969, 0xA90A, 0xB92B,
0x5AF5, 0x4AD4, 0x7AB7, 0x6A96, 0x1A71, 0x0A50, 0x3A33, 0x2A12,
0xDBFD, 0xCBDC, 0xFBBF, 0xEB9E, 0x9B79, 0x8B58, 0xBB3B, 0xAB1A,
0x6CA6, 0x7C87, 0x4CE4, 0x5CC5, 0x2C22, 0x3C03, 0x0C60, 0x1C41,
0xEDAE, 0xFD8F, 0xCDEC, 0xDDCD, 0xAD2A, 0xBD0B, 0x8D68, 0x9D49,
0x7E97, 0x6EB6, 0x5ED5, 0x4EF4, 0x3E13, 0x2E32, 0x1E51, 0x0E70,
0xFF9F, 0xEFBE, 0xDFDD, 0xCFFC, 0xBF1B, 0xAF3A, 0x9F59, 0x8F78,
0x9188, 0x81A9, 0xB1CA, 0xA1EB, 0xD10C, 0xC12D, 0xF14E, 0xE16F,
0x1080, 0x00A1, 0x30C2, 0x20E3, 0x5004, 0x4025, 0x7046, 0x6067,
0x83B9, 0x9398, 0xA3FB, 0xB3DA, 0xC33D, 0xD31C, 0xE37F, 0xF35E,
0x02B1, 0x1290, 0x22F3, 0x32D2, 0x4235, 0x5214, 0x6277, 0x7256,
0xB5EA, 0xA5CB, 0x95A8, 0x8589, 0xF56E, 0xE54F, 0xD52C, 0xC50D,
0x34E2, 0x24C3, 0x14A0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
0xA7DB, 0xB7FA, 0x8799, 0x97B8, 0xE75F, 0xF77E, 0xC71D, 0xD73C,
0x26D3, 0x36F2, 0x0691, 0x16B0, 0x6657, 0x7676, 0x4615, 0x5634,
0xD94C, 0xC96D, 0xF90E, 0xE92F, 0x99C8, 0x89E9, 0xB98A, 0xA9AB,
0x5844, 0x4865, 0x7806, 0x6827, 0x18C0, 0x08E1, 0x3882, 0x28A3,
0xCB7D, 0xDB5C, 0xEB3F, 0xFB1E, 0x8BF9, 0x9BD8, 0xABBB, 0xBB9A,
0x4A75, 0x5A54, 0x6A37, 0x7A16, 0x0AF1, 0x1AD0, 0x2AB3, 0x3A92,
0xFD2E, 0xED0F, 0xDD6C, 0xCD4D, 0xBDAA, 0xAD8B, 0x9DE8, 0x8DC9,
0x7C26, 0x6C07, 0x5C64, 0x4C45, 0x3CA2, 0x2C83, 0x1CE0, 0x0CC1,
0xEF1F, 0xFF3E, 0xCF5D, 0xDF7C, 0xAF9B, 0xBFBA, 0x8FD9, 0x9FF8,
0x6E17, 0x7E36, 0x4E55, 0x5E74, 0x2E93, 0x3EB2, 0x0ED1, 0x1EF0
};
static uint16_t CRC_CCITT(const uint8_t* data, size_t n) {
uint16_t crc = 0;
for (size_t i = 0; i < n; i++) {
#ifdef __AVR__
crc = pgm_read_word(&crctab[(crc >> 8 ^ data[i]) & 0XFF]) ^ (crc << 8);
#else // __AVR__
crc = crctab[(crc >> 8 ^ data[i]) & 0XFF] ^ (crc << 8);
#endif // __AVR__
}
return crc;
}
#endif // CRC_CCITT
#endif // USE_SD_CRC
//==============================================================================
// SdSpiCard member functions
//------------------------------------------------------------------------------
bool SdSpiCard::begin(SdSpiDriver* spi, uint8_t csPin, SPISettings settings) {
m_spiActive = false;
m_errorCode = SD_CARD_ERROR_NONE;
m_type = 0;
m_spiDriver = spi;
uint16_t t0 = curTimeMS();
uint32_t arg;
m_spiDriver->begin(csPin);
m_spiDriver->setSpiSettings(SD_SCK_HZ(250000));
spiStart();
// must supply min of 74 clock cycles with CS high.
spiUnselect();
for (uint8_t i = 0; i < 10; i++) {
spiSend(0XFF);
}
spiSelect();
DBG_BEGIN_TIME(DBG_CMD0_TIME);
// command to go idle in SPI mode
for (uint8_t i = 1;; i++) {
DBG_EVENT_COUNT(DBG_CMD0_COUNT);
if (cardCommand(CMD0, 0) == R1_IDLE_STATE) {
break;
}
if (i == SD_CMD0_RETRY) {
error(SD_CARD_ERROR_CMD0);
goto fail;
}
// stop multi-block write
spiSend(STOP_TRAN_TOKEN);
// finish block transfer
for (int i = 0; i < 520; i++) {
spiReceive();
}
}
DBG_END_TIME(DBG_CMD0_TIME);
#if USE_SD_CRC
if (cardCommand(CMD59, 1) != R1_IDLE_STATE) {
error(SD_CARD_ERROR_CMD59);
goto fail;
}
#endif // USE_SD_CRC
// check SD version
if (cardCommand(CMD8, 0x1AA) == (R1_ILLEGAL_COMMAND | R1_IDLE_STATE)) {
type(SD_CARD_TYPE_SD1);
} else {
for (uint8_t i = 0; i < 4; i++) {
m_status = spiReceive();
}
if (m_status == 0XAA) {
type(SD_CARD_TYPE_SD2);
} else {
error(SD_CARD_ERROR_CMD8);
goto fail;
}
}
// initialize card and send host supports SDHC if SD2
arg = type() == SD_CARD_TYPE_SD2 ? 0X40000000 : 0;
DBG_BEGIN_TIME(DBG_ACMD41_TIME);
while (cardAcmd(ACMD41, arg) != R1_READY_STATE) {
DBG_EVENT_COUNT(DBG_ACMD41_COUNT);
// check for timeout
if (isTimedOut(t0, SD_INIT_TIMEOUT)) {
error(SD_CARD_ERROR_ACMD41);
goto fail;
}
}
DBG_END_TIME(DBG_ACMD41_TIME);
// if SD2 read OCR register to check for SDHC card
if (type() == SD_CARD_TYPE_SD2) {
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
if ((spiReceive() & 0XC0) == 0XC0) {
type(SD_CARD_TYPE_SDHC);
}
// Discard rest of ocr - contains allowed voltage range.
for (uint8_t i = 0; i < 3; i++) {
spiReceive();
}
}
spiStop();
m_spiDriver->setSpiSettings(settings);
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
// send command and return error code. Return zero for OK
uint8_t SdSpiCard::cardCommand(uint8_t cmd, uint32_t arg) {
// select card
if (!m_spiActive) {
spiStart();
}
// wait if busy unless CMD0
if (cmd != CMD0) {
DBG_BEGIN_TIME(DBG_CMD_BUSY);
waitNotBusy(SD_CMD_TIMEOUT);
DBG_END_TIME(DBG_CMD_BUSY);
}
#if USE_SD_CRC
// form message
uint8_t buf[6];
buf[0] = (uint8_t)0x40U | cmd;
buf[1] = (uint8_t)(arg >> 24U);
buf[2] = (uint8_t)(arg >> 16U);
buf[3] = (uint8_t)(arg >> 8U);
buf[4] = (uint8_t)arg;
// add CRC
buf[5] = CRC7(buf, 5);
// send message
spiSend(buf, 6);
#else // USE_SD_CRC
// send command
spiSend(cmd | 0x40);
// send argument
uint8_t *pa = reinterpret_cast<uint8_t *>(&arg);
for (int8_t i = 3; i >= 0; i--) {
spiSend(pa[i]);
}
// send CRC - correct for CMD0 with arg zero or CMD8 with arg 0X1AA
spiSend(cmd == CMD0 ? 0X95 : 0X87);
#endif // USE_SD_CRC
// discard first fill byte to avoid MISO pull-up problem.
spiReceive();
// there are 1-8 fill bytes before response. fill bytes should be 0XFF.
for (uint8_t i = 0; ((m_status = spiReceive()) & 0X80) && i < 10; i++) {
}
return m_status;
}
//------------------------------------------------------------------------------
uint32_t SdSpiCard::cardCapacity() {
csd_t csd;
return readCSD(&csd) ? sdCardCapacity(&csd) : 0;
}
//------------------------------------------------------------------------------
void SdSpiCard::dbgClearStats() {::dbgClearStats();}
//------------------------------------------------------------------------------
void SdSpiCard::dbgPrintStats() {::dbgPrintStats();}
//------------------------------------------------------------------------------
bool SdSpiCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
csd_t csd;
if (!readCSD(&csd)) {
goto fail;
}
// check for single block erase
if (!csd.v1.erase_blk_en) {
// erase size mask
uint8_t m = (csd.v1.sector_size_high << 1) | csd.v1.sector_size_low;
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
// error card can't erase specified area
error(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
goto fail;
}
}
if (m_type != SD_CARD_TYPE_SDHC) {
firstBlock <<= 9;
lastBlock <<= 9;
}
if (cardCommand(CMD32, firstBlock)
|| cardCommand(CMD33, lastBlock)
|| cardCommand(CMD38, 0)) {
error(SD_CARD_ERROR_ERASE);
goto fail;
}
DBG_BEGIN_TIME(DBG_ERASE_BUSY);
if (!waitNotBusy(SD_ERASE_TIMEOUT)) {
error(SD_CARD_ERROR_ERASE_TIMEOUT);
goto fail;
}
DBG_END_TIME(DBG_ERASE_BUSY);
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::eraseSingleBlockEnable() {
csd_t csd;
return readCSD(&csd) ? csd.v1.erase_blk_en : false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::isBusy() {
bool rtn = true;
bool spiActive = m_spiActive;
if (!spiActive) {
spiStart();
}
for (uint8_t i = 0; i < 8; i++) {
if (0XFF == spiReceive()) {
rtn = false;
break;
}
}
if (!spiActive) {
spiStop();
}
return rtn;
}
//------------------------------------------------------------------------------
bool SdSpiCard::isTimedOut(uint16_t startMS, uint16_t timeoutMS) {
#if WDT_YIELD_TIME_MICROS
static uint32_t last;
if ((micros() - last) > WDT_YIELD_TIME_MICROS) {
SysCall::yield();
last = micros();
}
#endif // WDT_YIELD_TIME_MICROS
return (curTimeMS() - startMS) > timeoutMS;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readBlock(uint32_t blockNumber, uint8_t* dst) {
SD_TRACE("RB", blockNumber);
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD17, blockNumber)) {
error(SD_CARD_ERROR_CMD17);
goto fail;
}
if (!readData(dst, 512)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readBlocks(uint32_t block, uint8_t* dst, size_t count) {
if (!readStart(block)) {
return false;
}
for (uint16_t b = 0; b < count; b++, dst += 512) {
if (!readData(dst, 512)) {
return false;
}
}
return readStop();
}
//------------------------------------------------------------------------------
bool SdSpiCard::readData(uint8_t *dst) {
return readData(dst, 512);
}
//------------------------------------------------------------------------------
bool SdSpiCard::readData(uint8_t* dst, size_t count) {
#if USE_SD_CRC
uint16_t crc;
#endif // USE_SD_CRC
DBG_BEGIN_TIME(DBG_WAIT_READ);
// wait for start block token
uint16_t t0 = curTimeMS();
while ((m_status = spiReceive()) == 0XFF) {
if (isTimedOut(t0, SD_READ_TIMEOUT)) {
error(SD_CARD_ERROR_READ_TIMEOUT);
goto fail;
}
}
DBG_END_TIME(DBG_WAIT_READ);
if (m_status != DATA_START_BLOCK) {
error(SD_CARD_ERROR_READ);
goto fail;
}
// transfer data
if ((m_status = spiReceive(dst, count))) {
error(SD_CARD_ERROR_DMA);
goto fail;
}
#if USE_SD_CRC
// get crc
crc = (spiReceive() << 8) | spiReceive();
if (crc != CRC_CCITT(dst, count)) {
error(SD_CARD_ERROR_READ_CRC);
goto fail;
}
#else
// discard crc
spiReceive();
spiReceive();
#endif // USE_SD_CRC
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readOCR(uint32_t* ocr) {
uint8_t *p = reinterpret_cast<uint8_t*>(ocr);
if (cardCommand(CMD58, 0)) {
error(SD_CARD_ERROR_CMD58);
goto fail;
}
for (uint8_t i = 0; i < 4; i++) {
p[3 - i] = spiReceive();
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
/** read CID or CSR register */
bool SdSpiCard::readRegister(uint8_t cmd, void* buf) {
uint8_t* dst = reinterpret_cast<uint8_t*>(buf);
if (cardCommand(cmd, 0)) {
error(SD_CARD_ERROR_READ_REG);
goto fail;
}
if (!readData(dst, 16)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::readStart(uint32_t blockNumber) {
SD_TRACE("RS", blockNumber);
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD18, blockNumber)) {
error(SD_CARD_ERROR_CMD18);
goto fail;
}
// spiStop();
return true;
fail:
spiStop();
return false;
}
//-----------------------------------------------------------------------------
bool SdSpiCard::readStatus(uint8_t* status) {
// retrun is R2 so read extra status byte.
if (cardAcmd(ACMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_ACMD13);
goto fail;
}
if (!readData(status, 64)) {
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//-----------------------------------------------------------------------------
void SdSpiCard::spiStart() {
if (!m_spiActive) {
spiActivate();
spiSelect();
m_spiActive = true;
}
}
//-----------------------------------------------------------------------------
void SdSpiCard::spiStop() {
if (m_spiActive) {
spiUnselect();
spiSend(0XFF);
spiDeactivate();
m_spiActive = false;
}
}
//------------------------------------------------------------------------------
bool SdSpiCard::readStop() {
if (cardCommand(CMD12, 0)) {
error(SD_CARD_ERROR_CMD12);
goto fail;
}
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
// wait for card to go not busy
bool SdSpiCard::waitNotBusy(uint16_t timeoutMS) {
uint16_t t0 = curTimeMS();
#if WDT_YIELD_TIME_MICROS
// Call isTimedOut first to insure yield is called.
while (!isTimedOut(t0, timeoutMS)) {
if (spiReceive() == 0XFF) {
return true;
}
}
return false;
#else // WDT_YIELD_TIME_MICROS
// Check not busy first since yield is not called in isTimedOut.
while (spiReceive() != 0XFF) {
if (isTimedOut(t0, timeoutMS)) {
return false;
}
}
return true;
#endif // WDT_YIELD_TIME_MICROS
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeBlock(uint32_t blockNumber, const uint8_t* src) {
SD_TRACE("WB", blockNumber);
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD24, blockNumber)) {
error(SD_CARD_ERROR_CMD24);
goto fail;
}
if (!writeData(DATA_START_BLOCK, src)) {
goto fail;
}
#if CHECK_FLASH_PROGRAMMING
// wait for flash programming to complete
DBG_BEGIN_TIME(DBG_WRITE_FLASH);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_FLASH_PROGRAMMING);
goto fail;
}
DBG_END_TIME(DBG_WRITE_FLASH);
// response is r2 so get and check two bytes for nonzero
if (cardCommand(CMD13, 0) || spiReceive()) {
error(SD_CARD_ERROR_CMD13);
goto fail;
}
#endif // CHECK_PROGRAMMING
spiStop();
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeBlocks(uint32_t block, const uint8_t* src, size_t count) {
if (!writeStart(block)) {
goto fail;
}
for (size_t b = 0; b < count; b++, src += 512) {
if (!writeData(src)) {
goto fail;
}
}
return writeStop();
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeData(const uint8_t* src) {
// wait for previous write to finish
DBG_BEGIN_TIME(DBG_WRITE_BUSY);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
error(SD_CARD_ERROR_WRITE_TIMEOUT);
goto fail;
}
DBG_END_TIME(DBG_WRITE_BUSY);
if (!writeData(WRITE_MULTIPLE_TOKEN, src)) {
goto fail;
}
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
// send one block of data for write block or write multiple blocks
bool SdSpiCard::writeData(uint8_t token, const uint8_t* src) {
#if USE_SD_CRC
uint16_t crc = CRC_CCITT(src, 512);
#else // USE_SD_CRC
uint16_t crc = 0XFFFF;
#endif // USE_SD_CRC
spiSend(token);
spiSend(src, 512);
spiSend(crc >> 8);
spiSend(crc & 0XFF);
m_status = spiReceive();
if ((m_status & DATA_RES_MASK) != DATA_RES_ACCEPTED) {
error(SD_CARD_ERROR_WRITE);
goto fail;
}
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStart(uint32_t blockNumber) {
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
}
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStart(uint32_t blockNumber, uint32_t eraseCount) {
SD_TRACE("WS", blockNumber);
// send pre-erase count
if (cardAcmd(ACMD23, eraseCount)) {
error(SD_CARD_ERROR_ACMD23);
goto fail;
}
// use address if not SDHC card
if (type() != SD_CARD_TYPE_SDHC) {
blockNumber <<= 9;
}
if (cardCommand(CMD25, blockNumber)) {
error(SD_CARD_ERROR_CMD25);
goto fail;
}
return true;
fail:
spiStop();
return false;
}
//------------------------------------------------------------------------------
bool SdSpiCard::writeStop() {
DBG_BEGIN_TIME(DBG_WRITE_STOP);
if (!waitNotBusy(SD_WRITE_TIMEOUT)) {
goto fail;
}
DBG_END_TIME(DBG_WRITE_STOP);
spiSend(STOP_TRAN_TOKEN);
spiStop();
return true;
fail:
error(SD_CARD_ERROR_STOP_TRAN);
spiStop();
return false;
}

View file

@ -0,0 +1,379 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SdSpiCard_h
#define SdSpiCard_h
/**
* \file
* \brief SdSpiCard class for V2 SD/SDHC cards
*/
#include <stddef.h>
#include "../SysCall.h"
#include "SdInfo.h"
#include "../FatLib/BaseBlockDriver.h"
#include "../SpiDriver/SdSpiDriver.h"
//==============================================================================
/**
* \class SdSpiCard
* \brief Raw access to SD and SDHC flash memory cards via SPI protocol.
*/
#if ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
class SdSpiCard : public BaseBlockDriver {
#else // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
class SdSpiCard {
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || ENABLE_SDIO_CLASS
public:
/** Construct an instance of SdSpiCard. */
SdSpiCard() : m_errorCode(SD_CARD_ERROR_INIT_NOT_CALLED), m_type(0) {}
/** Initialize the SD card.
* \param[in] spi SPI driver for card.
* \param[in] csPin card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings);
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte sectors in the card
* or zero if an error occurs.
*/
uint32_t cardCapacity();
/** \return Card size in sectors or zero if an error occurs. */
uint32_t cardSize() {return cardCapacity();}
/** Clear debug stats. */
void dbgClearStats();
/** Print debug stats. */
void dbgPrintStats();
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single block erase.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock);
/** Determine if card supports single block erase.
*
* \return true is returned if single block erase is supported.
* false is returned if single block erase is not supported.
*/
bool eraseSingleBlockEnable();
/**
* Set SD error code.
* \param[in] code value for error code.
*/
void error(uint8_t code) {
m_errorCode = code;
}
/**
* \return code for the last error. See SdInfo.h for a list of error codes.
*/
int errorCode() const {
return m_errorCode;
}
/** \return error data for last error. */
int errorData() const {
return m_status;
}
/**
* Check for busy. MISO low indicates the card is busy.
*
* \return true if busy else false.
*/
bool isBusy();
/**
* Read a 512 byte block from an SD card.
*
* \param[in] lba Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t lba, uint8_t* dst);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] lba Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t lba, uint8_t* dst, size_t nb);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(cid_t* cid) {
return readRegister(CMD10, cid);
}
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(csd_t* csd) {
return readRegister(CMD9, csd);
}
/** Read one data block in a multiple block read sequence
*
* \param[out] dst Pointer to the location for the data to be read.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readData(uint8_t *dst);
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success else false.
*/
bool readOCR(uint32_t* ocr);
/** Start a read multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStart(uint32_t blockNumber);
/** Return the 64 byte card status
* \param[out] status location for 64 status bytes.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStatus(uint8_t* status);
/** End a read multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStop();
/** \return success if sync successful. Not for user apps. */
bool syncBlocks() {return true;}
/** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/
int type() const {
return m_type;
}
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] lba Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t lba, const uint8_t* src);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] lba Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t lba, const uint8_t* src, size_t nb);
/** Write one data block in a multiple block write sequence.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple blocks sequence.
*
* \param[in] blockNumber Address of first block in sequence.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t blockNumber);
/** Start a write multiple blocks sequence with pre-erase.
*
* \param[in] blockNumber Address of first block in sequence.
* \param[in] eraseCount The number of blocks to be pre-erased.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t blockNumber, uint32_t eraseCount);
/** End a write multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStop();
/** Set CS low and activate the card. */
void spiStart();
/** Set CS high and deactivate the card. */
void spiStop();
private:
// private functions
uint8_t cardAcmd(uint8_t cmd, uint32_t arg) {
cardCommand(CMD55, 0);
return cardCommand(cmd, arg);
}
uint8_t cardCommand(uint8_t cmd, uint32_t arg);
bool isTimedOut(uint16_t startMS, uint16_t timeoutMS);
bool readData(uint8_t* dst, size_t count);
bool readRegister(uint8_t cmd, void* buf);
void type(uint8_t value) {
m_type = value;
}
bool waitNotBusy(uint16_t timeoutMS);
bool writeData(uint8_t token, const uint8_t* src);
//---------------------------------------------------------------------------
// functions defined in SdSpiDriver.h
void spiActivate() {
m_spiDriver->activate();
}
void spiDeactivate() {
m_spiDriver->deactivate();
}
uint8_t spiReceive() {
return m_spiDriver->receive();
}
uint8_t spiReceive(uint8_t* buf, size_t n) {
return m_spiDriver->receive(buf, n);
}
void spiSend(uint8_t data) {
m_spiDriver->send(data);
}
void spiSend(const uint8_t* buf, size_t n) {
m_spiDriver->send(buf, n);
}
void spiSelect() {
m_spiDriver->select();
}
void spiUnselect() {
m_spiDriver->unselect();
}
uint8_t m_errorCode;
SdSpiDriver *m_spiDriver;
bool m_spiActive;
uint8_t m_status;
uint8_t m_type;
};
//==============================================================================
/**
* \class SdSpiCardEX
* \brief Extended SD I/O block driver.
*/
class SdSpiCardEX : public SdSpiCard {
public:
/** Initialize the SD card
*
* \param[in] spi SPI driver.
* \param[in] csPin Card chip select pin number.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin(SdSpiDriver* spi, uint8_t csPin, SPISettings spiSettings) {
m_curState = IDLE_STATE;
return SdSpiCard::begin(spi, csPin, spiSettings);
}
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t block, uint8_t* dst);
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool syncBlocks();
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t block, const uint8_t* src);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb);
private:
static const uint32_t IDLE_STATE = 0;
static const uint32_t READ_STATE = 1;
static const uint32_t WRITE_STATE = 2;
uint32_t m_curBlock;
uint8_t m_curState;
};
#endif // SdSpiCard_h

View file

@ -0,0 +1,94 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SdSpiCard.h"
bool SdSpiCardEX::readBlock(uint32_t block, uint8_t* dst) {
if (m_curState != READ_STATE || block != m_curBlock) {
if (!syncBlocks()) {
return false;
}
if (!SdSpiCard::readStart(block)) {
return false;
}
m_curBlock = block;
m_curState = READ_STATE;
}
if (!SdSpiCard::readData(dst)) {
return false;
}
m_curBlock++;
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::readBlocks(uint32_t block, uint8_t* dst, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!readBlock(block + i, dst + i*512UL)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::syncBlocks() {
if (m_curState == READ_STATE) {
m_curState = IDLE_STATE;
if (!SdSpiCard::readStop()) {
return false;
}
} else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE;
if (!SdSpiCard::writeStop()) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::writeBlock(uint32_t block, const uint8_t* src) {
if (m_curState != WRITE_STATE || m_curBlock != block) {
if (!syncBlocks()) {
return false;
}
if (!SdSpiCard::writeStart(block)) {
return false;
}
m_curBlock = block;
m_curState = WRITE_STATE;
}
if (!SdSpiCard::writeData(src)) {
return false;
}
m_curBlock++;
return true;
}
//-----------------------------------------------------------------------------
bool SdSpiCardEX::writeBlocks(uint32_t block,
const uint8_t* src, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!writeBlock(block + i, src + i*512UL)) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,303 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SdioCard_h
#define SdioCard_h
#include "../SysCall.h"
#include "../BlockDriver.h"
/**
* \class SdioCard
* \brief Raw SDIO access to SD and SDHC flash memory cards.
*/
class SdioCard : public BaseBlockDriver {
public:
/** Initialize the SD card.
* \return true for success else false.
*/
bool begin();
/**
* Determine the size of an SD flash memory card.
*
* \return The number of 512 byte sectors in the card
* or zero if an error occurs.
*/
uint32_t cardCapacity();
/** \return Card size in sectors or zero if an error occurs. */
uint32_t cardSize() {return cardCapacity();}
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single block erase.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock);
/**
* \return code for the last error. See SdInfo.h for a list of error codes.
*/
uint8_t errorCode();
/** \return error data for last error. */
uint32_t errorData();
/** \return error line for last error. Tmp function for debug. */
uint32_t errorLine();
/**
* Check for busy with CMD13.
*
* \return true if busy else false.
*/
bool isBusy();
/** \return the SD clock frequency in kHz. */
uint32_t kHzSdClk();
/**
* Read a 512 byte block from an SD card.
*
* \param[in] lba Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t lba, uint8_t* dst);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] lba Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t lba, uint8_t* dst, size_t nb);
/**
* Read a card's CID register. The CID contains card identification
* information such as Manufacturer ID, Product name, Product serial
* number and Manufacturing date.
*
* \param[out] cid pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCID(void* cid);
/**
* Read a card's CSD register. The CSD contains Card-Specific Data that
* provides information regarding access to the card's contents.
*
* \param[out] csd pointer to area for returned data.
*
* \return true for success or false for failure.
*/
bool readCSD(void* csd);
/** Read one data block in a multiple block read sequence
*
* \param[out] dst Pointer to the location for the data to be read.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readData(uint8_t *dst);
/** Read OCR register.
*
* \param[out] ocr Value of OCR register.
* \return true for success else false.
*/
bool readOCR(uint32_t* ocr);
/** Start a read multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
*
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStart(uint32_t lba);
/** Start a read multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
* \param[in] count Maximum block count.
* \note This function is used with readData() and readStop() for optimized
* multiple block reads. SPI chipSelect must be low for the entire sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStart(uint32_t lba, uint32_t count);
/** End a read multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readStop();
/** \return success if sync successful. Not for user apps. */
bool syncBlocks();
/** Return the card type: SD V1, SD V2 or SDHC
* \return 0 - SD V1, 1 - SD V2, or 3 - SDHC.
*/
uint8_t type();
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] lba Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t lba, const uint8_t* src);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] lba Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t lba, const uint8_t* src, size_t nb);
/** Write one data block in a multiple block write sequence.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeData(const uint8_t* src);
/** Start a write multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
*
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t lba);
/** Start a write multiple blocks sequence.
*
* \param[in] lba Address of first block in sequence.
* \param[in] count Maximum block count.
* \note This function is used with writeData() and writeStop()
* for optimized multiple block writes.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStart(uint32_t lba, uint32_t count);
/** End a write multiple blocks sequence.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeStop();
};
//==============================================================================
/**
* \class SdioCardEX
* \brief Extended SD I/O block driver.
*/
class SdioCardEX : public SdioCard {
public:
/** Initialize the SD card
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool begin() {
m_curState = IDLE_STATE;
return SdioCard::begin();
}
/** Erase a range of blocks.
*
* \param[in] firstBlock The address of the first block in the range.
* \param[in] lastBlock The address of the last block in the range.
*
* \note This function requests the SD card to do a flash erase for a
* range of blocks. The data on the card after an erase operation is
* either 0 or 1, depends on the card vendor. The card must support
* single block erase.
*
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool erase(uint32_t firstBlock, uint32_t lastBlock) {
return syncBlocks() && SdioCard::erase(firstBlock, lastBlock);
}
/**
* Read a 512 byte block from an SD card.
*
* \param[in] block Logical block to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlock(uint32_t block, uint8_t* dst);
/** End multi-block transfer and go to idle state.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool syncBlocks();
/**
* Writes a 512 byte block to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlock(uint32_t block, const uint8_t* src);
/**
* Read multiple 512 byte blocks from an SD card.
*
* \param[in] block Logical block to be read.
* \param[in] nb Number of blocks to be read.
* \param[out] dst Pointer to the location that will receive the data.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool readBlocks(uint32_t block, uint8_t* dst, size_t nb);
/**
* Write multiple 512 byte blocks to an SD card.
*
* \param[in] block Logical block to be written.
* \param[in] nb Number of blocks to be written.
* \param[in] src Pointer to the location of the data to be written.
* \return The value true is returned for success and
* the value false is returned for failure.
*/
bool writeBlocks(uint32_t block, const uint8_t* src, size_t nb);
private:
static const uint32_t IDLE_STATE = 0;
static const uint32_t READ_STATE = 1;
static const uint32_t WRITE_STATE = 2;
uint32_t m_curLba;
uint32_t m_limitLba;
uint8_t m_curState;
};
#endif // SdioCard_h

View file

@ -0,0 +1,108 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SdioCard.h"
// limit of K66 due to errata KINETIS_K_0N65N.
const uint32_t MAX_SDHC_COUNT = 0XFFFF;
// Max RU is 1024 blocks.
const uint32_t RU_MASK = 0X03FF;
bool SdioCardEX::readBlock(uint32_t lba, uint8_t* dst) {
if (m_curState != READ_STATE || lba != m_curLba) {
if (!syncBlocks()) {
return false;
}
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::readStart(lba, m_limitLba - lba)) {
return false;
}
m_curLba = lba;
m_curState = READ_STATE;
}
if (!SdioCard::readData(dst)) {
return false;
}
m_curLba++;
if (m_curLba >= m_limitLba) {
m_curState = IDLE_STATE;
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::readBlocks(uint32_t lba, uint8_t* dst, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!readBlock(lba + i, dst + i*512UL)) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::syncBlocks() {
if (m_curState == READ_STATE) {
m_curState = IDLE_STATE;
if (!SdioCard::readStop()) {
return false;
}
} else if (m_curState == WRITE_STATE) {
m_curState = IDLE_STATE;
if (!SdioCard::writeStop()) {
return false;
}
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::writeBlock(uint32_t lba, const uint8_t* src) {
if (m_curState != WRITE_STATE || m_curLba != lba) {
if (!syncBlocks()) {
return false;
}
m_limitLba = (lba + MAX_SDHC_COUNT) & ~RU_MASK;
if (!SdioCard::writeStart(lba , m_limitLba - lba)) {
return false;
}
m_curLba = lba;
m_curState = WRITE_STATE;
}
if (!SdioCard::writeData(src)) {
return false;
}
m_curLba++;
if (m_curLba >= m_limitLba) {
m_curState = IDLE_STATE;
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCardEX::writeBlocks(uint32_t lba, const uint8_t* src, size_t nb) {
for (size_t i = 0; i < nb; i++) {
if (!writeBlock(lba + i, src + i*512UL)) {
return false;
}
}
return true;
}

View file

@ -0,0 +1,800 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
#if defined(__MK64FX512__) || defined(__MK66FX1M0__)
#include "SdioCard.h"
//==============================================================================
#define SDHC_PROCTL_DTW_4BIT 0x01
const uint32_t FIFO_WML = 16;
const uint32_t CMD8_RETRIES = 10;
const uint32_t BUSY_TIMEOUT_MICROS = 500000;
//==============================================================================
const uint32_t SDHC_IRQSTATEN_MASK =
SDHC_IRQSTATEN_DMAESEN | SDHC_IRQSTATEN_AC12ESEN |
SDHC_IRQSTATEN_DEBESEN | SDHC_IRQSTATEN_DCESEN |
SDHC_IRQSTATEN_DTOESEN | SDHC_IRQSTATEN_CIESEN |
SDHC_IRQSTATEN_CEBESEN | SDHC_IRQSTATEN_CCESEN |
SDHC_IRQSTATEN_CTOESEN | SDHC_IRQSTATEN_DINTSEN |
SDHC_IRQSTATEN_TCSEN | SDHC_IRQSTATEN_CCSEN;
const uint32_t SDHC_IRQSTAT_CMD_ERROR =
SDHC_IRQSTAT_CIE | SDHC_IRQSTAT_CEBE |
SDHC_IRQSTAT_CCE | SDHC_IRQSTAT_CTOE;
const uint32_t SDHC_IRQSTAT_DATA_ERROR =
SDHC_IRQSTAT_AC12E | SDHC_IRQSTAT_DEBE |
SDHC_IRQSTAT_DCE | SDHC_IRQSTAT_DTOE;
const uint32_t SDHC_IRQSTAT_ERROR =
SDHC_IRQSTAT_DMAE | SDHC_IRQSTAT_CMD_ERROR |
SDHC_IRQSTAT_DATA_ERROR;
const uint32_t SDHC_IRQSIGEN_MASK =
SDHC_IRQSIGEN_DMAEIEN | SDHC_IRQSIGEN_AC12EIEN |
SDHC_IRQSIGEN_DEBEIEN | SDHC_IRQSIGEN_DCEIEN |
SDHC_IRQSIGEN_DTOEIEN | SDHC_IRQSIGEN_CIEIEN |
SDHC_IRQSIGEN_CEBEIEN | SDHC_IRQSIGEN_CCEIEN |
SDHC_IRQSIGEN_CTOEIEN | SDHC_IRQSIGEN_TCIEN;
//=============================================================================
const uint32_t CMD_RESP_NONE = SDHC_XFERTYP_RSPTYP(0);
const uint32_t CMD_RESP_R1 = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
SDHC_XFERTYP_RSPTYP(2);
const uint32_t CMD_RESP_R1b = SDHC_XFERTYP_CICEN | SDHC_XFERTYP_CCCEN |
SDHC_XFERTYP_RSPTYP(3);
const uint32_t CMD_RESP_R2 = SDHC_XFERTYP_CCCEN | SDHC_XFERTYP_RSPTYP(1);
const uint32_t CMD_RESP_R3 = SDHC_XFERTYP_RSPTYP(2);
const uint32_t CMD_RESP_R6 = CMD_RESP_R1;
const uint32_t CMD_RESP_R7 = CMD_RESP_R1;
const uint32_t DATA_READ = SDHC_XFERTYP_DTDSEL | SDHC_XFERTYP_DPSEL;
const uint32_t DATA_READ_DMA = DATA_READ | SDHC_XFERTYP_DMAEN;
const uint32_t DATA_READ_MULTI_DMA = DATA_READ_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
const uint32_t DATA_READ_MULTI_PGM = DATA_READ | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN;
const uint32_t DATA_WRITE_DMA = SDHC_XFERTYP_DPSEL | SDHC_XFERTYP_DMAEN;
const uint32_t DATA_WRITE_MULTI_DMA = DATA_WRITE_DMA | SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_AC12EN | SDHC_XFERTYP_BCEN;
const uint32_t DATA_WRITE_MULTI_PGM = SDHC_XFERTYP_DPSEL |
SDHC_XFERTYP_MSBSEL |
SDHC_XFERTYP_BCEN | SDHC_XFERTYP_AC12EN;
const uint32_t ACMD6_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD6) | CMD_RESP_R1;
const uint32_t ACMD41_XFERTYP = SDHC_XFERTYP_CMDINX(ACMD41) | CMD_RESP_R3;
const uint32_t CMD0_XFERTYP = SDHC_XFERTYP_CMDINX(CMD0) | CMD_RESP_NONE;
const uint32_t CMD2_XFERTYP = SDHC_XFERTYP_CMDINX(CMD2) | CMD_RESP_R2;
const uint32_t CMD3_XFERTYP = SDHC_XFERTYP_CMDINX(CMD3) | CMD_RESP_R6;
const uint32_t CMD6_XFERTYP = SDHC_XFERTYP_CMDINX(CMD6) | CMD_RESP_R1 |
DATA_READ_DMA;
const uint32_t CMD7_XFERTYP = SDHC_XFERTYP_CMDINX(CMD7) | CMD_RESP_R1b;
const uint32_t CMD8_XFERTYP = SDHC_XFERTYP_CMDINX(CMD8) | CMD_RESP_R7;
const uint32_t CMD9_XFERTYP = SDHC_XFERTYP_CMDINX(CMD9) | CMD_RESP_R2;
const uint32_t CMD10_XFERTYP = SDHC_XFERTYP_CMDINX(CMD10) | CMD_RESP_R2;
const uint32_t CMD12_XFERTYP = SDHC_XFERTYP_CMDINX(CMD12) | CMD_RESP_R1b |
SDHC_XFERTYP_CMDTYP(3);
const uint32_t CMD13_XFERTYP = SDHC_XFERTYP_CMDINX(CMD13) | CMD_RESP_R1;
const uint32_t CMD17_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD17) | CMD_RESP_R1 |
DATA_READ_DMA;
const uint32_t CMD18_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
DATA_READ_MULTI_DMA;
const uint32_t CMD18_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD18) | CMD_RESP_R1 |
DATA_READ_MULTI_PGM;
const uint32_t CMD24_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD24) | CMD_RESP_R1 |
DATA_WRITE_DMA;
const uint32_t CMD25_DMA_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
DATA_WRITE_MULTI_DMA;
const uint32_t CMD25_PGM_XFERTYP = SDHC_XFERTYP_CMDINX(CMD25) | CMD_RESP_R1 |
DATA_WRITE_MULTI_PGM;
const uint32_t CMD32_XFERTYP = SDHC_XFERTYP_CMDINX(CMD32) | CMD_RESP_R1;
const uint32_t CMD33_XFERTYP = SDHC_XFERTYP_CMDINX(CMD33) | CMD_RESP_R1;
const uint32_t CMD38_XFERTYP = SDHC_XFERTYP_CMDINX(CMD38) | CMD_RESP_R1b;
const uint32_t CMD55_XFERTYP = SDHC_XFERTYP_CMDINX(CMD55) | CMD_RESP_R1;
//=============================================================================
static bool cardCommand(uint32_t xfertyp, uint32_t arg);
static void enableGPIO(bool enable);
static void enableDmaIrs();
static void initSDHC();
static bool isBusyCMD13();
static bool isBusyCommandComplete();
static bool isBusyCommandInhibit();
static bool readReg16(uint32_t xfertyp, void* data);
static void setSdclk(uint32_t kHzMax);
static bool yieldTimeout(bool (*fcn)());
static bool waitDmaStatus();
static bool waitTimeout(bool (*fcn)());
//-----------------------------------------------------------------------------
static bool (*m_busyFcn)() = 0;
static bool m_initDone = false;
static bool m_version2;
static bool m_highCapacity;
static uint8_t m_errorCode = SD_CARD_ERROR_INIT_NOT_CALLED;
static uint32_t m_errorLine = 0;
static uint32_t m_rca;
static volatile bool m_dmaBusy = false;
static volatile uint32_t m_irqstat;
static uint32_t m_sdClkKhz = 0;
static uint32_t m_ocr;
static cid_t m_cid;
static csd_t m_csd;
//=============================================================================
#define USE_DEBUG_MODE 0
#if USE_DEBUG_MODE
#define DBG_IRQSTAT() if (SDHC_IRQSTAT) {Serial.print(__LINE__);\
Serial.print(" IRQSTAT "); Serial.println(SDHC_IRQSTAT, HEX);}
static void printRegs(uint32_t line) {
Serial.print(line);
Serial.print(" PRSSTAT ");
Serial.print(SDHC_PRSSTAT, HEX);
Serial.print(" PROCTL ");
Serial.print(SDHC_PROCTL, HEX);
Serial.print(" IRQSTAT ");
Serial.print(SDHC_IRQSTAT, HEX);
Serial.print(" m_irqstat ");
Serial.println(m_irqstat, HEX);
}
#else // USE_DEBUG_MODE
#define DBG_IRQSTAT()
#endif // USE_DEBUG_MODE
//=============================================================================
// Error function and macro.
#define sdError(code) setSdErrorCode(code, __LINE__)
inline bool setSdErrorCode(uint8_t code, uint32_t line) {
m_errorCode = code;
m_errorLine = line;
return false; // setSdErrorCode
}
//=============================================================================
// ISR
void sdhc_isr() {
SDHC_IRQSIGEN = 0;
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
m_dmaBusy = false;
}
//=============================================================================
// Static functions.
static bool cardAcmd(uint32_t rca, uint32_t xfertyp, uint32_t arg) {
return cardCommand(CMD55_XFERTYP, rca) && cardCommand (xfertyp, arg);
}
//-----------------------------------------------------------------------------
static bool cardCommand(uint32_t xfertyp, uint32_t arg) {
DBG_IRQSTAT();
if (waitTimeout(isBusyCommandInhibit)) {
return false; // Caller will set errorCode.
}
SDHC_CMDARG = arg;
SDHC_XFERTYP = xfertyp;
if (waitTimeout(isBusyCommandComplete)) {
return false; // Caller will set errorCode.
}
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
return (m_irqstat & SDHC_IRQSTAT_CC) &&
!(m_irqstat & SDHC_IRQSTAT_CMD_ERROR);
}
//-----------------------------------------------------------------------------
static bool cardCMD6(uint32_t arg, uint8_t* status) {
// CMD6 returns 64 bytes.
if (waitTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
enableDmaIrs();
SDHC_DSADDR = (uint32_t)status;
SDHC_CMDARG = arg;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(1) | SDHC_BLKATTR_BLKSIZE(64);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
SDHC_XFERTYP = CMD6_XFERTYP;
if (!waitDmaStatus()) {
return sdError(SD_CARD_ERROR_CMD6);
}
return true;
}
//-----------------------------------------------------------------------------
static void enableGPIO(bool enable) {
const uint32_t PORT_CLK = PORT_PCR_MUX(4) | PORT_PCR_DSE;
const uint32_t PORT_CMD_DATA = PORT_CLK | PORT_PCR_PS | PORT_PCR_PE;
PORTE_PCR0 = enable ? PORT_CMD_DATA : 0; // SDHC_D1
PORTE_PCR1 = enable ? PORT_CMD_DATA : 0; // SDHC_D0
PORTE_PCR2 = enable ? PORT_CLK : 0; // SDHC_CLK
PORTE_PCR3 = enable ? PORT_CMD_DATA : 0; // SDHC_CMD
PORTE_PCR4 = enable ? PORT_CMD_DATA : 0; // SDHC_D3
PORTE_PCR5 = enable ? PORT_CMD_DATA : 0; // SDHC_D2
}
//-----------------------------------------------------------------------------
static void enableDmaIrs() {
m_dmaBusy = true;
m_irqstat = 0;
}
//-----------------------------------------------------------------------------
static void initSDHC() {
#ifdef HAS_KINETIS_MPU
// Allow SDHC Bus Master access.
MPU_RGDAAC0 |= 0x0C000000;
#endif
// Enable SDHC clock.
SIM_SCGC3 |= SIM_SCGC3_SDHC;
// Disable GPIO clock.
enableGPIO(false);
// Reset SDHC. Use default Water Mark Level of 16.
SDHC_SYSCTL = SDHC_SYSCTL_RSTA;
while (SDHC_SYSCTL & SDHC_SYSCTL_RSTA) {
}
// Set initial SCK rate.
setSdclk(400);
enableGPIO(true);
// Enable desired IRQSTAT bits.
SDHC_IRQSTATEN = SDHC_IRQSTATEN_MASK;
NVIC_SET_PRIORITY(IRQ_SDHC, 6*16);
NVIC_ENABLE_IRQ(IRQ_SDHC);
// Send 80 clocks to card.
SDHC_SYSCTL |= SDHC_SYSCTL_INITA;
while (SDHC_SYSCTL & SDHC_SYSCTL_INITA) {
}
}
//-----------------------------------------------------------------------------
static bool isBusyCMD13() {
if (!cardCommand(CMD13_XFERTYP, m_rca)) {
// Caller will timeout.
return true;
}
return !(SDHC_CMDRSP0 & CARD_STATUS_READY_FOR_DATA);
}
//-----------------------------------------------------------------------------
static bool isBusyCommandComplete() {
return !(SDHC_IRQSTAT &(SDHC_IRQSTAT_CC | SDHC_IRQSTAT_CMD_ERROR));
}
//-----------------------------------------------------------------------------
static bool isBusyCommandInhibit() {
return SDHC_PRSSTAT & SDHC_PRSSTAT_CIHB;
}
//-----------------------------------------------------------------------------
static bool isBusyDMA() {
return m_dmaBusy;
}
//-----------------------------------------------------------------------------
static bool isBusyFifoRead() {
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BREN);
}
//-----------------------------------------------------------------------------
static bool isBusyFifoWrite() {
return !(SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN);
}
//-----------------------------------------------------------------------------
static bool isBusyTransferComplete() {
return !(SDHC_IRQSTAT & (SDHC_IRQSTAT_TC | SDHC_IRQSTAT_ERROR));
}
//-----------------------------------------------------------------------------
static bool rdWrBlocks(uint32_t xfertyp,
uint32_t lba, uint8_t* buf, size_t n) {
if ((3 & (uint32_t)buf) || n == 0) {
return sdError(SD_CARD_ERROR_DMA);
}
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
enableDmaIrs();
SDHC_DSADDR = (uint32_t)buf;
SDHC_CMDARG = m_highCapacity ? lba : 512*lba;
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(n) | SDHC_BLKATTR_BLKSIZE(512);
SDHC_IRQSIGEN = SDHC_IRQSIGEN_MASK;
SDHC_XFERTYP = xfertyp;
return waitDmaStatus();
}
//-----------------------------------------------------------------------------
// Read 16 byte CID or CSD register.
static bool readReg16(uint32_t xfertyp, void* data) {
uint8_t* d = reinterpret_cast<uint8_t*>(data);
if (!cardCommand(xfertyp, m_rca)) {
return false; // Caller will set errorCode.
}
uint32_t sr[] = {SDHC_CMDRSP0, SDHC_CMDRSP1, SDHC_CMDRSP2, SDHC_CMDRSP3};
for (int i = 0; i < 15; i++) {
d[14 - i] = sr[i/4] >> 8*(i%4);
}
d[15] = 0;
return true;
}
//-----------------------------------------------------------------------------
static void setSdclk(uint32_t kHzMax) {
const uint32_t DVS_LIMIT = 0X10;
const uint32_t SDCLKFS_LIMIT = 0X100;
uint32_t dvs = 1;
uint32_t sdclkfs = 1;
uint32_t maxSdclk = 1000*kHzMax;
while ((F_CPU/(sdclkfs*DVS_LIMIT) > maxSdclk) && (sdclkfs < SDCLKFS_LIMIT)) {
sdclkfs <<= 1;
}
while ((F_CPU/(sdclkfs*dvs) > maxSdclk) && (dvs < DVS_LIMIT)) {
dvs++;
}
m_sdClkKhz = F_CPU/(1000*sdclkfs*dvs);
sdclkfs >>= 1;
dvs--;
// Disable SDHC clock.
SDHC_SYSCTL &= ~SDHC_SYSCTL_SDCLKEN;
// Change dividers.
uint32_t sysctl = SDHC_SYSCTL & ~(SDHC_SYSCTL_DTOCV_MASK
| SDHC_SYSCTL_DVS_MASK | SDHC_SYSCTL_SDCLKFS_MASK);
SDHC_SYSCTL = sysctl | SDHC_SYSCTL_DTOCV(0x0E) | SDHC_SYSCTL_DVS(dvs)
| SDHC_SYSCTL_SDCLKFS(sdclkfs);
// Wait until the SDHC clock is stable.
while (!(SDHC_PRSSTAT & SDHC_PRSSTAT_SDSTB)) {
}
// Enable the SDHC clock.
SDHC_SYSCTL |= SDHC_SYSCTL_SDCLKEN;
}
//-----------------------------------------------------------------------------
static bool transferStop() {
DBG_IRQSTAT();
if (!cardCommand(CMD12_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD12);
}
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
// Save registers before reset DAT lines.
uint32_t irqsststen = SDHC_IRQSTATEN;
uint32_t proctl = SDHC_PROCTL & ~SDHC_PROCTL_SABGREQ;
// Do reset to clear CDIHB. Should be a better way!
SDHC_SYSCTL |= SDHC_SYSCTL_RSTD;
// Restore registers.
SDHC_IRQSTATEN = irqsststen;
SDHC_PROCTL = proctl;
return true;
}
//-----------------------------------------------------------------------------
// Return true if timeout occurs.
static bool yieldTimeout(bool (*fcn)()) {
m_busyFcn = fcn;
uint32_t m = micros();
while (fcn()) {
if ((micros() - m) > BUSY_TIMEOUT_MICROS) {
m_busyFcn = 0;
return true;
}
yield();
}
m_busyFcn = 0;
return false; // Caller will set errorCode.
}
//-----------------------------------------------------------------------------
static bool waitDmaStatus() {
if (yieldTimeout(isBusyDMA)) {
return false; // Caller will set errorCode.
}
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
}
//-----------------------------------------------------------------------------
// Return true if timeout occurs.
static bool waitTimeout(bool (*fcn)()) {
uint32_t m = micros();
while (fcn()) {
if ((micros() - m) > BUSY_TIMEOUT_MICROS) {
return true;
}
}
return false; // Caller will set errorCode.
}
//=============================================================================
bool SdioCard::begin() {
uint32_t kHzSdClk;
uint32_t arg;
m_initDone = false;
m_errorCode = SD_CARD_ERROR_NONE;
m_highCapacity = false;
m_version2 = false;
// initialize controller.
initSDHC();
if (!cardCommand(CMD0_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD0);
}
// Try several times for case of reset delay.
for (uint32_t i = 0; i < CMD8_RETRIES; i++) {
if (cardCommand(CMD8_XFERTYP, 0X1AA)) {
if (SDHC_CMDRSP0 != 0X1AA) {
return sdError(SD_CARD_ERROR_CMD8);
}
m_version2 = true;
break;
}
}
arg = m_version2 ? 0X40300000 : 0x00300000;
uint32_t m = micros();
do {
if (!cardAcmd(0, ACMD41_XFERTYP, arg) ||
((micros() - m) > BUSY_TIMEOUT_MICROS)) {
return sdError(SD_CARD_ERROR_ACMD41);
}
} while ((SDHC_CMDRSP0 & 0x80000000) == 0);
m_ocr = SDHC_CMDRSP0;
if (SDHC_CMDRSP0 & 0x40000000) {
// Is high capacity.
m_highCapacity = true;
}
if (!cardCommand(CMD2_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD2);
}
if (!cardCommand(CMD3_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD3);
}
m_rca = SDHC_CMDRSP0 & 0xFFFF0000;
if (!readReg16(CMD9_XFERTYP, &m_csd)) {
return sdError(SD_CARD_ERROR_CMD9);
}
if (!readReg16(CMD10_XFERTYP, &m_cid)) {
return sdError(SD_CARD_ERROR_CMD10);
}
if (!cardCommand(CMD7_XFERTYP, m_rca)) {
return sdError(SD_CARD_ERROR_CMD7);
}
// Set card to bus width four.
if (!cardAcmd(m_rca, ACMD6_XFERTYP, 2)) {
return sdError(SD_CARD_ERROR_ACMD6);
}
// Set SDHC to bus width four.
SDHC_PROCTL &= ~SDHC_PROCTL_DTW_MASK;
SDHC_PROCTL |= SDHC_PROCTL_DTW(SDHC_PROCTL_DTW_4BIT);
SDHC_WML = SDHC_WML_RDWML(FIFO_WML) | SDHC_WML_WRWML(FIFO_WML);
// Determine if High Speed mode is supported and set frequency.
uint8_t status[64];
if (cardCMD6(0X00FFFFFF, status) && (2 & status[13]) &&
cardCMD6(0X80FFFFF1, status) && (status[16] & 0XF) == 1) {
kHzSdClk = 50000;
} else {
kHzSdClk = 25000;
}
// disable GPIO
enableGPIO(false);
// Set the SDHC SCK frequency.
setSdclk(kHzSdClk);
// enable GPIO
enableGPIO(true);
m_initDone = true;
return true;
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::cardCapacity() {
return sdCardCapacity(&m_csd);
}
//-----------------------------------------------------------------------------
bool SdioCard::erase(uint32_t firstBlock, uint32_t lastBlock) {
// check for single block erase
if (!m_csd.v1.erase_blk_en) {
// erase size mask
uint8_t m = (m_csd.v1.sector_size_high << 1) | m_csd.v1.sector_size_low;
if ((firstBlock & m) != 0 || ((lastBlock + 1) & m) != 0) {
// error card can't erase specified area
return sdError(SD_CARD_ERROR_ERASE_SINGLE_BLOCK);
}
}
if (!m_highCapacity) {
firstBlock <<= 9;
lastBlock <<= 9;
}
if (!cardCommand(CMD32_XFERTYP, firstBlock)) {
return sdError(SD_CARD_ERROR_CMD32);
}
if (!cardCommand(CMD33_XFERTYP, lastBlock)) {
return sdError(SD_CARD_ERROR_CMD33);
}
if (!cardCommand(CMD38_XFERTYP, 0)) {
return sdError(SD_CARD_ERROR_CMD38);
}
if (waitTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_ERASE_TIMEOUT);
}
return true;
}
//-----------------------------------------------------------------------------
uint8_t SdioCard::errorCode() {
return m_errorCode;
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::errorData() {
return m_irqstat;
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::errorLine() {
return m_errorLine;
}
//-----------------------------------------------------------------------------
bool SdioCard::isBusy() {
return m_busyFcn ? m_busyFcn() : m_initDone && isBusyCMD13();
}
//-----------------------------------------------------------------------------
uint32_t SdioCard::kHzSdClk() {
return m_sdClkKhz;
}
//-----------------------------------------------------------------------------
bool SdioCard::readBlock(uint32_t lba, uint8_t* buf) {
uint8_t aligned[512];
uint8_t* ptr = (uint32_t)buf & 3 ? aligned : buf;
if (!rdWrBlocks(CMD17_DMA_XFERTYP, lba, ptr, 1)) {
return sdError(SD_CARD_ERROR_CMD18);
}
if (ptr != buf) {
memcpy(buf, aligned, 512);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readBlocks(uint32_t lba, uint8_t* buf, size_t n) {
if ((uint32_t)buf & 3) {
for (size_t i = 0; i < n; i++, lba++, buf += 512) {
if (!readBlock(lba, buf)) {
return false; // readBlock will set errorCode.
}
}
return true;
}
if (!rdWrBlocks(CMD18_DMA_XFERTYP, lba, buf, n)) {
return sdError(SD_CARD_ERROR_CMD18);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readCID(void* cid) {
memcpy(cid, &m_cid, 16);
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readCSD(void* csd) {
memcpy(csd, &m_csd, 16);
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readData(uint8_t *dst) {
DBG_IRQSTAT();
uint32_t *p32 = reinterpret_cast<uint32_t*>(dst);
if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_RTA)) {
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) {
// Don't stop at block gap if last block. Allows auto CMD12.
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
} else {
noInterrupts();
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
interrupts();
}
}
if (waitTimeout(isBusyFifoRead)) {
return sdError(SD_CARD_ERROR_READ_FIFO);
}
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BREN)) {
}
for (uint32_t i = 0; i < FIFO_WML; i++) {
p32[i] = SDHC_DATPORT;
}
p32 += FIFO_WML;
}
if (waitTimeout(isBusyTransferComplete)) {
return sdError(SD_CARD_ERROR_READ_TIMEOUT);
}
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
}
//-----------------------------------------------------------------------------
bool SdioCard::readOCR(uint32_t* ocr) {
*ocr = m_ocr;
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readStart(uint32_t lba) {
// K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode.
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
}
//-----------------------------------------------------------------------------
// SDHC will do Auto CMD12 after count blocks.
bool SdioCard::readStart(uint32_t lba, uint32_t count) {
DBG_IRQSTAT();
if (count > 0XFFFF) {
return sdError(SD_CARD_ERROR_READ_START);
}
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
if (count > 1) {
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
if (!cardCommand(CMD18_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) {
return sdError(SD_CARD_ERROR_CMD18);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::readStop() {
return transferStop();
}
//-----------------------------------------------------------------------------
bool SdioCard::syncBlocks() {
return true;
}
//-----------------------------------------------------------------------------
uint8_t SdioCard::type() {
return m_version2 ? m_highCapacity ?
SD_CARD_TYPE_SDHC : SD_CARD_TYPE_SD2 : SD_CARD_TYPE_SD1;
}
//-----------------------------------------------------------------------------
bool SdioCard::writeBlock(uint32_t lba, const uint8_t* buf) {
uint8_t *ptr;
uint8_t aligned[512];
if (3 & (uint32_t)buf) {
ptr = aligned;
memcpy(aligned, buf, 512);
} else {
ptr = const_cast<uint8_t*>(buf);
}
if (!rdWrBlocks(CMD24_DMA_XFERTYP, lba, ptr, 1)) {
return sdError(SD_CARD_ERROR_CMD24);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::writeBlocks(uint32_t lba, const uint8_t* buf, size_t n) {
uint8_t* ptr = const_cast<uint8_t*>(buf);
if (3 & (uint32_t)ptr) {
for (size_t i = 0; i < n; i++, lba++, ptr += 512) {
if (!writeBlock(lba, ptr)) {
return false; // writeBlock will set errorCode.
}
}
return true;
}
if (!rdWrBlocks(CMD25_DMA_XFERTYP, lba, ptr, n)) {
return sdError(SD_CARD_ERROR_CMD25);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::writeData(const uint8_t* src) {
DBG_IRQSTAT();
const uint32_t* p32 = reinterpret_cast<const uint32_t*>(src);
if (!(SDHC_PRSSTAT & SDHC_PRSSTAT_WTA)) {
SDHC_PROCTL &= ~SDHC_PROCTL_SABGREQ;
// Don't stop at block gap if last block. Allows auto CMD12.
if ((SDHC_BLKATTR & 0XFFFF0000) == 0X10000) {
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
} else {
SDHC_PROCTL |= SDHC_PROCTL_CREQ;
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
}
if (waitTimeout(isBusyFifoWrite)) {
return sdError(SD_CARD_ERROR_WRITE_FIFO);
}
for (uint32_t iw = 0 ; iw < 512/(4*FIFO_WML); iw++) {
while (0 == (SDHC_PRSSTAT & SDHC_PRSSTAT_BWEN)) {
}
for (uint32_t i = 0; i < FIFO_WML; i++) {
SDHC_DATPORT = p32[i];
}
p32 += FIFO_WML;
}
if (waitTimeout(isBusyTransferComplete)) {
return sdError(SD_CARD_ERROR_WRITE_TIMEOUT);
}
m_irqstat = SDHC_IRQSTAT;
SDHC_IRQSTAT = m_irqstat;
return (m_irqstat & SDHC_IRQSTAT_TC) && !(m_irqstat & SDHC_IRQSTAT_ERROR);
}
//-----------------------------------------------------------------------------
bool SdioCard::writeStart(uint32_t lba) {
// K66/K65 Errata - SDHC: Does not support Infinite Block Transfer Mode.
return sdError(SD_CARD_ERROR_FUNCTION_NOT_SUPPORTED);
}
//-----------------------------------------------------------------------------
// SDHC will do Auto CMD12 after count blocks.
bool SdioCard::writeStart(uint32_t lba, uint32_t count) {
if (count > 0XFFFF) {
return sdError(SD_CARD_ERROR_WRITE_START);
}
DBG_IRQSTAT();
if (yieldTimeout(isBusyCMD13)) {
return sdError(SD_CARD_ERROR_CMD13);
}
if (count > 1) {
SDHC_PROCTL |= SDHC_PROCTL_SABGREQ;
}
SDHC_BLKATTR = SDHC_BLKATTR_BLKCNT(count) | SDHC_BLKATTR_BLKSIZE(512);
if (!cardCommand(CMD25_PGM_XFERTYP, m_highCapacity ? lba : 512*lba)) {
return sdError(SD_CARD_ERROR_CMD25);
}
return true;
}
//-----------------------------------------------------------------------------
bool SdioCard::writeStop() {
return transferStop();
}
#endif // defined(__MK64FX512__) || defined(__MK66FX1M0__)

View file

@ -0,0 +1,512 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SdFat_h
#define SdFat_h
/**
* \file
* \brief SdFat class
*/
#include "SysCall.h"
#include "BlockDriver.h"
#include "FatLib/FatLib.h"
#include "SdCard/SdioCard.h"
#if INCLUDE_SDIOS
#include "sdios.h"
#endif // INCLUDE_SDIOS
//------------------------------------------------------------------------------
/** SdFat version 1.1.2 */
#define SD_FAT_VERSION 10102
//==============================================================================
/**
* \class SdBaseFile
* \brief Class for backward compatibility.
*/
class SdBaseFile : public FatFile {
public:
SdBaseFile() {}
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of open flags. see
* FatFile::open(FatFile*, const char*, oflag_t).
*/
SdBaseFile(const char* path, oflag_t oflag) : FatFile(path, oflag) {}
};
//-----------------------------------------------------------------------------
#if ENABLE_ARDUINO_FEATURES
/**
* \class SdFile
* \brief Class for backward compatibility.
*/
class SdFile : public PrintFile {
public:
SdFile() {}
/** Create a file object and open it in the current working directory.
*
* \param[in] path A path for a file to be opened.
*
* \param[in] oflag Values for \a oflag are constructed by a
* bitwise-inclusive OR of open flags. see
* FatFile::open(FatFile*, const char*, oflag_t).
*/
SdFile(const char* path, oflag_t oflag) : PrintFile(path, oflag) {}
};
#endif // #if ENABLE_ARDUINO_FEATURES
//-----------------------------------------------------------------------------
/**
* \class SdFileSystem
* \brief Virtual base class for %SdFat library.
*/
template<class SdDriverClass>
class SdFileSystem : public FatFileSystem {
public:
/** Initialize file system.
* \return true for success else false.
*/
bool begin() {
return FatFileSystem::begin(&m_card);
}
/** \return Pointer to SD card object */
SdDriverClass *card() {
m_card.syncBlocks();
return &m_card;
}
/** %Print any SD error code to Serial and halt. */
void errorHalt() {
errorHalt(&Serial);
}
/** %Print any SD error code and halt.
*
* \param[in] pr Print destination.
*/
void errorHalt(Print* pr) {
errorPrint(pr);
SysCall::halt();
}
/** %Print msg, any SD error code and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(char const* msg) {
errorHalt(&Serial, msg);
}
/** %Print msg, any SD error code, and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(Print* pr, char const* msg) {
errorPrint(pr, msg);
SysCall::halt();
}
/** %Print any SD error code to Serial */
void errorPrint() {
errorPrint(&Serial);
}
/** %Print any SD error code.
* \param[in] pr Print device.
*/
void errorPrint(Print* pr) {
if (!cardErrorCode()) {
return;
}
pr->print(F("SD errorCode: 0X"));
pr->print(cardErrorCode(), HEX);
pr->print(F(",0X"));
pr->println(cardErrorData(), HEX);
}
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const char* msg) {
errorPrint(&Serial, msg);
}
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(Print* pr, char const* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
/** %Print any SD error code and halt. */
void initErrorHalt() {
initErrorHalt(&Serial);
}
/** %Print error details and halt after begin fails.
*
* \param[in] pr Print destination.
*/
void initErrorHalt(Print* pr) {
initErrorPrint(pr);
SysCall::halt();
}
/**Print message, error details, and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(char const *msg) {
initErrorHalt(&Serial, msg);
}
/**Print message, error details, and halt after begin() fails.
* \param[in] pr Print device.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, char const *msg) {
pr->println(msg);
initErrorHalt(pr);
}
/** Print error details after begin() fails. */
void initErrorPrint() {
initErrorPrint(&Serial);
}
/** Print error details after begin() fails.
*
* \param[in] pr Print destination.
*/
void initErrorPrint(Print* pr) {
if (cardErrorCode()) {
pr->println(F("Can't access SD card. Do not reformat."));
if (cardErrorCode() == SD_CARD_ERROR_CMD0) {
pr->println(F("No card, wrong chip select pin, or SPI problem?"));
}
errorPrint(pr);
} else if (vol()->fatType() == 0) {
pr->println(F("Invalid format, reformat SD."));
} else if (!vwd()->isOpen()) {
pr->println(F("Can't open root directory."));
} else {
pr->println(F("No error found."));
}
}
/**Print message and error details and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorPrint(char const *msg) {
initErrorPrint(&Serial, msg);
}
/**Print message and error details and halt after begin() fails.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorPrint(Print* pr, char const *msg) {
pr->println(msg);
initErrorPrint(pr);
}
#if defined(ARDUINO) || defined(DOXYGEN)
/** %Print msg, any SD error code, and halt.
*
* \param[in] msg Message to print.
*/
void errorHalt(const __FlashStringHelper* msg) {
errorHalt(&Serial, msg);
}
/** %Print msg, any SD error code, and halt.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorHalt(Print* pr, const __FlashStringHelper* msg) {
errorPrint(pr, msg);
SysCall::halt();
}
/** %Print msg, any SD error code.
*
* \param[in] msg Message to print.
*/
void errorPrint(const __FlashStringHelper* msg) {
errorPrint(&Serial, msg);
}
/** %Print msg, any SD error code.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void errorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->print(F("error: "));
pr->println(msg);
errorPrint(pr);
}
/**Print message, error details, and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorHalt(const __FlashStringHelper* msg) {
initErrorHalt(&Serial, msg);
}
/**Print message, error details, and halt after begin() fails.
* \param[in] pr Print device for message.
* \param[in] msg Message to print.
*/
void initErrorHalt(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorHalt(pr);
}
/**Print message and error details and halt after begin() fails.
*
* \param[in] msg Message to print.
*/
void initErrorPrint(const __FlashStringHelper* msg) {
initErrorPrint(&Serial, msg);
}
/**Print message and error details and halt after begin() fails.
*
* \param[in] pr Print destination.
* \param[in] msg Message to print.
*/
void initErrorPrint(Print* pr, const __FlashStringHelper* msg) {
pr->println(msg);
initErrorPrint(pr);
}
#endif // defined(ARDUINO) || defined(DOXYGEN)
/** \return The card error code */
uint8_t cardErrorCode() {
return m_card.errorCode();
}
/** \return the card error data */
uint32_t cardErrorData() {
return m_card.errorData();
}
protected:
SdDriverClass m_card;
};
//==============================================================================
/**
* \class SdFat
* \brief Main file system class for %SdFat library.
*/
class SdFat : public SdFileSystem<SdSpiCard> {
public:
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
SdFat() {
m_spi.setPort(nullptr);
}
/** Constructor with SPI port selection.
* \param[in] spiPort SPI port number.
*/
explicit SdFat(SPIClass* spiPort) {
m_spi.setPort(spiPort);
}
#endif // IMPLEMENT_SPI_PORT_SELECTION
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin();
}
/** Initialize SD card for diagnostic use only.
*
* \param[in] csPin SD card chip select pin.
* \param[in] settings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool cardBegin(uint8_t csPin = SS, SPISettings settings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, settings);
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
bool fsBegin() {
return FatFileSystem::begin(card());
}
private:
SdFatSpiDriver m_spi;
};
//==============================================================================
#if ENABLE_SDIO_CLASS || defined(DOXYGEN)
/**
* \class SdFatSdio
* \brief SdFat class using SDIO.
*/
class SdFatSdio : public SdFileSystem<SdioCard> {
public:
/** Initialize SD card and file system.
* \return true for success else false.
*/
bool begin() {
return m_card.begin() && SdFileSystem::begin();
}
/** Initialize SD card for diagnostic use only.
*
* \return true for success else false.
*/
bool cardBegin() {
return m_card.begin();
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
bool fsBegin() {
return SdFileSystem::begin();
}
};
#if ENABLE_SDIOEX_CLASS || defined(DOXYGEN)
//-----------------------------------------------------------------------------
/**
* \class SdFatSdioEX
* \brief SdFat class using SDIO.
*/
class SdFatSdioEX : public SdFileSystem<SdioCardEX> {
public:
/** Initialize SD card and file system.
* \return true for success else false.
*/
bool begin() {
return m_card.begin() && SdFileSystem::begin();
}
/** \return Pointer to SD card object */
SdioCardEX* card() {
return &m_card;
}
/** Initialize SD card for diagnostic use only.
*
* \return true for success else false.
*/
bool cardBegin() {
return m_card.begin();
}
/** Initialize file system for diagnostic use only.
* \return true for success else false.
*/
bool fsBegin() {
return SdFileSystem::begin();
}
};
#endif // ENABLE_SDIOEX_CLASS || defined(DOXYGEN)
#endif // ENABLE_SDIO_CLASS || defined(DOXYGEN)
//=============================================================================
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
/**
* \class SdFatSoftSpi
* \brief SdFat class using software SPI.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdFatSoftSpi : public SdFileSystem<SdSpiCard> {
public:
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings ignored for software SPI..
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin();
}
private:
SdSpiSoftDriver<MisoPin, MosiPin, SckPin> m_spi;
};
#endif // #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
//==============================================================================
#if ENABLE_EXTENDED_TRANSFER_CLASS || defined(DOXYGEN)
/**
* \class SdFatEX
* \brief SdFat class with extended SD I/O.
*/
class SdFatEX : public SdFileSystem<SdSpiCardEX> {
public:
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
SdFatEX() {
m_spi.setPort(nullptr);
}
/** Constructor with SPI port selection.
* \param[in] spiPort SPI port number.
*/
explicit SdFatEX(SPIClass* spiPort) {
m_spi.setPort(spiPort);
}
#endif // IMPLEMENT_SPI_PORT_SELECTION
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin();
}
private:
SdFatSpiDriver m_spi;
};
//==============================================================================
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
/**
* \class SdFatSoftSpiEX
* \brief SdFat class using software SPI and extended SD I/O.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdFatSoftSpiEX : public SdFileSystem<SdSpiCardEX> {
public:
/** Initialize SD card and file system.
*
* \param[in] csPin SD card chip select pin.
* \param[in] spiSettings ignored for software SPI.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, SPISettings spiSettings = SPI_FULL_SPEED) {
return m_card.begin(&m_spi, csPin, spiSettings) &&
SdFileSystem::begin();
}
private:
SdSpiSoftDriver<MisoPin, MosiPin, SckPin> m_spi;
};
#endif // #if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
#endif // ENABLE_EXTENDED_TRANSFER_CLASS || defined(DOXYGEN)
//=============================================================================
/**
* \class Sd2Card
* \brief Raw access to SD and SDHC card using default SPI library.
*/
class Sd2Card : public SdSpiCard {
public:
/** Initialize the SD card.
* \param[in] csPin SD chip select pin.
* \param[in] settings SPI speed, mode, and bit order.
* \return true for success else false.
*/
bool begin(uint8_t csPin = SS, SPISettings settings = SD_SCK_MHZ(50)) {
return SdSpiCard::begin(&m_spi, csPin, settings);
}
private:
SdFatSpiDriver m_spi;
};
#endif // SdFat_h

View file

@ -0,0 +1,231 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* \file
* \brief configuration definitions
*/
#ifndef SdFatConfig_h
#define SdFatConfig_h
#include <Arduino.h>
#include <stdint.h>
#ifdef __AVR__
#include <avr/io.h>
#endif // __AVR__
//------------------------------------------------------------------------------
/**
* Set INCLUDE_SDIOS nonzero to include sdios.h in SdFat.h.
* sdios.h provides C++ style IO Streams.
*/
#define INCLUDE_SDIOS 1
//------------------------------------------------------------------------------
/**
* Set USE_LONG_FILE_NAMES nonzero to use long file names (LFN).
* Long File Name are limited to a maximum length of 255 characters.
*
* This implementation allows 7-bit characters in the range
* 0X20 to 0X7E except the following characters are not allowed:
*
* < (less than)
* > (greater than)
* : (colon)
* " (double quote)
* / (forward slash)
* \ (backslash)
* | (vertical bar or pipe)
* ? (question mark)
* * (asterisk)
*
*/
#define USE_LONG_FILE_NAMES 1
//------------------------------------------------------------------------------
/**
* If the symbol ENABLE_EXTENDED_TRANSFER_CLASS is nonzero, the class SdFatEX
* will be defined. If the symbol ENABLE_SOFTWARE_SPI_CLASS is also nonzero,
* the class SdFatSoftSpiEX will be defined.
*
* These classes used extended multi-block SD I/O for better performance.
* the SPI bus may not be shared with other devices in this mode.
*/
#define ENABLE_EXTENDED_TRANSFER_CLASS 0
//------------------------------------------------------------------------------
/**
* If the symbol USE_STANDARD_SPI_LIBRARY is zero, an optimized custom SPI
* driver is used if it exists. If the symbol USE_STANDARD_SPI_LIBRARY is
* one, the standard Arduino SPI.h library is used with SPI. If the symbol
* USE_STANDARD_SPI_LIBRARY is two, the SPI port can be selected with the
* constructors SdFat(SPIClass* spiPort) and SdFatEX(SPIClass* spiPort).
*/
#define USE_STANDARD_SPI_LIBRARY 1
//------------------------------------------------------------------------------
/**
* If the symbol ENABLE_SOFTWARE_SPI_CLASS is nonzero, the class SdFatSoftSpi
* will be defined. If ENABLE_EXTENDED_TRANSFER_CLASS is also nonzero,
* the class SdFatSoftSpiEX will be defined.
*/
#define ENABLE_SOFTWARE_SPI_CLASS 1
//------------------------------------------------------------------------------
/** If the symbol USE_FCNTL_H is nonzero, open flags for access modes O_RDONLY,
* O_WRONLY, O_RDWR and the open modifiers O_APPEND, O_CREAT, O_EXCL, O_SYNC
* will be defined by including the system file fcntl.h.
*/
#if defined(__AVR__)
// AVR fcntl.h does not define open flags.
#define USE_FCNTL_H 0
#elif defined(PLATFORM_ID)
// Particle boards - use fcntl.h.
#define USE_FCNTL_H 1
#elif defined(__arm__)
// ARM gcc defines open flags.
#define USE_FCNTL_H 1
#elif defined(ESP32)
#define USE_FCNTL_H 1
#else // defined(__AVR__)
#define USE_FCNTL_H 0
#endif // defined(__AVR__)
//------------------------------------------------------------------------------
/**
* If CHECK_FLASH_PROGRAMMING is zero, overlap of single sector flash
* programming and other operations will be allowed for faster write
* performance.
*
* Some cards will not sleep in low power mode unless CHECK_FLASH_PROGRAMMING
* is non-zero.
*/
#define CHECK_FLASH_PROGRAMMING 1
//------------------------------------------------------------------------------
/**
* Set MAINTAIN_FREE_CLUSTER_COUNT nonzero to keep the count of free clusters
* updated. This will increase the speed of the freeClusterCount() call
* after the first call. Extra flash will be required.
*/
#define MAINTAIN_FREE_CLUSTER_COUNT 0
//------------------------------------------------------------------------------
/**
* To enable SD card CRC checking set USE_SD_CRC nonzero.
*
* Set USE_SD_CRC to 1 to use a smaller CRC-CCITT function. This function
* is slower for AVR but may be fast for ARM and other processors.
*
* Set USE_SD_CRC to 2 to used a larger table driven CRC-CCITT function. This
* function is faster for AVR but may be slower for ARM and other processors.
*/
#define USE_SD_CRC 1
//------------------------------------------------------------------------------
/**
* Handle Watchdog Timer for WiFi modules.
*
* Yield will be called before accessing the SPI bus if it has been more
* than WDT_YIELD_TIME_MICROS microseconds since the last yield call by SdFat.
*/
#if defined(PLATFORM_ID) || defined(ESP8266)
// If Particle device or ESP8266 call yield.
#define WDT_YIELD_TIME_MICROS 100000
#else
#define WDT_YIELD_TIME_MICROS 0
#endif
//------------------------------------------------------------------------------
/**
* Set FAT12_SUPPORT nonzero to enable use of FAT12 volumes.
* FAT12 has not been well tested and requires additional flash.
*/
#define FAT12_SUPPORT 0
//------------------------------------------------------------------------------
/**
* Set DESTRUCTOR_CLOSES_FILE nonzero to close a file in its destructor.
*
* Causes use of lots of heap in ARM.
*/
#define DESTRUCTOR_CLOSES_FILE 1
//------------------------------------------------------------------------------
/**
* Call flush for endl if ENDL_CALLS_FLUSH is nonzero
*
* The standard for iostreams is to call flush. This is very costly for
* SdFat. Each call to flush causes 2048 bytes of I/O to the SD.
*
* SdFat has a single 512 byte buffer for SD I/O so it must write the current
* data block to the SD, read the directory block from the SD, update the
* directory entry, write the directory block to the SD and read the data
* block back into the buffer.
*
* The SD flash memory controller is not designed for this many rewrites
* so performance may be reduced by more than a factor of 100.
*
* If ENDL_CALLS_FLUSH is zero, you must call flush and/or close to force
* all data to be written to the SD.
*/
#define ENDL_CALLS_FLUSH 0
//------------------------------------------------------------------------------
/**
* Set USE_SEPARATE_FAT_CACHE nonzero to use a second 512 byte cache
* for FAT table entries. This improves performance for large writes
* that are not a multiple of 512 bytes.
*/
#ifdef __arm__
#define USE_SEPARATE_FAT_CACHE 1
#else // __arm__
#define USE_SEPARATE_FAT_CACHE 0
#endif // __arm__
//------------------------------------------------------------------------------
/**
* Set USE_MULTI_BLOCK_IO nonzero to use multi-block SD read/write.
*
* Don't use mult-block read/write on small AVR boards.
*/
#if defined(RAMEND) && RAMEND < 3000
#define USE_MULTI_BLOCK_IO 0
#else // RAMEND
#define USE_MULTI_BLOCK_IO 1
#endif // RAMEND
//-----------------------------------------------------------------------------
/** Enable SDIO driver if available. */
#define ENABLE_SDIO_CLASS 1
#define ENABLE_SDIOEX_CLASS 1
//------------------------------------------------------------------------------
/**
* Determine the default SPI configuration.
*/
#if defined(__STM32F1__) || defined(__STM32F4__) || defined(PLATFORM_ID)
// has multiple SPI ports
#define SD_HAS_CUSTOM_SPI 2
#elif defined(__AVR__)\
|| defined(__SAM3X8E__) || defined(__SAM3X8H__)\
|| (defined(__arm__) && defined(CORE_TEENSY))\
|| defined(ESP8266)
#define SD_HAS_CUSTOM_SPI 1
#else // SD_HAS_CUSTOM_SPI
// Use standard SPI library.
#define SD_HAS_CUSTOM_SPI 0
#endif // SD_HAS_CUSTOM_SPI
//------------------------------------------------------------------------------
/**
* Check if API to select HW SPI port is needed.
*/
#if USE_STANDARD_SPI_LIBRARY > 1 || SD_HAS_CUSTOM_SPI > 1
#define IMPLEMENT_SPI_PORT_SELECTION 1
#else // IMPLEMENT_SPI_PORT_SELECTION
#define IMPLEMENT_SPI_PORT_SELECTION 0
#endif // IMPLEMENT_SPI_PORT_SELECTION
#endif // SdFatConfig_h

View file

@ -0,0 +1,386 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* @file
* @brief Fast Digital Pin functions
*
* @defgroup digitalPin Fast Pin I/O
* @details Fast Digital I/O functions and template class.
* @{
*/
#ifndef DigitalPin_h
#define DigitalPin_h
#if defined(__AVR__) || defined(DOXYGEN)
#include <avr/io.h>
/** GpioPinMap type */
struct GpioPinMap_t {
volatile uint8_t* pin; /**< address of PIN for this pin */
volatile uint8_t* ddr; /**< address of DDR for this pin */
volatile uint8_t* port; /**< address of PORT for this pin */
uint8_t mask; /**< bit mask for this pin */
};
/** Initializer macro. */
#define GPIO_PIN(reg, bit) {&PIN##reg, &DDR##reg, &PORT##reg, 1 << bit}
// Include pin map for current board.
#include "boards/GpioPinMap.h"
//------------------------------------------------------------------------------
/** generate bad pin number error */
void badPinNumber(void)
__attribute__((error("Pin number is too large or not a constant")));
//------------------------------------------------------------------------------
/** Check for valid pin number
* @param[in] pin Number of pin to be checked.
*/
static inline __attribute__((always_inline))
void badPinCheck(uint8_t pin) {
if (!__builtin_constant_p(pin) || pin >= NUM_DIGITAL_PINS) {
badPinNumber();
}
}
//------------------------------------------------------------------------------
/** DDR register address
* @param[in] pin Arduino pin number
* @return register address
*/
static inline __attribute__((always_inline))
volatile uint8_t* ddrReg(uint8_t pin) {
badPinCheck(pin);
return GpioPinMap[pin].ddr;
}
//------------------------------------------------------------------------------
/** Bit mask for pin
* @param[in] pin Arduino pin number
* @return mask
*/
static inline __attribute__((always_inline))
uint8_t pinMask(uint8_t pin) {
badPinCheck(pin);
return GpioPinMap[pin].mask;
}
//------------------------------------------------------------------------------
/** PIN register address
* @param[in] pin Arduino pin number
* @return register address
*/
static inline __attribute__((always_inline))
volatile uint8_t* pinReg(uint8_t pin) {
badPinCheck(pin);
return GpioPinMap[pin].pin;
}
//------------------------------------------------------------------------------
/** PORT register address
* @param[in] pin Arduino pin number
* @return register address
*/
static inline __attribute__((always_inline))
volatile uint8_t* portReg(uint8_t pin) {
badPinCheck(pin);
return GpioPinMap[pin].port;
}
//------------------------------------------------------------------------------
/** Fast write helper.
* @param[in] address I/O register address
* @param[in] mask bit mask for pin
* @param[in] level value for bit
*/
static inline __attribute__((always_inline))
void fastBitWriteSafe(volatile uint8_t* address, uint8_t mask, bool level) {
uint8_t s;
if (address > reinterpret_cast<uint8_t*>(0X3F)) {
s = SREG;
cli();
}
if (level) {
*address |= mask;
} else {
*address &= ~mask;
}
if (address > reinterpret_cast<uint8_t*>(0X3F)) {
SREG = s;
}
}
//------------------------------------------------------------------------------
/** Read pin value.
* @param[in] pin Arduino pin number
* @return value read
*/
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin) {
return *pinReg(pin) & pinMask(pin);
}
//------------------------------------------------------------------------------
/** Toggle a pin.
* @param[in] pin Arduino pin number
*
* If the pin is in output mode toggle the pin level.
* If the pin is in input mode toggle the state of the 20K pullup.
*/
static inline __attribute__((always_inline))
void fastDigitalToggle(uint8_t pin) {
if (pinReg(pin) > reinterpret_cast<uint8_t*>(0X3F)) {
// must write bit to high address port
*pinReg(pin) = pinMask(pin);
} else {
// will compile to sbi and PIN register will not be read.
*pinReg(pin) |= pinMask(pin);
}
}
//------------------------------------------------------------------------------
/** Set pin value.
* @param[in] pin Arduino pin number
* @param[in] level value to write
*/
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool level) {
fastBitWriteSafe(portReg(pin), pinMask(pin), level);
}
//------------------------------------------------------------------------------
/** Write the DDR register.
* @param[in] pin Arduino pin number
* @param[in] level value to write
*/
static inline __attribute__((always_inline))
void fastDdrWrite(uint8_t pin, bool level) {
fastBitWriteSafe(ddrReg(pin), pinMask(pin), level);
}
//------------------------------------------------------------------------------
/** Set pin mode.
* @param[in] pin Arduino pin number
* @param[in] mode INPUT, OUTPUT, or INPUT_PULLUP.
*
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
* and disabled if the mode is INPUT.
*/
static inline __attribute__((always_inline))
void fastPinMode(uint8_t pin, uint8_t mode) {
fastDdrWrite(pin, mode == OUTPUT);
if (mode != OUTPUT) {
fastDigitalWrite(pin, mode == INPUT_PULLUP);
}
}
#else // defined(__AVR__)
#if defined(CORE_TEENSY)
//------------------------------------------------------------------------------
/** read pin value
* @param[in] pin Arduino pin number
* @return value read
*/
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin) {
return *portInputRegister(pin);
}
//------------------------------------------------------------------------------
/** Set pin value
* @param[in] pin Arduino pin number
* @param[in] level value to write
*/
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool value) {
if (value) {
*portSetRegister(pin) = 1;
} else {
*portClearRegister(pin) = 1;
}
}
#elif defined(__SAM3X8E__) || defined(__SAM3X8H__)
//------------------------------------------------------------------------------
/** read pin value
* @param[in] pin Arduino pin number
* @return value read
*/
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin) {
return g_APinDescription[pin].pPort->PIO_PDSR & g_APinDescription[pin].ulPin;
}
//------------------------------------------------------------------------------
/** Set pin value
* @param[in] pin Arduino pin number
* @param[in] level value to write
*/
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, bool value) {
if (value) {
g_APinDescription[pin].pPort->PIO_SODR = g_APinDescription[pin].ulPin;
} else {
g_APinDescription[pin].pPort->PIO_CODR = g_APinDescription[pin].ulPin;
}
}
#elif defined(ESP8266)
//------------------------------------------------------------------------------
/** Set pin value
* @param[in] pin Arduino pin number
* @param[in] val value to write
*/
static inline __attribute__((always_inline))
void fastDigitalWrite(uint8_t pin, uint8_t val) {
if (pin < 16) {
if (val) {
GPOS = (1 << pin);
} else {
GPOC = (1 << pin);
}
} else if (pin == 16) {
if (val) {
GP16O |= 1;
} else {
GP16O &= ~1;
}
}
}
//------------------------------------------------------------------------------
/** Read pin value
* @param[in] pin Arduino pin number
* @return value read
*/
static inline __attribute__((always_inline))
bool fastDigitalRead(uint8_t pin) {
if (pin < 16) {
return GPIP(pin);
} else if (pin == 16) {
return GP16I & 0x01;
}
return 0;
}
#else // CORE_TEENSY
//------------------------------------------------------------------------------
inline void fastDigitalWrite(uint8_t pin, bool value) {
digitalWrite(pin, value);
}
//------------------------------------------------------------------------------
inline bool fastDigitalRead(uint8_t pin) {
return digitalRead(pin);
}
#endif // CORE_TEENSY
//------------------------------------------------------------------------------
inline void fastDigitalToggle(uint8_t pin) {
fastDigitalWrite(pin, !fastDigitalRead(pin));
}
//------------------------------------------------------------------------------
inline void fastPinMode(uint8_t pin, uint8_t mode) {
pinMode(pin, mode);
}
#endif // __AVR__
//------------------------------------------------------------------------------
/** set pin configuration
* @param[in] pin Arduino pin number
* @param[in] mode mode INPUT or OUTPUT.
* @param[in] level If mode is output, set level high/low.
* If mode is input, enable or disable the pin's 20K pullup.
*/
#define fastPinConfig(pin, mode, level)\
{fastPinMode(pin, mode); fastDigitalWrite(pin, level);}
//==============================================================================
/**
* @class DigitalPin
* @brief Fast digital port I/O
*/
template<uint8_t PinNumber>
class DigitalPin {
public:
//----------------------------------------------------------------------------
/** Constructor */
DigitalPin() {}
//----------------------------------------------------------------------------
/** Asignment operator.
* @param[in] value If true set the pin's level high else set the
* pin's level low.
*
* @return This DigitalPin instance.
*/
inline DigitalPin & operator = (bool value) __attribute__((always_inline)) {
write(value);
return *this;
}
//----------------------------------------------------------------------------
/** Parenthesis operator.
* @return Pin's level
*/
inline operator bool () const __attribute__((always_inline)) {
return read();
}
//----------------------------------------------------------------------------
/** Set pin configuration.
* @param[in] mode: INPUT or OUTPUT.
* @param[in] level If mode is OUTPUT, set level high/low.
* If mode is INPUT, enable or disable the pin's 20K pullup.
*/
inline __attribute__((always_inline))
void config(uint8_t mode, bool level) {
fastPinConfig(PinNumber, mode, level);
}
//----------------------------------------------------------------------------
/**
* Set pin level high if output mode or enable 20K pullup if input mode.
*/
inline __attribute__((always_inline))
void high() {write(true);}
//----------------------------------------------------------------------------
/**
* Set pin level low if output mode or disable 20K pullup if input mode.
*/
inline __attribute__((always_inline))
void low() {write(false);}
//----------------------------------------------------------------------------
/**
* Set pin mode.
* @param[in] mode: INPUT, OUTPUT, or INPUT_PULLUP.
*
* The internal pullup resistors will be enabled if mode is INPUT_PULLUP
* and disabled if the mode is INPUT.
*/
inline __attribute__((always_inline))
void mode(uint8_t mode) {
fastPinMode(PinNumber, mode);
}
//----------------------------------------------------------------------------
/** @return Pin's level. */
inline __attribute__((always_inline))
bool read() const {
return fastDigitalRead(PinNumber);
}
//----------------------------------------------------------------------------
/** Toggle a pin.
*
* If the pin is in output mode toggle the pin's level.
* If the pin is in input mode toggle the state of the 20K pullup.
*/
inline __attribute__((always_inline))
void toggle() {
fastDigitalToggle(PinNumber);
}
//----------------------------------------------------------------------------
/** Write the pin's level.
* @param[in] value If true set the pin's level high else set the
* pin's level low.
*/
inline __attribute__((always_inline))
void write(bool value) {
fastDigitalWrite(PinNumber, value);
}
};
#endif // DigitalPin_h
/** @} */

View file

@ -0,0 +1,79 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SdSpiBaseDriver_h
#define SdSpiBaseDriver_h
/**
* \class SdSpiBaseDriver
* \brief SPI base driver.
*/
class SdSpiBaseDriver {
public:
/** Set SPI options for access to SD/SDHC cards.
*
*/
virtual void activate() = 0;
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
virtual void begin(uint8_t chipSelectPin) = 0;
/**
* End SPI transaction.
*/
virtual void deactivate() = 0;
/** Receive a byte.
*
* \return The byte.
*/
virtual uint8_t receive() = 0;
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
virtual uint8_t receive(uint8_t* buf, size_t n) = 0;
/** Send a byte.
*
* \param[in] data Byte to send
*/
virtual void send(uint8_t data) = 0;
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
virtual void send(const uint8_t* buf, size_t n) = 0;
/** Set CS low. */
virtual void select() = 0;
/** Save SPI settings.
* \param[in] spiSettings SPI speed, mode, and bit order.
*/
virtual void setSpiSettings(SPISettings spiSettings) = 0;
/** Set CS high. */
virtual void unselect() = 0;
};
#endif // SdSpiBaseDriver_h

View file

@ -0,0 +1,438 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* \file
* \brief SpiDriver classes
*/
#ifndef SdSpiDriver_h
#define SdSpiDriver_h
#include <Arduino.h>
#include "SPI.h"
#include "SdSpiBaseDriver.h"
#include "../SdFatConfig.h"
//------------------------------------------------------------------------------
/** SDCARD_SPI is defined if board has built-in SD card socket */
#ifndef SDCARD_SPI
#define SDCARD_SPI SPI
#endif // SDCARD_SPI
//------------------------------------------------------------------------------
/**
* \class SdSpiLibDriver
* \brief SdSpiLibDriver - use standard SPI library.
*/
#if ENABLE_SOFTWARE_SPI_CLASS
class SdSpiLibDriver : public SdSpiBaseDriver {
#else // ENABLE_SOFTWARE_SPI_CLASS
class SdSpiLibDriver {
#endif // ENABLE_SOFTWARE_SPI_CLASS
public:
#if IMPLEMENT_SPI_PORT_SELECTION
/** Activate SPI hardware. */
void activate() {
m_spi->beginTransaction(m_spiSettings);
}
/** Deactivate SPI hardware. */
void deactivate() {
m_spi->endTransaction();
}
/** Initialize the SPI bus.
*
* \param[in] csPin SD card chip select pin.
*/
void begin(uint8_t csPin) {
m_csPin = csPin;
digitalWrite(csPin, HIGH);
pinMode(csPin, OUTPUT);
m_spi->begin();
}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {
return m_spi->transfer( 0XFF);
}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = m_spi->transfer(0XFF);
}
return 0;
}
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {
m_spi->transfer(data);
}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void send(const uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
m_spi->transfer(buf[i]);
}
}
#else // IMPLEMENT_SPI_PORT_SELECTION
/** Activate SPI hardware. */
void activate() {
SDCARD_SPI.beginTransaction(m_spiSettings);
}
/** Deactivate SPI hardware. */
void deactivate() {
SDCARD_SPI.endTransaction();
}
/** Initialize the SPI bus.
*
* \param[in] csPin SD card chip select pin.
*/
void begin(uint8_t csPin) {
m_csPin = csPin;
digitalWrite(csPin, HIGH);
pinMode(csPin, OUTPUT);
SDCARD_SPI.begin();
}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {
return SDCARD_SPI.transfer( 0XFF);
}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = SDCARD_SPI.transfer(0XFF);
}
return 0;
}
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {
SDCARD_SPI.transfer(data);
}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void send(const uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
SDCARD_SPI.transfer(buf[i]);
}
}
#endif // IMPLEMENT_SPI_PORT_SELECTION
/** Set CS low. */
void select() {
digitalWrite(m_csPin, LOW);
}
/** Save SPISettings.
*
* \param[in] spiSettings SPI speed, mode, and byte order.
*/
void setSpiSettings(SPISettings spiSettings) {
m_spiSettings = spiSettings;
}
/** Set CS high. */
void unselect() {
digitalWrite(m_csPin, HIGH);
}
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
/** Set SPI port.
* \param[in] spiPort Hardware SPI port.
*/
void setPort(SPIClass* spiPort) {
m_spi = spiPort ? spiPort : &SDCARD_SPI;
}
private:
SPIClass* m_spi;
#else // IMPLEMENT_SPI_PORT_SELECTION
private:
#endif // IMPLEMENT_SPI_PORT_SELECTION
SPISettings m_spiSettings;
uint8_t m_csPin;
};
//------------------------------------------------------------------------------
/**
* \class SdSpiAltDriver
* \brief Optimized SPI class for access to SD and SDHC flash memory cards.
*/
#if ENABLE_SOFTWARE_SPI_CLASS
class SdSpiAltDriver : public SdSpiBaseDriver {
#else // ENABLE_SOFTWARE_SPI_CLASS
class SdSpiAltDriver {
#endif // ENABLE_SOFTWARE_SPI_CLASS
public:
/** Activate SPI hardware. */
void activate();
/** Deactivate SPI hardware. */
void deactivate();
/** Initialize the SPI bus.
*
* \param[in] csPin SD card chip select pin.
*/
void begin(uint8_t csPin);
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive();
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t receive(uint8_t* buf, size_t n);
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data);
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void send(const uint8_t* buf, size_t n);
/** Set CS low. */
void select() {
digitalWrite(m_csPin, LOW);
}
/** Save SPISettings.
*
* \param[in] spiSettings SPI speed, mode, and byte order.
*/
void setSpiSettings(SPISettings spiSettings) {
m_spiSettings = spiSettings;
}
/** Set CS high. */
void unselect() {
digitalWrite(m_csPin, HIGH);
}
#if IMPLEMENT_SPI_PORT_SELECTION || defined(DOXYGEN)
/** Set SPI port number.
* \param[in] spiPort Hardware SPI port.
*/
void setPort(SPIClass* spiPort) {
m_spi = spiPort ? spiPort : &SDCARD_SPI;
}
private:
SPIClass* m_spi;
#else // IMPLEMENT_SPI_PORT_SELECTION
private:
#endif // IMPLEMENT_SPI_PORT_SELECTION
SPISettings m_spiSettings;
uint8_t m_csPin;
};
//------------------------------------------------------------------------------
#if ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
#ifdef ARDUINO
#include "SoftSPI.h"
#elif defined(PLATFORM_ID) // Only defined if a Particle device
#include "SoftSPIParticle.h"
#endif // ARDUINO
/**
* \class SdSpiSoftDriver
* \brief Software SPI class for access to SD and SDHC flash memory cards.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin>
class SdSpiSoftDriver : public SdSpiBaseDriver {
public:
/** Dummy activate SPI hardware for software SPI */
void activate() {}
/** Dummy deactivate SPI hardware for software SPI */
void deactivate() {}
/** Initialize the SPI bus.
*
* \param[in] csPin SD card chip select pin.
*/
void begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
m_spi.begin();
}
/** Receive a byte.
*
* \return The byte.
*/
uint8_t receive() {
return m_spi.receive();
}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = receive();
}
return 0;
}
/** Send a byte.
*
* \param[in] data Byte to send
*/
void send(uint8_t data) {
m_spi.send(data);
}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
send(buf[i]);
}
}
/** Set CS low. */
void select() {
digitalWrite(m_csPin, LOW);
}
/** Save SPISettings.
*
* \param[in] spiSettings SPI speed, mode, and byte order.
*/
void setSpiSettings(SPISettings spiSettings) {
(void)spiSettings;
}
/** Set CS high. */
void unselect() {
digitalWrite(m_csPin, HIGH);
}
private:
uint8_t m_csPin;
SoftSPI<MisoPin, MosiPin, SckPin, 0> m_spi;
};
#endif // ENABLE_SOFTWARE_SPI_CLASS || defined(DOXYGEN)
//------------------------------------------------------------------------------
// Choose SPI driver for SdFat and SdFatEX classes.
#if USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
/** SdFat uses Arduino library SPI. */
typedef SdSpiLibDriver SdFatSpiDriver;
#else // USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
/** SdFat uses custom fast SPI. */
typedef SdSpiAltDriver SdFatSpiDriver;
#endif // USE_STANDARD_SPI_LIBRARY || !SD_HAS_CUSTOM_SPI
/** typedef for for SdSpiCard class. */
#if ENABLE_SOFTWARE_SPI_CLASS
// Need virtual driver.
typedef SdSpiBaseDriver SdSpiDriver;
#else // ENABLE_SOFTWARE_SPI_CLASS
// Don't need virtual driver.
typedef SdFatSpiDriver SdSpiDriver;
#endif // ENABLE_SOFTWARE_SPI_CLASS
//==============================================================================
// Use of in-line for AVR to save flash.
#ifdef __AVR__
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::deactivate() {
SPI.endTransaction();
}
//------------------------------------------------------------------------------
inline uint8_t SdSpiAltDriver::receive() {
SPDR = 0XFF;
while (!(SPSR & (1 << SPIF))) {}
return SPDR;
}
//------------------------------------------------------------------------------
inline uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
if (n-- == 0) {
return 0;
}
SPDR = 0XFF;
for (size_t i = 0; i < n; i++) {
while (!(SPSR & (1 << SPIF))) {}
uint8_t b = SPDR;
SPDR = 0XFF;
buf[i] = b;
}
while (!(SPSR & (1 << SPIF))) {}
buf[n] = SPDR;
return 0;
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::send(uint8_t data) {
SPDR = data;
while (!(SPSR & (1 << SPIF))) {}
}
//------------------------------------------------------------------------------
inline void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
if (n == 0) {
return;
}
SPDR = buf[0];
if (n > 1) {
uint8_t b = buf[1];
size_t i = 2;
while (1) {
while (!(SPSR & (1 << SPIF))) {}
SPDR = b;
if (i == n) {
break;
}
b = buf[i++];
}
}
while (!(SPSR & (1 << SPIF))) {}
}
#endif // __AVR__
#endif // SdSpiDriver_h

View file

@ -0,0 +1,104 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
#if defined(ESP8266)
#include "SdSpiDriver.h"
//------------------------------------------------------------------------------
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
}
//------------------------------------------------------------------------------
/** Set SPI options for access to SD/SDHC cards.
*
*/
void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::deactivate() {
// Note: endTransaction is an empty function on ESP8266.
SPI.endTransaction();
}
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpiAltDriver::receive() {
return SPI.transfer(0XFF);
}
//------------------------------------------------------------------------------
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
// Adjust to 32-bit alignment.
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && n) {
*buf++ = SPI.transfer(0xff);
n--;
}
// Do multiple of four byte transfers.
size_t n4 = 4*(n/4);
SPI.transferBytes(0, buf, n4);
// Transfer up to three remaining bytes.
for (buf += n4, n -= n4; n; n--) {
*buf++ = SPI.transfer(0xff);
}
return 0;
}
//------------------------------------------------------------------------------
/** Send a byte.
*
* \param[in] b Byte to send
*/
void SdSpiAltDriver::send(uint8_t b) {
SPI.transfer(b);
}
//------------------------------------------------------------------------------
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
// Adjust to 32-bit alignment.
while ((reinterpret_cast<uintptr_t>(buf) & 0X3) && n) {
SPI.transfer(*buf++);
n--;
}
SPI.transferBytes(const_cast<uint8_t*>(buf), 0, n);
}
#endif // defined(ESP8266)

View file

@ -0,0 +1,102 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
#if defined(PLATFORM_ID)
#include "SdSpiDriver.h"
static volatile bool SPI_DMA_TransferCompleted = false;
//-----------------------------------------------------------------------------
static void SD_SPI_DMA_TransferComplete_Callback(void) {
SPI_DMA_TransferCompleted = true;
}
//------------------------------------------------------------------------------
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
*/
void SdSpiAltDriver::activate() {
m_spi->beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
m_spi->begin();
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
}
//------------------------------------------------------------------------------
/**
* End SPI transaction.
*/
void SdSpiAltDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpiAltDriver::receive() {
return m_spi->transfer(0XFF);
}
//------------------------------------------------------------------------------
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
SPI_DMA_TransferCompleted = false;
m_spi->transfer(nullptr, buf, n, SD_SPI_DMA_TransferComplete_Callback);
while (!SPI_DMA_TransferCompleted) {}
return 0;
}
//------------------------------------------------------------------------------
/** Send a byte.
*
* \param[in] b Byte to send
*/
void SdSpiAltDriver::send(uint8_t b) {
m_spi->transfer(b);
}
//------------------------------------------------------------------------------
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
SPI_DMA_TransferCompleted = false;
m_spi->transfer(const_cast<uint8_t*>(buf), nullptr, n,
SD_SPI_DMA_TransferComplete_Callback);
while (!SPI_DMA_TransferCompleted) {}
}
#endif // defined(PLATFORM_ID)

View file

@ -0,0 +1,218 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SdSpiDriver.h"
#if defined(__SAM3X8E__) || defined(__SAM3X8H__)
/** Use SAM3X DMAC if nonzero */
#define USE_SAM3X_DMAC 1
/** Use extra Bus Matrix arbitration fix if nonzero */
#define USE_SAM3X_BUS_MATRIX_FIX 0
/** Time in ms for DMA receive timeout */
#define SAM3X_DMA_TIMEOUT 100
/** chip select register number */
#define SPI_CHIP_SEL 3
/** DMAC receive channel */
#define SPI_DMAC_RX_CH 1
/** DMAC transmit channel */
#define SPI_DMAC_TX_CH 0
/** DMAC Channel HW Interface Number for SPI TX. */
#define SPI_TX_IDX 1
/** DMAC Channel HW Interface Number for SPI RX. */
#define SPI_RX_IDX 2
//------------------------------------------------------------------------------
/** Disable DMA Controller. */
static void dmac_disable() {
DMAC->DMAC_EN &= (~DMAC_EN_ENABLE);
}
/** Enable DMA Controller. */
static void dmac_enable() {
DMAC->DMAC_EN = DMAC_EN_ENABLE;
}
/** Disable DMA Channel. */
static void dmac_channel_disable(uint32_t ul_num) {
DMAC->DMAC_CHDR = DMAC_CHDR_DIS0 << ul_num;
}
/** Enable DMA Channel. */
static void dmac_channel_enable(uint32_t ul_num) {
DMAC->DMAC_CHER = DMAC_CHER_ENA0 << ul_num;
}
/** Poll for transfer complete. */
static bool dmac_channel_transfer_done(uint32_t ul_num) {
return (DMAC->DMAC_CHSR & (DMAC_CHSR_ENA0 << ul_num)) ? false : true;
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
#if USE_SAM3X_DMAC
pmc_enable_periph_clk(ID_DMAC);
dmac_disable();
DMAC->DMAC_GCFG = DMAC_GCFG_ARB_CFG_FIXED;
dmac_enable();
#if USE_SAM3X_BUS_MATRIX_FIX
MATRIX->MATRIX_WPMR = 0x4d415400;
MATRIX->MATRIX_MCFG[1] = 1;
MATRIX->MATRIX_MCFG[2] = 1;
MATRIX->MATRIX_SCFG[0] = 0x01000010;
MATRIX->MATRIX_SCFG[1] = 0x01000010;
MATRIX->MATRIX_SCFG[7] = 0x01000010;
#endif // USE_SAM3X_BUS_MATRIX_FIX
#endif // USE_SAM3X_DMAC
}
//------------------------------------------------------------------------------
// start RX DMA
static void spiDmaRX(uint8_t* dst, uint16_t count) {
dmac_channel_disable(SPI_DMAC_RX_CH);
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_SADDR = (uint32_t)&SPI0->SPI_RDR;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DADDR = (uint32_t)dst;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_DSCR = 0;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLA = count |
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_PER2MEM_DMA_FC |
DMAC_CTRLB_SRC_INCR_FIXED | DMAC_CTRLB_DST_INCR_INCREMENTING;
DMAC->DMAC_CH_NUM[SPI_DMAC_RX_CH].DMAC_CFG = DMAC_CFG_SRC_PER(SPI_RX_IDX) |
DMAC_CFG_SRC_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ASAP_CFG;
dmac_channel_enable(SPI_DMAC_RX_CH);
}
//------------------------------------------------------------------------------
// start TX DMA
static void spiDmaTX(const uint8_t* src, uint16_t count) {
static uint8_t ff = 0XFF;
uint32_t src_incr = DMAC_CTRLB_SRC_INCR_INCREMENTING;
if (!src) {
src = &ff;
src_incr = DMAC_CTRLB_SRC_INCR_FIXED;
}
dmac_channel_disable(SPI_DMAC_TX_CH);
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_SADDR = (uint32_t)src;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DADDR = (uint32_t)&SPI0->SPI_TDR;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_DSCR = 0;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLA = count |
DMAC_CTRLA_SRC_WIDTH_BYTE | DMAC_CTRLA_DST_WIDTH_BYTE;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CTRLB = DMAC_CTRLB_SRC_DSCR |
DMAC_CTRLB_DST_DSCR | DMAC_CTRLB_FC_MEM2PER_DMA_FC |
src_incr | DMAC_CTRLB_DST_INCR_FIXED;
DMAC->DMAC_CH_NUM[SPI_DMAC_TX_CH].DMAC_CFG = DMAC_CFG_DST_PER(SPI_TX_IDX) |
DMAC_CFG_DST_H2SEL | DMAC_CFG_SOD | DMAC_CFG_FIFOCFG_ALAP_CFG;
dmac_channel_enable(SPI_DMAC_TX_CH);
}
//------------------------------------------------------------------------------
// initialize SPI controller
void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
Spi* pSpi = SPI0;
// Save the divisor
uint32_t scbr = pSpi->SPI_CSR[SPI_CHIP_SEL] & 0XFF00;
// Disable SPI
pSpi->SPI_CR = SPI_CR_SPIDIS;
// reset SPI
pSpi->SPI_CR = SPI_CR_SWRST;
// no mode fault detection, set master mode
pSpi->SPI_MR = SPI_PCS(SPI_CHIP_SEL) | SPI_MR_MODFDIS | SPI_MR_MSTR;
// mode 0, 8-bit,
pSpi->SPI_CSR[SPI_CHIP_SEL] = scbr | SPI_CSR_CSAAT | SPI_CSR_NCPHA;
// enable SPI
pSpi->SPI_CR |= SPI_CR_SPIEN;
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::deactivate() {
SPI.endTransaction();
}
//------------------------------------------------------------------------------
static inline uint8_t spiTransfer(uint8_t b) {
Spi* pSpi = SPI0;
pSpi->SPI_TDR = b;
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
b = pSpi->SPI_RDR;
return b;
}
//------------------------------------------------------------------------------
/** SPI receive a byte */
uint8_t SdSpiAltDriver::receive() {
return spiTransfer(0XFF);
}
//------------------------------------------------------------------------------
/** SPI receive multiple bytes */
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
Spi* pSpi = SPI0;
int rtn = 0;
#if USE_SAM3X_DMAC
// clear overrun error
pSpi->SPI_SR;
spiDmaRX(buf, n);
spiDmaTX(0, n);
uint32_t m = millis();
while (!dmac_channel_transfer_done(SPI_DMAC_RX_CH)) {
if ((millis() - m) > SAM3X_DMA_TIMEOUT) {
dmac_channel_disable(SPI_DMAC_RX_CH);
dmac_channel_disable(SPI_DMAC_TX_CH);
rtn = 2;
break;
}
}
if (pSpi->SPI_SR & SPI_SR_OVRES) {
rtn |= 1;
}
#else // USE_SAM3X_DMAC
for (size_t i = 0; i < n; i++) {
pSpi->SPI_TDR = 0XFF;
while ((pSpi->SPI_SR & SPI_SR_RDRF) == 0) {}
buf[i] = pSpi->SPI_RDR;
}
#endif // USE_SAM3X_DMAC
return rtn;
}
//------------------------------------------------------------------------------
/** SPI send a byte */
void SdSpiAltDriver::send(uint8_t b) {
spiTransfer(b);
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
Spi* pSpi = SPI0;
#if USE_SAM3X_DMAC
spiDmaTX(buf, n);
while (!dmac_channel_transfer_done(SPI_DMAC_TX_CH)) {}
#else // #if USE_SAM3X_DMAC
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
for (size_t i = 0; i < n; i++) {
pSpi->SPI_TDR = buf[i];
while ((pSpi->SPI_SR & SPI_SR_TDRE) == 0) {}
}
#endif // #if USE_SAM3X_DMAC
while ((pSpi->SPI_SR & SPI_SR_TXEMPTY) == 0) {}
// leave RDR empty
pSpi->SPI_RDR;
}
#endif // defined(__SAM3X8E__) || defined(__SAM3X8H__)

View file

@ -0,0 +1,105 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
#if defined(__STM32F1__) || defined(__STM32F4__)
#include "SdSpiDriver.h"
#if defined(__STM32F1__)
#define USE_STM32_DMA 1
#elif defined(__STM32F4__)
#define USE_STM32_DMA 1
#else // defined(__STM32F1__)
#error Unknown STM32 type
#endif // defined(__STM32F1__)
//------------------------------------------------------------------------------
/** Set SPI options for access to SD/SDHC cards.
*
* \param[in] divisor SCK clock divider relative to the APB1 or APB2 clock.
*/
void SdSpiAltDriver::activate() {
m_spi->beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
/** Initialize the SPI bus.
*
* \param[in] chipSelectPin SD card chip select pin.
*/
void SdSpiAltDriver::begin(uint8_t csPin) {
m_csPin = csPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
m_spi->begin();
}
//------------------------------------------------------------------------------
/**
* End SPI transaction.
*/
void SdSpiAltDriver::deactivate() {
m_spi->endTransaction();
}
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpiAltDriver::receive() {
return m_spi->transfer(0XFF);
}
//------------------------------------------------------------------------------
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
#if USE_STM32_DMA
return m_spi->dmaTransfer(nullptr, buf, n);
#else // USE_STM32_DMA
m_spi->read(buf, n);
return 0;
#endif // USE_STM32_DMA
}
//------------------------------------------------------------------------------
/** Send a byte.
*
* \param[in] b Byte to send
*/
void SdSpiAltDriver::send(uint8_t b) {
m_spi->transfer(b);
}
//------------------------------------------------------------------------------
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
#if USE_STM32_DMA
m_spi->dmaTransfer(const_cast<uint8*>(buf), nullptr, n);
#else // USE_STM32_DMA
m_spi->write(const_cast<uint8*>(buf), n);
#endif // USE_STM32_DMA
}
#endif // defined(__STM32F1__) || defined(__STM32F4__)

View file

@ -0,0 +1,233 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#include "SdSpiDriver.h"
#if defined(__arm__) && defined(CORE_TEENSY)
// SPI definitions
// #include "kinetis.h"
//------------------------------------------------------------------------------
void SdSpiAltDriver::activate() {
SPI.beginTransaction(m_spiSettings);
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::begin(uint8_t chipSelectPin) {
m_csPin = chipSelectPin;
pinMode(m_csPin, OUTPUT);
digitalWrite(m_csPin, HIGH);
SPI.begin();
}
//------------------------------------------------------------------------------
void SdSpiAltDriver::deactivate() {
SPI.endTransaction();
}
//==============================================================================
#ifdef KINETISK
// use 16-bit frame if SPI_USE_8BIT_FRAME is zero
#define SPI_USE_8BIT_FRAME 0
// Limit initial fifo to three entries to avoid fifo overrun
#define SPI_INITIAL_FIFO_DEPTH 3
// define some symbols that are not in mk20dx128.h
#ifndef SPI_SR_RXCTR
#define SPI_SR_RXCTR 0XF0
#endif // SPI_SR_RXCTR
#ifndef SPI_PUSHR_CONT
#define SPI_PUSHR_CONT 0X80000000
#endif // SPI_PUSHR_CONT
#ifndef SPI_PUSHR_CTAS
#define SPI_PUSHR_CTAS(n) (((n) & 7) << 28)
#endif // SPI_PUSHR_CTAS
//------------------------------------------------------------------------------
/** SPI receive a byte */
uint8_t SdSpiAltDriver::receive() {
SPI0_MCR |= SPI_MCR_CLR_RXF;
SPI0_SR = SPI_SR_TCF;
SPI0_PUSHR = 0xFF;
while (!(SPI0_SR & SPI_SR_TCF)) {}
return SPI0_POPR;
}
//------------------------------------------------------------------------------
/** SPI receive multiple bytes */
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
#if SPI_USE_8BIT_FRAME
// initial number of bytes to push into TX FIFO
int nf = n < SPI_INITIAL_FIFO_DEPTH ? n : SPI_INITIAL_FIFO_DEPTH;
for (int i = 0; i < nf; i++) {
SPI0_PUSHR = 0XFF;
}
// limit for pushing dummy data into TX FIFO
uint8_t* limit = buf + n - nf;
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = 0XFF;
*buf++ = SPI0_POPR;
}
// limit for rest of RX data
limit += nf;
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
*buf++ = SPI0_POPR;
}
#else // SPI_USE_8BIT_FRAME
// use 16 bit frame to avoid TD delay between frames
// get one byte if n is odd
if (n & 1) {
*buf++ = receive();
n--;
}
// initial number of words to push into TX FIFO
int nf = n/2 < SPI_INITIAL_FIFO_DEPTH ? n/2 : SPI_INITIAL_FIFO_DEPTH;
for (int i = 0; i < nf; i++) {
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
}
uint8_t* limit = buf + n - 2*nf;
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | 0XFFFF;
uint16_t w = SPI0_POPR;
*buf++ = w >> 8;
*buf++ = w & 0XFF;
}
// limit for rest of RX data
limit += 2*nf;
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
uint16_t w = SPI0_POPR;
*buf++ = w >> 8;
*buf++ = w & 0XFF;
}
#endif // SPI_USE_8BIT_FRAME
return 0;
}
//------------------------------------------------------------------------------
/** SPI send a byte */
void SdSpiAltDriver::send(uint8_t b) {
SPI0_MCR |= SPI_MCR_CLR_RXF;
SPI0_SR = SPI_SR_TCF;
SPI0_PUSHR = b;
while (!(SPI0_SR & SPI_SR_TCF)) {}
}
//------------------------------------------------------------------------------
/** SPI send multiple bytes */
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
// clear any data in RX FIFO
SPI0_MCR = SPI_MCR_MSTR | SPI_MCR_CLR_RXF | SPI_MCR_PCSIS(0x1F);
#if SPI_USE_8BIT_FRAME
// initial number of bytes to push into TX FIFO
int nf = n < SPI_INITIAL_FIFO_DEPTH ? n : SPI_INITIAL_FIFO_DEPTH;
// limit for pushing data into TX fifo
const uint8_t* limit = buf + n;
for (int i = 0; i < nf; i++) {
SPI0_PUSHR = *buf++;
}
// write data to TX FIFO
while (buf < limit) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = *buf++;
SPI0_POPR;
}
// wait for data to be sent
while (nf) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_POPR;
nf--;
}
#else // SPI_USE_8BIT_FRAME
// use 16 bit frame to avoid TD delay between frames
// send one byte if n is odd
if (n & 1) {
send(*buf++);
n--;
}
// initial number of words to push into TX FIFO
int nf = n/2 < SPI_INITIAL_FIFO_DEPTH ? n/2 : SPI_INITIAL_FIFO_DEPTH;
// limit for pushing data into TX fifo
const uint8_t* limit = buf + n;
for (int i = 0; i < nf; i++) {
uint16_t w = (*buf++) << 8;
w |= *buf++;
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
}
// write data to TX FIFO
while (buf < limit) {
uint16_t w = *buf++ << 8;
w |= *buf++;
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_PUSHR = SPI_PUSHR_CONT | SPI_PUSHR_CTAS(1) | w;
SPI0_POPR;
}
// wait for data to be sent
while (nf) {
while (!(SPI0_SR & SPI_SR_RXCTR)) {}
SPI0_POPR;
nf--;
}
#endif // SPI_USE_8BIT_FRAME
}
#else // KINETISK
//==============================================================================
// Use standard SPI library if not KINETISK
//------------------------------------------------------------------------------
/** Receive a byte.
*
* \return The byte.
*/
uint8_t SdSpiAltDriver::receive() {
return SPI.transfer(0XFF);
}
/** Receive multiple bytes.
*
* \param[out] buf Buffer to receive the data.
* \param[in] n Number of bytes to receive.
*
* \return Zero for no error or nonzero error code.
*/
uint8_t SdSpiAltDriver::receive(uint8_t* buf, size_t n) {
for (size_t i = 0; i < n; i++) {
buf[i] = SPI.transfer(0XFF);
}
return 0;
}
/** Send a byte.
*
* \param[in] b Byte to send
*/
void SdSpiAltDriver::send(uint8_t b) {
SPI.transfer(b);
}
/** Send multiple bytes.
*
* \param[in] buf Buffer for data to be sent.
* \param[in] n Number of bytes to send.
*/
void SdSpiAltDriver::send(const uint8_t* buf , size_t n) {
for (size_t i = 0; i < n; i++) {
SPI.transfer(buf[i]);
}
}
#endif // KINETISK
#endif // defined(__arm__) && defined(CORE_TEENSY)

View file

@ -0,0 +1,167 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* 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.
*/
/**
* @file
* @brief Software SPI.
*
* @defgroup softSPI Software SPI
* @details Software SPI Template Class.
* @{
*/
#ifndef SoftSPI_h
#define SoftSPI_h
#include "DigitalPin.h"
//------------------------------------------------------------------------------
/** Nop for timing. */
#define nop asm volatile ("nop\n\t")
//------------------------------------------------------------------------------
/** Pin Mode for MISO is input.*/
#define MISO_MODE INPUT
/** Pullups disabled for MISO are disabled. */
#define MISO_LEVEL false
/** Pin Mode for MOSI is output.*/
#define MOSI_MODE OUTPUT
/** Pin Mode for SCK is output. */
#define SCK_MODE OUTPUT
//------------------------------------------------------------------------------
/**
* @class SoftSPI
* @brief Fast software SPI.
*/
template<uint8_t MisoPin, uint8_t MosiPin, uint8_t SckPin, uint8_t Mode = 0>
class SoftSPI {
public:
//----------------------------------------------------------------------------
/** Initialize SoftSPI pins. */
void begin() {
fastPinConfig(MisoPin, MISO_MODE, MISO_LEVEL);
fastPinConfig(MosiPin, MOSI_MODE, !MODE_CPHA(Mode));
fastPinConfig(SckPin, SCK_MODE, MODE_CPOL(Mode));
}
//----------------------------------------------------------------------------
/** Soft SPI receive byte.
* @return Data byte received.
*/
inline __attribute__((always_inline))
uint8_t receive() {
uint8_t data = 0;
receiveBit(7, &data);
receiveBit(6, &data);
receiveBit(5, &data);
receiveBit(4, &data);
receiveBit(3, &data);
receiveBit(2, &data);
receiveBit(1, &data);
receiveBit(0, &data);
return data;
}
//----------------------------------------------------------------------------
/** Soft SPI send byte.
* @param[in] data Data byte to send.
*/
inline __attribute__((always_inline))
void send(uint8_t data) {
sendBit(7, data);
sendBit(6, data);
sendBit(5, data);
sendBit(4, data);
sendBit(3, data);
sendBit(2, data);
sendBit(1, data);
sendBit(0, data);
}
//----------------------------------------------------------------------------
/** Soft SPI transfer byte.
* @param[in] txData Data byte to send.
* @return Data byte received.
*/
inline __attribute__((always_inline))
uint8_t transfer(uint8_t txData) {
uint8_t rxData = 0;
transferBit(7, &rxData, txData);
transferBit(6, &rxData, txData);
transferBit(5, &rxData, txData);
transferBit(4, &rxData, txData);
transferBit(3, &rxData, txData);
transferBit(2, &rxData, txData);
transferBit(1, &rxData, txData);
transferBit(0, &rxData, txData);
return rxData;
}
private:
//----------------------------------------------------------------------------
inline __attribute__((always_inline))
bool MODE_CPHA(uint8_t mode) {return (mode & 1) != 0;}
inline __attribute__((always_inline))
bool MODE_CPOL(uint8_t mode) {return (mode & 2) != 0;}
inline __attribute__((always_inline))
void receiveBit(uint8_t bit, uint8_t* data) {
if (MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
}
nop;
nop;
fastDigitalWrite(SckPin,
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
if (fastDigitalRead(MisoPin)) *data |= 1 << bit;
if (!MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
}
}
//----------------------------------------------------------------------------
inline __attribute__((always_inline))
void sendBit(uint8_t bit, uint8_t data) {
if (MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
}
fastDigitalWrite(MosiPin, data & (1 << bit));
fastDigitalWrite(SckPin,
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
nop;
nop;
if (!MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
}
}
//----------------------------------------------------------------------------
inline __attribute__((always_inline))
void transferBit(uint8_t bit, uint8_t* rxData, uint8_t txData) {
if (MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, !MODE_CPOL(Mode));
}
fastDigitalWrite(MosiPin, txData & (1 << bit));
fastDigitalWrite(SckPin,
MODE_CPHA(Mode) ? MODE_CPOL(Mode) : !MODE_CPOL(Mode));
if (fastDigitalRead(MisoPin)) *rxData |= 1 << bit;
if (!MODE_CPHA(Mode)) {
fastDigitalWrite(SckPin, MODE_CPOL(Mode));
}
}
//----------------------------------------------------------------------------
};
#endif // SoftSPI_h
/** @} */

View file

@ -0,0 +1,37 @@
#ifndef AvrDevelopersGpioPinMap_h
#define AvrDevelopersGpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(B, 0), // D0
GPIO_PIN(B, 1), // D1
GPIO_PIN(B, 2), // D2
GPIO_PIN(B, 3), // D3
GPIO_PIN(B, 4), // D4
GPIO_PIN(B, 5), // D5
GPIO_PIN(B, 6), // D6
GPIO_PIN(B, 7), // D7
GPIO_PIN(D, 0), // D8
GPIO_PIN(D, 1), // D9
GPIO_PIN(D, 2), // D10
GPIO_PIN(D, 3), // D11
GPIO_PIN(D, 4), // D12
GPIO_PIN(D, 5), // D13
GPIO_PIN(D, 6), // D14
GPIO_PIN(D, 7), // D15
GPIO_PIN(C, 0), // D16
GPIO_PIN(C, 1), // D17
GPIO_PIN(C, 2), // D18
GPIO_PIN(C, 3), // D19
GPIO_PIN(C, 4), // D20
GPIO_PIN(C, 5), // D21
GPIO_PIN(C, 6), // D22
GPIO_PIN(C, 7), // D23
GPIO_PIN(A, 7), // D24
GPIO_PIN(A, 6), // D25
GPIO_PIN(A, 5), // D26
GPIO_PIN(A, 4), // D27
GPIO_PIN(A, 3), // D28
GPIO_PIN(A, 2), // D29
GPIO_PIN(A, 1), // D30
GPIO_PIN(A, 0) // D31
};
#endif // AvrDevelopersGpioPinMap_h

View file

@ -0,0 +1,37 @@
#ifndef BobuinoGpioPinMap_h
#define BobuinoGpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(B, 0), // D0
GPIO_PIN(B, 1), // D1
GPIO_PIN(B, 2), // D2
GPIO_PIN(B, 3), // D3
GPIO_PIN(B, 4), // D4
GPIO_PIN(B, 5), // D5
GPIO_PIN(B, 6), // D6
GPIO_PIN(B, 7), // D7
GPIO_PIN(D, 0), // D8
GPIO_PIN(D, 1), // D9
GPIO_PIN(D, 2), // D10
GPIO_PIN(D, 3), // D11
GPIO_PIN(D, 4), // D12
GPIO_PIN(D, 5), // D13
GPIO_PIN(D, 6), // D14
GPIO_PIN(D, 7), // D15
GPIO_PIN(C, 0), // D16
GPIO_PIN(C, 1), // D17
GPIO_PIN(C, 2), // D18
GPIO_PIN(C, 3), // D19
GPIO_PIN(C, 4), // D20
GPIO_PIN(C, 5), // D21
GPIO_PIN(C, 6), // D22
GPIO_PIN(C, 7), // D23
GPIO_PIN(A, 0), // D24
GPIO_PIN(A, 1), // D25
GPIO_PIN(A, 2), // D26
GPIO_PIN(A, 3), // D27
GPIO_PIN(A, 4), // D28
GPIO_PIN(A, 5), // D29
GPIO_PIN(A, 6), // D30
GPIO_PIN(A, 7) // D31
};
#endif // BobuinoGpioPinMap_h

View file

@ -0,0 +1,45 @@
#ifndef GpioPinMap_h
#define GpioPinMap_h
#if defined(__AVR_ATmega168__)\
||defined(__AVR_ATmega168P__)\
||defined(__AVR_ATmega328P__)
// 168 and 328 Arduinos
#include "UnoGpioPinMap.h"
#elif defined(__AVR_ATmega1280__)\
|| defined(__AVR_ATmega2560__)
// Mega ADK
#include "MegaGpioPinMap.h"
#elif defined(__AVR_ATmega32U4__)
#ifdef CORE_TEENSY
#include "Teensy2GpioPinMap.h"
#else // CORE_TEENSY
// Leonardo or Yun
#include "LeonardoGpioPinMap.h"
#endif // CORE_TEENSY
#elif defined(__AVR_AT90USB646__)\
|| defined(__AVR_AT90USB1286__)
// Teensy++ 1.0 & 2.0
#include "Teensy2ppGpioPinMap.h"
#elif defined(__AVR_ATmega1284P__)\
|| defined(__AVR_ATmega1284__)\
|| defined(__AVR_ATmega644P__)\
|| defined(__AVR_ATmega644__)\
|| defined(__AVR_ATmega64__)\
|| defined(__AVR_ATmega32__)\
|| defined(__AVR_ATmega324__)\
|| defined(__AVR_ATmega16__)
#ifdef ARDUINO_1284P_AVR_DEVELOPERS
#include "AvrDevelopersGpioPinMap.h"
#elif defined(BOBUINO_PINOUT) || defined(ARDUINO_1284P_BOBUINO)
#include "BobuinoGpioPinMap.h"
#elif defined(ARDUINO_1284P_SLEEPINGBEAUTY)
#include "SleepingBeautyGpioPinMap.h"
#elif defined(STANDARD_PINOUT) || defined(ARDUINO_1284P_STANDARD)
#include "Standard1284GpioPinMap.h"
#else // ARDUINO_1284P_AVR_DEVELOPERS
#error Undefined variant 1284, 644, 324
#endif // ARDUINO_1284P_AVR_DEVELOPERS
#else // 1284P, 1284, 644
#error Unknown board type.
#endif // end all boards
#endif // GpioPinMap_h

View file

@ -0,0 +1,35 @@
#ifndef LeonardoGpioPinMap_h
#define LeonardoGpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(D, 2), // D0
GPIO_PIN(D, 3), // D1
GPIO_PIN(D, 1), // D2
GPIO_PIN(D, 0), // D3
GPIO_PIN(D, 4), // D4
GPIO_PIN(C, 6), // D5
GPIO_PIN(D, 7), // D6
GPIO_PIN(E, 6), // D7
GPIO_PIN(B, 4), // D8
GPIO_PIN(B, 5), // D9
GPIO_PIN(B, 6), // D10
GPIO_PIN(B, 7), // D11
GPIO_PIN(D, 6), // D12
GPIO_PIN(C, 7), // D13
GPIO_PIN(B, 3), // D14
GPIO_PIN(B, 1), // D15
GPIO_PIN(B, 2), // D16
GPIO_PIN(B, 0), // D17
GPIO_PIN(F, 7), // D18
GPIO_PIN(F, 6), // D19
GPIO_PIN(F, 5), // D20
GPIO_PIN(F, 4), // D21
GPIO_PIN(F, 1), // D22
GPIO_PIN(F, 0), // D23
GPIO_PIN(D, 4), // D24
GPIO_PIN(D, 7), // D25
GPIO_PIN(B, 4), // D26
GPIO_PIN(B, 5), // D27
GPIO_PIN(B, 6), // D28
GPIO_PIN(D, 6) // D29
};
#endif // LeonardoGpioPinMap_h

View file

@ -0,0 +1,75 @@
#ifndef MegaGpioPinMap_h
#define MegaGpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(E, 0), // D0
GPIO_PIN(E, 1), // D1
GPIO_PIN(E, 4), // D2
GPIO_PIN(E, 5), // D3
GPIO_PIN(G, 5), // D4
GPIO_PIN(E, 3), // D5
GPIO_PIN(H, 3), // D6
GPIO_PIN(H, 4), // D7
GPIO_PIN(H, 5), // D8
GPIO_PIN(H, 6), // D9
GPIO_PIN(B, 4), // D10
GPIO_PIN(B, 5), // D11
GPIO_PIN(B, 6), // D12
GPIO_PIN(B, 7), // D13
GPIO_PIN(J, 1), // D14
GPIO_PIN(J, 0), // D15
GPIO_PIN(H, 1), // D16
GPIO_PIN(H, 0), // D17
GPIO_PIN(D, 3), // D18
GPIO_PIN(D, 2), // D19
GPIO_PIN(D, 1), // D20
GPIO_PIN(D, 0), // D21
GPIO_PIN(A, 0), // D22
GPIO_PIN(A, 1), // D23
GPIO_PIN(A, 2), // D24
GPIO_PIN(A, 3), // D25
GPIO_PIN(A, 4), // D26
GPIO_PIN(A, 5), // D27
GPIO_PIN(A, 6), // D28
GPIO_PIN(A, 7), // D29
GPIO_PIN(C, 7), // D30
GPIO_PIN(C, 6), // D31
GPIO_PIN(C, 5), // D32
GPIO_PIN(C, 4), // D33
GPIO_PIN(C, 3), // D34
GPIO_PIN(C, 2), // D35
GPIO_PIN(C, 1), // D36
GPIO_PIN(C, 0), // D37
GPIO_PIN(D, 7), // D38
GPIO_PIN(G, 2), // D39
GPIO_PIN(G, 1), // D40
GPIO_PIN(G, 0), // D41
GPIO_PIN(L, 7), // D42
GPIO_PIN(L, 6), // D43
GPIO_PIN(L, 5), // D44
GPIO_PIN(L, 4), // D45
GPIO_PIN(L, 3), // D46
GPIO_PIN(L, 2), // D47
GPIO_PIN(L, 1), // D48
GPIO_PIN(L, 0), // D49
GPIO_PIN(B, 3), // D50
GPIO_PIN(B, 2), // D51
GPIO_PIN(B, 1), // D52
GPIO_PIN(B, 0), // D53
GPIO_PIN(F, 0), // D54
GPIO_PIN(F, 1), // D55
GPIO_PIN(F, 2), // D56
GPIO_PIN(F, 3), // D57
GPIO_PIN(F, 4), // D58
GPIO_PIN(F, 5), // D59
GPIO_PIN(F, 6), // D60
GPIO_PIN(F, 7), // D61
GPIO_PIN(K, 0), // D62
GPIO_PIN(K, 1), // D63
GPIO_PIN(K, 2), // D64
GPIO_PIN(K, 3), // D65
GPIO_PIN(K, 4), // D66
GPIO_PIN(K, 5), // D67
GPIO_PIN(K, 6), // D68
GPIO_PIN(K, 7) // D69
};
#endif // MegaGpioPinMap_h

View file

@ -0,0 +1,37 @@
#ifndef SleepingBeautyGpioPinMap_h
#define SleepingBeautyGpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(D, 0), // D0
GPIO_PIN(D, 1), // D1
GPIO_PIN(D, 2), // D2
GPIO_PIN(D, 3), // D3
GPIO_PIN(B, 0), // D4
GPIO_PIN(B, 1), // D5
GPIO_PIN(B, 2), // D6
GPIO_PIN(B, 3), // D7
GPIO_PIN(D, 6), // D8
GPIO_PIN(D, 5), // D9
GPIO_PIN(B, 4), // D10
GPIO_PIN(B, 5), // D11
GPIO_PIN(B, 6), // D12
GPIO_PIN(B, 7), // D13
GPIO_PIN(C, 7), // D14
GPIO_PIN(C, 6), // D15
GPIO_PIN(A, 5), // D16
GPIO_PIN(A, 4), // D17
GPIO_PIN(A, 3), // D18
GPIO_PIN(A, 2), // D19
GPIO_PIN(A, 1), // D20
GPIO_PIN(A, 0), // D21
GPIO_PIN(D, 4), // D22
GPIO_PIN(D, 7), // D23
GPIO_PIN(C, 2), // D24
GPIO_PIN(C, 3), // D25
GPIO_PIN(C, 4), // D26
GPIO_PIN(C, 5), // D27
GPIO_PIN(C, 1), // D28
GPIO_PIN(C, 0), // D29
GPIO_PIN(A, 6), // D30
GPIO_PIN(A, 7) // D31
};
#endif // SleepingBeautyGpioPinMap_h

View file

@ -0,0 +1,37 @@
#ifndef Standard1284GpioPinMap_h
#define Standard1284GpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(B, 0), // D0
GPIO_PIN(B, 1), // D1
GPIO_PIN(B, 2), // D2
GPIO_PIN(B, 3), // D3
GPIO_PIN(B, 4), // D4
GPIO_PIN(B, 5), // D5
GPIO_PIN(B, 6), // D6
GPIO_PIN(B, 7), // D7
GPIO_PIN(D, 0), // D8
GPIO_PIN(D, 1), // D9
GPIO_PIN(D, 2), // D10
GPIO_PIN(D, 3), // D11
GPIO_PIN(D, 4), // D12
GPIO_PIN(D, 5), // D13
GPIO_PIN(D, 6), // D14
GPIO_PIN(D, 7), // D15
GPIO_PIN(C, 0), // D16
GPIO_PIN(C, 1), // D17
GPIO_PIN(C, 2), // D18
GPIO_PIN(C, 3), // D19
GPIO_PIN(C, 4), // D20
GPIO_PIN(C, 5), // D21
GPIO_PIN(C, 6), // D22
GPIO_PIN(C, 7), // D23
GPIO_PIN(A, 0), // D24
GPIO_PIN(A, 1), // D25
GPIO_PIN(A, 2), // D26
GPIO_PIN(A, 3), // D27
GPIO_PIN(A, 4), // D28
GPIO_PIN(A, 5), // D29
GPIO_PIN(A, 6), // D30
GPIO_PIN(A, 7) // D31
};
#endif // Standard1284GpioPinMap_h

View file

@ -0,0 +1,30 @@
#ifndef Teensy2GpioPinMap_h
#define Teensy2GpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(B, 0), // D0
GPIO_PIN(B, 1), // D1
GPIO_PIN(B, 2), // D2
GPIO_PIN(B, 3), // D3
GPIO_PIN(B, 7), // D4
GPIO_PIN(D, 0), // D5
GPIO_PIN(D, 1), // D6
GPIO_PIN(D, 2), // D7
GPIO_PIN(D, 3), // D8
GPIO_PIN(C, 6), // D9
GPIO_PIN(C, 7), // D10
GPIO_PIN(D, 6), // D11
GPIO_PIN(D, 7), // D12
GPIO_PIN(B, 4), // D13
GPIO_PIN(B, 5), // D14
GPIO_PIN(B, 6), // D15
GPIO_PIN(F, 7), // D16
GPIO_PIN(F, 6), // D17
GPIO_PIN(F, 5), // D18
GPIO_PIN(F, 4), // D19
GPIO_PIN(F, 1), // D20
GPIO_PIN(F, 0), // D21
GPIO_PIN(D, 4), // D22
GPIO_PIN(D, 5), // D23
GPIO_PIN(E, 6), // D24
};
#endif // Teensy2GpioPinMap_h

View file

@ -0,0 +1,51 @@
#ifndef Teensypp2GpioPinMap_h
#define Teensypp2GpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(D, 0), // D0
GPIO_PIN(D, 1), // D1
GPIO_PIN(D, 2), // D2
GPIO_PIN(D, 3), // D3
GPIO_PIN(D, 4), // D4
GPIO_PIN(D, 5), // D5
GPIO_PIN(D, 6), // D6
GPIO_PIN(D, 7), // D7
GPIO_PIN(E, 0), // D8
GPIO_PIN(E, 1), // D9
GPIO_PIN(C, 0), // D10
GPIO_PIN(C, 1), // D11
GPIO_PIN(C, 2), // D12
GPIO_PIN(C, 3), // D13
GPIO_PIN(C, 4), // D14
GPIO_PIN(C, 5), // D15
GPIO_PIN(C, 6), // D16
GPIO_PIN(C, 7), // D17
GPIO_PIN(E, 6), // D18
GPIO_PIN(E, 7), // D19
GPIO_PIN(B, 0), // D20
GPIO_PIN(B, 1), // D21
GPIO_PIN(B, 2), // D22
GPIO_PIN(B, 3), // D23
GPIO_PIN(B, 4), // D24
GPIO_PIN(B, 5), // D25
GPIO_PIN(B, 6), // D26
GPIO_PIN(B, 7), // D27
GPIO_PIN(A, 0), // D28
GPIO_PIN(A, 1), // D29
GPIO_PIN(A, 2), // D30
GPIO_PIN(A, 3), // D31
GPIO_PIN(A, 4), // D32
GPIO_PIN(A, 5), // D33
GPIO_PIN(A, 6), // D34
GPIO_PIN(A, 7), // D35
GPIO_PIN(E, 4), // D36
GPIO_PIN(E, 5), // D37
GPIO_PIN(F, 0), // D38
GPIO_PIN(F, 1), // D39
GPIO_PIN(F, 2), // D40
GPIO_PIN(F, 3), // D41
GPIO_PIN(F, 4), // D42
GPIO_PIN(F, 5), // D43
GPIO_PIN(F, 6), // D44
GPIO_PIN(F, 7), // D45
};
#endif // Teensypp2GpioPinMap_h

View file

@ -0,0 +1,25 @@
#ifndef UnoGpioPinMap_h
#define UnoGpioPinMap_h
static const GpioPinMap_t GpioPinMap[] = {
GPIO_PIN(D, 0), // D0
GPIO_PIN(D, 1), // D1
GPIO_PIN(D, 2), // D2
GPIO_PIN(D, 3), // D3
GPIO_PIN(D, 4), // D4
GPIO_PIN(D, 5), // D5
GPIO_PIN(D, 6), // D6
GPIO_PIN(D, 7), // D7
GPIO_PIN(B, 0), // D8
GPIO_PIN(B, 1), // D9
GPIO_PIN(B, 2), // D10
GPIO_PIN(B, 3), // D11
GPIO_PIN(B, 4), // D12
GPIO_PIN(B, 5), // D13
GPIO_PIN(C, 0), // D14
GPIO_PIN(C, 1), // D15
GPIO_PIN(C, 2), // D16
GPIO_PIN(C, 3), // D17
GPIO_PIN(C, 4), // D18
GPIO_PIN(C, 5) // D19
};
#endif // UnoGpioPinMap_h

View file

@ -0,0 +1,88 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef SysCall_h
#define SysCall_h
/**
* \file
* \brief SysCall class
*/
#if defined(ARDUINO)
#include <Arduino.h>
#include <SPI.h>
#elif defined(PLATFORM_ID) // Only defined if a Particle device
#include "application.h"
#else // defined(ARDUINO)
#error "Unknown system"
#endif // defined(ARDUINO)
//------------------------------------------------------------------------------
#ifdef ESP8266
// undefine F macro if ESP8266.
#undef F
#endif // ESP8266
//------------------------------------------------------------------------------
#ifndef F
/** Define macro for strings stored in flash. */
#define F(str) (str)
#endif // F
//------------------------------------------------------------------------------
/** \return the time in milliseconds. */
inline uint16_t curTimeMS() {
return millis();
}
//------------------------------------------------------------------------------
/**
* \class SysCall
* \brief SysCall - Class to wrap system calls.
*/
class SysCall {
public:
/** Halt execution of this thread. */
static void halt() {
while (1) {
yield();
}
}
/** Yield to other threads. */
static void yield();
};
#if defined(ESP8266)
inline void SysCall::yield() {
// Avoid ESP8266 bug
delay(0);
}
#elif defined(ARDUINO)
inline void SysCall::yield() {
// Use the external Arduino yield() function.
::yield();
}
#elif defined(PLATFORM_ID) // Only defined if a Particle device
inline void SysCall::yield() {
Particle.process();
}
#else // ESP8266
inline void SysCall::yield() {}
#endif // ESP8266
#endif // SysCall_h

View file

@ -0,0 +1,33 @@
/**
* Copyright (c) 2011-2018 Bill Greiman
* This file is part of the SdFat library for SD memory cards.
*
* MIT License
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included
* in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*/
#ifndef sdios_h
#define sdios_h
/**
* \file
* \brief C++ IO Streams features.
*/
#include "FatLib/fstream.h"
#include "FatLib/ArduinoStream.h"
#endif // sdios_h

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,218 @@
#ifndef _GUISLICE_CONFIG_H_
#define _GUISLICE_CONFIG_H_
// =======================================================================
// GUIslice library (user configuration) selection by device
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
// \file GUIslice_config.h
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// =========================================================================================
// SELECT ONE OF THE FOLLOWING EXAMPLE CONFIGURATIONS OR ADD YOUR OWN
// - Uncomment one of the following lines
// - These example configurations are located in the /configs folder
// - To add your own, make a copy of an example config, rename it
// and add it to the list here.
// - If no line is uncommented, then the default combined configuration
// file will be used, ie. GUIslice_config_ard.h / GUIslice_config_linux.h
// which is selected at the bottom of this file
// - Refer to https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Config-Table
// to help identify a suitable config for your MCU shield / display
// - Multiple configurations can be supported using the method described here:
// https://github.com/ImpulseAdventure/GUIslice/wiki/Arduino-Multiple-Configs
// =========================================================================================
// =========================================================================================
// IMPORTANT: Ensure you backup any custom config files before updating GUIslice!
// The Arduino IDE deletes all files within the library when updating
// =========================================================================================
// ---------------------------------------------------------------------------------------
// Add your own configs here:
// ---------------------------------------------------------------------------------------
//#include "../configs/my-config.h"
// ---------------------------------------------------------------------------------------
// Example configs included in library /configs:
// ---------------------------------------------------------------------------------------
// Arduino, ARM SAMD, Cortex M0/M4, nRF52:
// ------------------------------------------------------
//#include "../configs/ard-shld-adafruit_18_joy.h"
//#include "../configs/ard-shld-adafruit_28_cap.h"
//#include "../configs/ard-shld-adafruit_28_res.h"
//#include "../configs/ard-shld-eastrising_50_ra8875_res.h"
//#include "../configs/ard-shld-eastrising_50_ra8875_sumo_res.h"
//#include "../configs/ard-shld-eastrising_50_ssd1963_res.h"
//#include "../configs/ard-shld-eastrising_70_ra8876_gv.h"
//#include "../configs/ard-shld-elegoo_28_res.h"
//#include "../configs/ard-shld-generic1_35_touch.h"
//#include "../configs/ard-shld-gevino_tft.h"
//#include "../configs/ard-shld-ili9341_16b_touch.h"
//#include "../configs/ard-shld-mcufriend.h"
//#include "../configs/ard-shld-mcufriend_4wire.h"
//#include "../configs/ard-shld-mcufriend_xpt2046.h"
//#include "../configs/ard-shld-osmart_22_68130_touch.h"
//#include "../configs/ard-shld-waveshare_28_touch.h"
//#include "../configs/ard-shld-waveshare_40_notouch.h"
//#include "../configs/ard-shld-waveshare_40_xpt2046.h"
//#include "../configs/ard-adagfx-hx8347-xpt2046.h"
//#include "../configs/ard-adagfx-hx8357-ft6206.h"
//#include "../configs/ard-adagfx-hx8357-notouch.h"
//#include "../configs/ard-adagfx-hx8357-simple.h"
//#include "../configs/ard-adagfx-hx8357-stmpe610.h"
//#include "../configs/ard-adagfx-ili9341-ft6206.h"
//#include "../configs/ard-adagfx-ili9341-input.h"
//#include "../configs/ard-adagfx-ili9341-notouch.h"
//#include "../configs/ard-adagfx-ili9341-simple.h"
//#include "../configs/ard-adagfx-ili9341-stmpe610.h"
//#include "../configs/ard-adagfx-ili9341-xpt2046.h"
//#include "../configs/ard-adagfx-pcd8544-notouch.h"
//#include "../configs/ard-adagfx-ra8875-notouch.h"
//#include "../configs/ard-adagfx-ra8876-notouch.h"
//#include "../configs/ard-adagfx-ra8876-ft5206.h"
//#include "../configs/ard-adagfx-ssd1306-notouch.h"
//#include "../configs/ard-adagfx-st7735-notouch.h"
//#include "../configs/due-adagfx-ili9341-ft6206.h"
//#include "../configs/due-adagfx-ili9341-urtouch.h"
// ESP8266, ESP32, M5stack, TTGO:
// ------------------------------------------------------
//#include "../configs/esp-shld-m5stack.h"
//#include "../configs/esp-shld-ttgo_btc_ticker.h"
//#include "../configs/esp-tftespi-default-ft6206.h"
//#include "../configs/esp-tftespi-default-notouch.h"
//#include "../configs/esp-tftespi-default-simple.h"
//#include "../configs/esp-tftespi-default-stmpe610.h"
//#include "../configs/esp-tftespi-default-xpt2046.h"
//#include "../configs/esp-tftespi-default-xpt2046_int.h"
// Teensy:
// ------------------------------------------------------
//#include "../configs/teensy-adagfx-ili9341-xpt2046.h"
//#include "../configs/teensy-adagfx-ili9341-xpt2046-audio.h"
//#include "../configs/teensy-adagfx-ili9341_t3-xpt2046.h"
//#include "../configs/teensy-adagfx-ili9341_t3-xpt2046-audio.h"
// STM32:
// ------------------------------------------------------
//#include "../configs/stm32-adagfx-mcufriend-notouch.h"
//#include "../configs/stm32-adagfx-mcufriend-simple.h"
// Multi-device shields:
// ------------------------------------------------------
//#include "../configs/mult-shld-adafruit_24_feather_touch.h"
//#include "../configs/mult-shld-adafruit_35_feather_touch.h"
// Raspberry Pi / LINUX:
// ------------------------------------------------------
//#include "../configs/rpi-sdl1-default-tslib.h"
//#include "../configs/rpi-sdl1-default-sdl.h"
//#include "../configs/linux-sdl1-default-mouse.h"
// =========================================================================================
// DETECT DEVICE PLATFORM
// =========================================================================================
// Detect device platform
// #if defined(__linux__)
// #define GSLC_CFG_LINUX
// #elif defined(__AVR__) && !defined(TEENSYDUINO)
// // Note: Teensy 2 also defines __AVR__, so differentiate with TEENSYDUINO
// #define GSLC_CFG_ARD
// #elif defined(ARDUINO_SAMD_ZERO)
// #define GSLC_CFG_ARD
// #elif defined(ESP8266) || defined(ESP32)
// #define GSLC_CFG_ARD
// #elif defined(NRF52)
// #define GSLC_CFG_ARD
// #elif defined(ARDUINO_STM32_FEATHER) || defined(__STM32F1__)
// #define GSLC_CFG_ARD
// #elif defined(ARDUINO_ARCH_STM32) // ST Core from STMicroelectronics
// #define GSLC_CFG_ARD
// #elif defined(ARDUINO_ARCH_SAM) // Arduino Due
// #define GSLC_CFG_ARD
// #elif defined(ARDUINO_ARCH_SAMD) // M0_PRO
// #define GSLC_CFG_ARD
// #elif defined(__AVR__) && defined(TEENSYDUINO) // Teensy 2
// #define GSLC_DEV_TEENSY_2
// #define GSLC_CFG_ARD
// #elif defined(__MKL26Z64__) // Teensy LC
// #define GSLC_CFG_ARD
// #define GSLC_DEV_TEENSY_LC
// #elif defined(__MK20DX256__) // Teensy 3.2
// #define GSLC_CFG_ARD
// #define GSLC_DEV_TEENSY_3_2
// #elif defined(__MK64FX512__) // Teensy 3.5
// #define GSLC_CFG_ARD
// #define GSLC_DEV_TEENSY_3_5
// #elif defined(__MK66FX1M0__) // Teensy 3.6
// #define GSLC_CFG_ARD
// #define GSLC_DEV_TEENSY_3_6
// #elif defined(__MK66FX1M0__) // Teensy 3.6
// #define GSLC_CFG_ARD
// #define GSLC_DEV_TEENSY_3_6
// #elif defined(__IMXRT1062__)
// #define GSLC_CFG_ARD
// #define GSLC_DEV_TEENSY_4_0
// #else
// #warning Unknown
// #error "Unknown device platform"
// #endif
// Adafruit nRF52840 Feather
#include "ard-adagfx-ili9341-stmpe610.h"
// #include "ard-adagfx-ili9341-notouch.h"
#define GSLC_CFG_ARD
// =========================================================================================
// DEFAULT COMBINED CONFIGURATION FILE
// - If no user configuration has been selected, a default config will be selected here
// - Note that the include guard _GUISLICE_CONFIG_ARD_H_ and _GUISLICE_CONFIG_LINUX_H_
// will prevent these from loading if any of the user configs have been loaded
// =========================================================================================
#if defined(GSLC_CFG_LINUX)
#include "GUIslice_config_linux.h"
#elif defined(GSLC_CFG_ARD)
#include "GUIslice_config_ard.h"
#endif
// -----------------------------------------------------------------------------------------
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_CONFIG_H_

View file

@ -0,0 +1,526 @@
#ifndef _GUISLICE_CONFIG_ARD_H_
#define _GUISLICE_CONFIG_ARD_H_
#warning No config selected in GUIslice_config.h - resorting to defaults.
// =============================================================================
// GUIslice library (user configuration) for:
// - Arduino
// - Cortex-M0
// - ESP8266 / ESP32
// - nRF52
// - STM32
//
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =============================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =============================================================================
// \file GUIslice_config_ard.h
// =============================================================================
// User Configuration
// - This file can be modified by the user to match the
// intended target configuration
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
// specific to board and display combinations
// =============================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// =============================================================================
// DISPLAY CONFIGURATION - SELECT
// =============================================================================
// Specify the graphics driver library
// - Uncomment one of the following graphics drivers DRV_DISP_*
// applicable to the device type in use
// --------------------------------------------------------------
// Arduino / ATmega / AVR / Cortex-M0 / nRF52:
#define DRV_DISP_ADAGFX // Adafruit-GFX library
// --------------------------------------------------------------
// ESP8266 / ESP32 / NodeMCU:
// #define DRV_DISP_ADAGFX // Adafruit-GFX library
// #define DRV_DISP_TFT_ESPI // Bodmer/TFT_eSPI library
// #define DRV_DISP_M5STACK // m5stack/M5Stack library
// --------------------------------------------------------------
// STM32:
// #define DRV_DISP_ADAGFX // Adafruit-GFX library
// #define DRV_DISP_ADAGFX_AS // Adafruit-GFX-AS library, high speed using DMA
// --------------------------------------------------------------
// =============================================================================
// TOUCH CONFIGURATION - SELECT
// =============================================================================
// Specify the touchscreen driver
// - Uncomment one of the following touchscreen drivers DRV_TOUCH_*
// applicable to the controller chip in use
#define DRV_TOUCH_NONE // No touchscreen support & no input (GPIO / keyboard)
// #define DRV_TOUCH_ADA_STMPE610 // Adafruit STMPE610 touch driver
// #define DRV_TOUCH_ADA_FT6206 // Adafruit FT6206 touch driver
// #define DRV_TOUCH_ADA_SIMPLE // Adafruit Touchscreen
// #define DRV_TOUCH_TFT_ESPI // TFT_eSPI integrated XPT2046 touch driver
// #define DRV_TOUCH_M5STACK // M5stack integrated button driver
// #define DRV_TOUCH_XPT2046_PS // PaulStoffregen/XPT2046_Touchscreen
// #define DRV_TOUCH_XPT2046_STM // Arduino_STM32/Serasidis_XPT2046_touch (XPT2046_touch.h)
// #define DRV_TOUCH_INPUT // No touchscreen support, but input only (GPIO / keyboard)
// #define DRV_TOUCH_HANDLER // touch handler class
// =============================================================================
// DISPLAY CONFIGURATION - DETAILS
// - Graphics display driver-specific additional configuration
// =============================================================================
// -----------------------------------------------------------------------------
#if defined(DRV_DISP_ADAGFX)
// The Adafruit-GFX library supports a number of displays
// - Select a display sub-type by uncommenting one of the
// following DRV_DISP_ADAGFX_* lines
#define DRV_DISP_ADAGFX_ILI9341 // Adafruit ILI9341
//#define DRV_DISP_ADAGFX_ILI9341_8BIT // Adafruit ILI9341 (8-bit interface)
//#define DRV_DISP_ADAGFX_ST7735 // Adafruit ST7735
//#define DRV_DISP_ADAGFX_SSD1306 // Adafruit SSD1306
//#define DRV_DISP_ADAGFX_HX8347 // prenticedavid/HX8347D_kbv
//#define DRV_DISP_ADAGFX_HX8357 // Adafruit HX8357
//#define DRV_DISP_ADAGFX_PCD8544 // Adafruit PCD8544
// For Adafruit-GFX drivers, define pin connections
// - Define general pins (modify these example pin assignments to match your board)
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
#define ADAGFX_PIN_CS 10 // Display chip select
#define ADAGFX_PIN_DC 9 // Display SPI data/command
#define ADAGFX_PIN_RST 0 // Display Reset (some displays could use pin 11)
#define ADAGFX_PIN_SDCS 4 // SD card chip select
#define ADAGFX_PIN_WR A1 // Display write pin (for parallel displays)
#define ADAGFX_PIN_RD A0 // Display read pin (for parallel displays)
// Use hardware SPI interface?
// - Set to 1 to enable hardware SPI interface, 0 to use software SPI
// - Software SPI may support the use of custom pin selection (via ADAGFX_PIN_MOSI,
// ADAGFX_PIN_MISO, ADAGFX_PIN_CLK). These pin definitions can be left blank in
// hardware SPI mode.
#define ADAGFX_SPI_HW 1
// Define custom SPI pin connections used in software SPI mode (ADAGFX_SPI_HW=0)
// - These definitions can be left blank in hardware mode (ADAGFX_SPI_HW=1)
#define ADAGFX_PIN_MOSI
#define ADAGFX_PIN_MISO
#define ADAGFX_PIN_CLK
// Set Default rotation
// you can specify values 0,1,2,3, rotation is clockwise
#define GSLC_ROTATE 1
#elif defined(DRV_DISP_ADAGFX_AS)
//NOTE: this is a optimized driver for STM32 only
// The Adafruit-GFX-AS library supports a number of displays
// - Select a display sub-type by uncommenting one of the
// following DRV_DISP_ADAGFX_* lines
#define DRV_DISP_ADAGFX_ILI9341_STM // Adafruit ILI9341 (STM32 version)
// For Adafruit-GFX drivers, define pin connections
// - Define general pins (modify these example pin assignments to match your board)
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
//Note: Fixed pin setting for HW SPI1
// PA5 SCLK
// PA6 MISO
// PA7 MOSI
// USE Arduino STM32 PIN Notations
// - Define to use Arduino STM32 PIN Notations
// #define STM32_NOTATION
#if defined(STM32_NOTATION)
// NOTE: Using Arduino STM32 pin notation
#define ADAGFX_PIN_CS PA4 // Display chip select
#define ADAGFX_PIN_DC PB1 // Display SPI data/command
#define ADAGFX_PIN_RST PB0 // Display Reset (set to -1 in order to use Adafruit-GFX drivers w/o reset)
#define ADAGFX_PIN_SDCS // SD card chip select
#define ADAGFX_PIN_WR // Display write pin (for parallel displays)
#define ADAGFX_PIN_RD // Display read pin (for parallel displays)
#else
// NOTE: Using Arduino pin notation
#define ADAGFX_PIN_CS 10 // Display chip select
#define ADAGFX_PIN_DC 9 // Display SPI data/command
#define ADAGFX_PIN_RST 0 // Display Reset (some displays could use pin 11)
#define ADAGFX_PIN_SDCS 4 // SD card chip select
#define ADAGFX_PIN_WR A1 // Display write pin (for parallel displays)
#define ADAGFX_PIN_RD A0 // Display read pin (for parallel displays)
#endif
// Use hardware SPI interface?
// - Set to 1 to enable hardware SPI interface, 0 to use software SPI
// - Software SPI may support the use of custom pin selection (via ADAGFX_PIN_MOSI,
// ADAGFX_PIN_MISO, ADAGFX_PIN_CLK). These pin definitions can be left blank in
// hardware SPI mode.
#define ADAGFX_SPI_HW 1
// Define custom SPI pin connections used in software SPI mode (ADAGFX_SPI_HW=0)
// - These definitions can be left blank in hardware mode (ADAGFX_SPI_HW=1)
#define ADAGFX_PIN_MOSI
#define ADAGFX_PIN_MISO
#define ADAGFX_PIN_CLK
// Set Default rotation
// you can specify values 0,1,2,3, rotation is clockwise
#define GSLC_ROTATE 1
// -----------------------------------------------------------------------------
#elif defined(DRV_DISP_TFT_ESPI)
// NOTE: When using the TFT_eSPI library, there are additional
// library-specific configuration files that may need
// customization (including pin configuration), such as
// "User_Setup_Select.h" (typically located in the
// Arduino /libraries/TFT_eSPI folder). Please refer to
// Bodmer's TFT_eSPI library for more details:
// https://github.com/Bodmer/TFT_eSPI
// NOTE: To avoid potential SPI conflicts, it is recommended
// that SUPPORT_TRANSACTIONS is defined in TFT_eSPI's "User Setup"
// Set Default rotation
// you can specify values 0,1,2,3, rotation is clockwise
#define GSLC_ROTATE 1
// -----------------------------------------------------------------------------
#elif defined(DRV_DISP_M5STACK)
#define ADAGFX_PIN_SDCS 4 // SD card chip select
#define TFT_LIGHT_PIN 32 // display backlight
// Set Default rotation
// you can specify values 0,1,2,3, rotation is clockwise
// NOTE: M5stack has a fixed display. A setting of 1 should
// match the built-in display and not need changing.
#define GSLC_ROTATE 1
#else
#error "Unknown driver for display DRV_DISP_..."
#endif // DRV_DISP_*
// =============================================================================
// TOUCH CONFIGURATION - DETAILS
// - Touch Driver-specific additional configuration
// =============================================================================
// -----------------------------------------------------------------------------
#if defined(DRV_TOUCH_NONE)
//no touch defined
#elif defined(DRV_TOUCH_ADA_STMPE610)
// Select wiring method by setting one of the following to 1
#define ADATOUCH_I2C_HW 0
#define ADATOUCH_SPI_HW 1
#define ADATOUCH_SPI_SW 0 // [TODO]
// For ADATOUCH_I2C_HW=1
#define ADATOUCH_I2C_ADDR 0x41 // I2C address of touch device
// For ADATOUCH_SPI_HW=1
#define ADATOUCH_PIN_CS 8 // From Adafruit 2.8" TFT touch shield
// Calibration values for touch display
// - These values may need to be updated to match your display
// - Typically used in resistive displays
// - These values can be determined from the Adafruit touchtest example sketch
// (check for min and max values reported from program as you touch display
// corners)
// - Note that X & Y directions reference the display's natural orientation
#define ADATOUCH_X_MIN 230
#define ADATOUCH_Y_MIN 260
#define ADATOUCH_X_MAX 3800
#define ADATOUCH_Y_MAX 3700
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_ADA_FT6206)
// Define sensitivity coefficient (capacitive touch)
#define ADATOUCH_SENSITIVITY 40
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_ADA_SIMPLE)
// Define 4-wire resistive touchscreen pinout
#define ADATOUCH_PIN_YP A2 // "Y+": Must be an analog pin, use "An" notation
#define ADATOUCH_PIN_XM A3 // "X-": Must be an analog pin, use "An" notation
#define ADATOUCH_PIN_YM 44 // "Y-": Can be a digital pin
#define ADATOUCH_PIN_XP 45 // "X+": Can be a digital pin
#define ADATOUCH_RX 300 // "rxplate"
// Calibration values for touch display
// - These values may need to be updated to match your display
// - Typically used in resistive displays
#define ADATOUCH_X_MIN 100
#define ADATOUCH_Y_MIN 150
#define ADATOUCH_X_MAX 900
#define ADATOUCH_Y_MAX 900
// Define pressure threshold for detecting a touch
#define ADATOUCH_PRESS_MIN 10
#define ADATOUCH_PRESS_MAX 1000
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_TFT_ESPI)
// The TFT_eSPI display library also includes support for XPT2046 touch controller
// Note that TFT_eSPI's "User_Setup" should define TOUCH_CS
#define DRV_TOUCH_IN_DISP // Use the display driver (TFT_eSPI) for touch events
// Define the XPT2046 touch driver calibration values
// - The following are some example defaults, but they should be updated
// to match your specific touch device.
#define TFT_ESPI_TOUCH_CALIB { 321,3498,280,3593,3 }
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_M5STACK)
// M5stack integrated button handler
#define DRV_TOUCH_IN_DISP // Use the display driver (M5stack) for touch events
// NOTE: Long-press detection is only available in the latest
// M5stack library releases. Uncomment the following
// if the Btn wasReleasefor() API is available.
//
// Define duration (in ms) for a long-press button event
//#define M5STACK_TOUCH_PRESS_LONG 300
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_XPT2046_PS)
// PaulStoffregen/XPT2046_Touchscreen
// Chip select pin for touch
#define XPT2046_CS 3
// Calibration values for touch display
// - These values may need to be updated to match your display
// - empirically found for XPT2046
#define ADATOUCH_X_MIN 246
#define ADATOUCH_Y_MIN 3925
#define ADATOUCH_X_MAX 3837
#define ADATOUCH_Y_MAX 370
// Define pressure threshold for detecting a touch
#define ADATOUCH_PRESS_MIN 10
#define ADATOUCH_PRESS_MAX 1000
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_XPT2046_STM)
// Arduino_STM32/Serasidis_XPT2046_touch (XPT2046_touch.h)
// NOTE: This touch library is included in the Arduino_STM32 library
// While it still works on many non-STM32 targets, it is recommended
// that users use DRV_TOUCH_XPT2046_PS instead.
// SPI2 is used. Due to some known issues of the TFT SPI driver working on SPI1
// it was not possible to share the touch with SPI1.
// On the Arduino STM32 these are the following pins:
// PB13 SCLK
// PB14 MISO
// PB15 MOSI
#define XPT2046_DEFINE_DPICLASS SPIClass XPT2046_spi(2); //Create an SPI instance on SPI2 port
// Chip select pin for touch SPI2
#define XPT2046_CS PB12
// Calibration values for touch display
// - These values may need to be updated to match your display
// - empirically found for XPT2046
#define ADATOUCH_X_MIN 398
#define ADATOUCH_Y_MIN 280
#define ADATOUCH_X_MAX 3877
#define ADATOUCH_Y_MAX 3805
// Define pressure threshold for detecting a touch
#define ADATOUCH_PRESS_MIN 10
#define ADATOUCH_PRESS_MAX 1000
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_INPUT)
// Include basic support for GPIO/keyboard only
// -----------------------------------------------------------------------------
#elif defined(DRV_TOUCH_HANDLER)
// touch handler class
// -----------------------------------------------------------------------------
#else
#error "Unknown driver for touch DRV_TOUCH_..."
#endif // DRV_TOUCH_*
// -----------------------------------------------------------------------------
// TODO: maybe those macros should be moved to one include file which is included by all drivers
#define TOUCH_ROTATION_DATA 0x6350
#define TOUCH_ROTATION_SWAPXY(rotation) ((( TOUCH_ROTATION_DATA >> ((rotation&0x03)*4) ) >> 2 ) & 0x01 )
#define TOUCH_ROTATION_FLIPX(rotation) ((( TOUCH_ROTATION_DATA >> ((rotation&0x03)*4) ) >> 1 ) & 0x01 )
#define TOUCH_ROTATION_FLIPY(rotation) ((( TOUCH_ROTATION_DATA >> ((rotation&0x03)*4) ) >> 0 ) & 0x01 )
// - Set any of the following to 1 to perform touch display
// remapping functions, 0 to disable. Use DBG_TOUCH to determine which
// remapping modes should be enabled for your display
// - Please refer to the wiki for details:
// https://github.com/ImpulseAdventure/GUIslice/wiki/Configure-Touch-Support
#define ADATOUCH_SWAP_XY 0
#define ADATOUCH_FLIP_X 0
#define ADATOUCH_FLIP_Y 0
// Define the maximum number of touch events that are handled
// per gslc_Update() call. Normally this can be set to 1 but certain
// displays may require a greater value (eg. 30) in order to increase
// responsiveness of the touch functionality.
#define GSLC_TOUCH_MAX_EVT 1
// =============================================================================
// COMMON CONFIGURATION
// =============================================================================
// Error reporting
// - Set DEBUG_ERR to 1 to enable error reporting via the Serial connection
// - Enabling DEBUG_ERR increases FLASH memory consumption which may be
// limited on the baseline Arduino (ATmega328P) devices. Therefore it
// is recommended to disable DEBUG_ERR (set to 0) on baseline Arduino
// once initial device operation confirmed to work in examples ex01 and ex02.
//
#if defined(__AVR__)
#define DEBUG_ERR 1 // Debugging enabled by default
#else
// For all other devices, DEBUG_ERR is enabled by default.
// Since this mode increases FLASH memory considerably, it may be
// necessary to disable this feature.
#define DEBUG_ERR 1 // Debugging enabled by default
#endif
// Debug initialization message
// - By default, GUIslice outputs a message in DEBUG_ERR mode
// to indicate the initialization status, even during success.
// - To disable the messages during successful initialization,
// uncomment the following line.
//#define INIT_MSG_DISABLE
// Enable of optional features
// - For memory constrained devices such as Arduino, it is best to
// set the following features to 0 (to disable) unless they are
// required.
#define GSLC_FEATURE_COMPOUND 0 // Compound elements (eg. XSelNum)
#define GSLC_FEATURE_XGAUGE_RADIAL 0 // XGauge control with radial support
#define GSLC_FEATURE_XGAUGE_RAMP 0 // XGauge control with ramp support
#define GSLC_FEATURE_XTEXTBOX_EMBED 0 // XTextbox control with embedded color
#define GSLC_FEATURE_INPUT 0 // Keyboard / GPIO input control
// Enable support for SD card
// - Set to 1 to enable, 0 to disable
// - Note that the inclusion of the SD library consumes considerable
// RAM and flash memory which could be problematic for Arduino models
// with limited resources.
#define GSLC_SD_EN 0
// Define buffer size for loading images from SD
// - A larger buffer will be faster but at the cost of RAM
#define GSLC_SD_BUFFPIXEL 50
// Enable support for graphics clipping (DrvSetClipRect)
// - Note that this will impact performance of drawing graphics primitives
#define GSLC_CLIP_EN 1
// Enable for bitmap transparency and definition of color to use
#define GSLC_BMP_TRANS_EN 1 // 1 = enabled, 0 = disabled
#define GSLC_BMP_TRANS_RGB 0xFF,0x00,0xFF // RGB color (default:pink)
// In "Local String" mode, memory within internal element array is
// used for strings. This mode incurs a memory cost for all elements,
// irrespective of whether strings are used or their length. This
// mode may make string definition convenient but is not memory-efficient.
// Therefore, it is not recommended for limited memory devices such as
// Arduino.
// - When using element local string storage (GSLC_LOCAL_STR=1),
// GSLC_LOCAL_STR_LEN defines the fixed length buffer used for every element
#define GSLC_LOCAL_STR 0 // 1=Use local strings (in element array), 0=External
#define GSLC_LOCAL_STR_LEN 30 // Max string length of text elements
#define GSLC_USE_FLOAT 0 // 1=Use floating pt library, 0=Fixed-point lookup tables
// Debug diagnostic modes
// - Uncomment any of the following to enable specific debug modes
//#define DBG_LOG // Enable debugging log output
//#define DBG_TOUCH // Enable debugging of touch-presses
//#define DBG_FRAME_RATE // Enable diagnostic frame rate reporting
//#define DBG_DRAW_IMM // Enable immediate rendering of drawing primitives
//#define DBG_DRIVER // Enable graphics driver debug reporting
// =============================================================================
// INTERNAL CONFIGURATION
// - Users should not need to modify the following
// =============================================================================
// Display device string is only used in LINUX drivers
#define GSLC_DEV_TOUCH "" // No device path used
// Define compatibility for non-AVR to call PROGMEM functions
#if defined(__AVR__)
#define GSLC_USE_PROGMEM 1
#else
#define GSLC_USE_PROGMEM 0
#endif
// =============================================================================
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_CONFIG_ARD_H_

View file

@ -0,0 +1,191 @@
#ifndef _GUISLICE_CONFIG_LINUX_H_
#define _GUISLICE_CONFIG_LINUX_H_
#warning No config selected in GUIslice_config.h - resorting to defaults.
// =======================================================================
// GUIslice library (user configuration) for LINUX / Raspberry Pi / Beaglebone
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
// \file GUIslice_config_linux.h
// \brief GUIslice library (user configuration) for LINUX / Raspberry Pi / Beaglebone
// =======================================================================
// User Configuration
// - This file can be modified by the user to match the
// intended target configuration
// - Please refer to "docs/GUIslice_config_guide.xlsx" for detailed examples
// specific to board and display combinations
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// -----------------------------------------------------------------------------------------
// Specify the graphics driver library
// - Uncomment one of the following graphics drivers
#define DRV_DISP_SDL1 // LINUX: SDL 1.2 library
//#define DRV_DISP_SDL2 // LINUX: SDL 2.0 library
// Specify the touchscreen driver
// - Uncomment one of the following touchscreen drivers
//#define DRV_TOUCH_NONE // No touchscreen support
//#define DRV_TOUCH_SDL // LINUX: Use SDL touch driver
#define DRV_TOUCH_TSLIB // LINUX: Use tslib touch driver
// -----------------------------------------------------------------------------------------
// Enable of optional features
// - For memory constrained devices such as Arduino, it is best to
// set the following features to 0 (to disable) unless they are
// required.
#define GSLC_FEATURE_COMPOUND 1 // Compound elements (eg. XSelNum)
#define GSLC_FEATURE_XGAUGE_RADIAL 1 // XGauge control with radial support
#define GSLC_FEATURE_XGAUGE_RAMP 1 // XGauge control with ramp support
#define GSLC_FEATURE_XTEXTBOX_EMBED 0 // XTextbox control with embedded color
#define GSLC_FEATURE_INPUT 1 // Keyboard / GPIO input control
// Error reporting
// - Set DEBUG_ERR to 1 to enable error reporting via the console
#define DEBUG_ERR 1 // Enable by default
// Debug initialization message
// - By default, GUIslice outputs a message in DEBUG_ERR mode
// to indicate the initialization status, even during success.
// - To disable the messages during successful initialization,
// uncomment the following line.
//#define INIT_MSG_DISABLE
// -----------------------------------------------------------------------------------------
// Graphics display driver-specific additional configuration
#if defined(DRV_DISP_SDL1)
// Define default device paths for framebuffer & touchscreen
#define GSLC_DEV_FB "/dev/fb1"
#define GSLC_DEV_TOUCH "/dev/input/touchscreen"
#define GSLC_DEV_VID_DRV "fbcon"
// Enable SDL startup workaround? (1 to enable, 0 to disable)
#define DRV_SDL_FIX_START 0
// Show SDL mouse (1 to show, 0 to hide)
#define DRV_SDL_MOUSE_SHOW 0
#define GSLC_LOCAL_STR 1
#define GSLC_USE_FLOAT 1
#elif defined(DRV_DISP_SDL2)
// Define default device paths for framebuffer & touchscreen
// - The following assumes display driver (eg. fbtft) reads from fb1
// - Raspberry Pi can support hardware acceleration onto fb0
// - To use SDL2.0 with hardware acceleration with such displays,
// use fb0 as the target and then run fbcp to mirror fb0 to fb1
#define GSLC_DEV_FB "/dev/fb0"
#define GSLC_DEV_TOUCH ""
#define GSLC_DEV_VID_DRV "x11"
// Show SDL mouse (1 to show, 0 to hide)
#define DRV_SDL_MOUSE_SHOW 0
// Enable hardware acceleration
#define DRV_SDL_RENDER_ACCEL 1
#define GSLC_LOCAL_STR 1
#define GSLC_USE_FLOAT 1
#endif // DRV_DISP_*
// -----------------------------------------------------------------------------------------
// Touch Driver-specific additional configuration
#if defined(DRV_TOUCH_SDL)
#define DRV_TOUCH_IN_DISP // Use the display driver (SDL) for touch events
#endif // DRV_TOUCH_*
// NOTE: The GSLC_ROTATE feature is not yet supported in SDL mode
// however, the following settings are provided for future use.
// - Set any of the following to 1 to perform touch display
// remapping functions, 0 to disable. Use DBG_TOUCH to determine which
// remapping modes should be enabled for your display
// - Please refer to the wiki for details:
// https://github.com/ImpulseAdventure/GUIslice/wiki/Configure-Touch-Support
#define ADATOUCH_SWAP_XY 0
#define ADATOUCH_FLIP_X 0
#define ADATOUCH_FLIP_Y 0
// Define the maximum number of touch events that are handled
// per gslc_Update() call. Normally this can be set to 1 but certain
// displays may require a greater value (eg. 30) in order to increase
// responsiveness of the touch functionality.
#define GSLC_TOUCH_MAX_EVT 1
// -----------------------------------------------------------------------------------------
// When using element local string storage (GSLC_LOCAL_STR=1),
// this defines the fixed length buffer used for every element
#define GSLC_LOCAL_STR_LEN 30 // Max string length of text elements
// Debug modes
// - Uncomment the following to enable specific debug modes
//#define DBG_LOG // Enable debugging log output
//#define DBG_TOUCH // Enable debugging of touch-presses
//#define DBG_FRAME_RATE // Enable diagnostic frame rate reporting
//#define DBG_DRAW_IMM // Enable immediate rendering of drawing primitives
//#define DBG_DRIVER // Enable graphics driver debug reporting
// Enable for bitmap transparency and definition of color to use
#define GSLC_BMP_TRANS_EN 1 // 1 = enabled, 0 = disabled
#define GSLC_BMP_TRANS_RGB 0xFF,0x00,0xFF // RGB color (default:pink)
// -----------------------------------------------------------------------------------------
// Define compatibility for non-AVR to call PROGMEM functions
#define GSLC_USE_PROGMEM 0
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_CONFIG_LINUX_H_

View file

@ -0,0 +1,66 @@
#ifndef _GUISLICE_DRV_H_
#define _GUISLICE_DRV_H_
// =======================================================================
// GUIslice library (generic driver layer include)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
// =======================================================================
// Generic Driver Layer
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#if defined(DRV_DISP_SDL1)
#include "GUIslice_drv_sdl.h"
#elif defined(DRV_DISP_SDL2)
#include "GUIslice_drv_sdl.h"
#elif defined(DRV_DISP_ADAGFX) || defined(DRV_DISP_ADAGFX_AS)
#include "GUIslice_drv_adagfx.h"
#elif defined(DRV_DISP_TFT_ESPI)
#include "GUIslice_drv_tft_espi.h"
#elif defined(DRV_DISP_M5STACK)
#include "GUIslice_drv_m5stack.h"
#elif defined(DRV_DISP_UTFT)
#include "GUIslice_drv_utft.h"
#else
#error "Driver needs to be specified in GUIslice_config_*.h (DRV_DISP_*)"
#endif
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_DRV_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,757 @@
#ifndef _GUISLICE_DRV_ADAGFX_H_
#define _GUISLICE_DRV_ADAGFX_H_
// =======================================================================
// GUIslice library (driver layer for Adafruit-GFX)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file GUIslice_drv_adagfx.h
/// \brief GUIslice library (driver layer for Adafruit-GFX)
// =======================================================================
// Driver Layer for Adafruit-GFX
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "GUIslice.h"
#include <stdio.h>
// Determine characteristics for configured touch driver
// - DRV_TOUCH_TYPE_EXTERNAL: TDrv* external touch APIs are enabled
// - DRV_TOUCH_TYPE_RES: Resistive overlay
// - DRV_TOUCH_TYPE_CAP: Capacitive overlay
// - DRV_TOUCH_TYPE_ANALOG: Analog input
#if defined(DRV_TOUCH_ADA_STMPE610)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_ADA_FT6206)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_CAP // Capacitive
#elif defined(DRV_TOUCH_ADA_FT5206)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_CAP // Capacitive
#elif defined(DRV_TOUCH_ADA_SIMPLE)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#define DRV_TOUCH_TYPE_ANALOG // Analog
#elif defined(DRV_TOUCH_ADA_RA8875)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_ADA_RA8875_SUMO)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_XPT2046_STM)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_XPT2046_PS)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_URTOUCH)
#define DRV_TOUCH_TYPE_EXTERNAL
// Don't set DRV_TOUCH_TYPE_RES since URTouch provides its own calibration
//#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_INPUT)
#define DRV_TOUCH_TYPE_EXTERNAL
#elif defined(DRV_TOUCH_HANDLER)
#define DRV_TOUCH_TYPE_EXTERNAL
#elif defined(DRV_TOUCH_NONE)
#endif // DRV_TOUCH_*
// =======================================================================
// API support definitions
// - These defines indicate whether the driver includes optimized
// support for various APIs. If a define is set to 0, then the
// GUIslice core emulation will be used instead.
// - At the very minimum, the point draw routine must be available:
// gslc_DrvDrawPoint()
// =======================================================================
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
#define DRV_HAS_DRAW_TRI_FRAME 1 ///< Support gslc_DrvDrawFrameTriangle()
#define DRV_HAS_DRAW_TRI_FILL 1 ///< Support gslc_DrvDrawFillTriangle()
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
#define DRV_OVERRIDE_TXT_ALIGN 0 ///< Driver provides text alignment
// -----------------------------------------------------------------------
// Driver-specific overrides
// - Some drivers have exceptions to the above support configuration
// -----------------------------------------------------------------------
#if defined(DRV_DISP_WAVESHARE_ILI9486)
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
#undef DRV_HAS_DRAW_TRI_FRAME
#undef DRV_HAS_DRAW_TRI_FILL
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
#define DRV_HAS_DRAW_TRI_FRAME 0
#define DRV_HAS_DRAW_TRI_FILL 0
#elif defined(DRV_DISP_LCDGFX)
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
#undef DRV_HAS_DRAW_CIRCLE_FRAME
#undef DRV_HAS_DRAW_CIRCLE_FILL
#undef DRV_HAS_DRAW_TRI_FRAME
#undef DRV_HAS_DRAW_TRI_FILL
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
#define DRV_HAS_DRAW_CIRCLE_FRAME 0
#define DRV_HAS_DRAW_CIRCLE_FILL 0
#define DRV_HAS_DRAW_TRI_FRAME 0
#define DRV_HAS_DRAW_TRI_FILL 0
#elif defined(DRV_DISP_ADAGFX_RA8876)
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
#elif defined(DRV_DISP_ADAGFX_RA8876_GV)
#undef DRV_HAS_DRAW_RECT_ROUND_FRAME
#undef DRV_HAS_DRAW_RECT_ROUND_FILL
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0
#elif defined(DRV_DISP_ADAGFX_ILI9341)
// BLIT support in library
#undef DRV_HAS_DRAW_BMP_MEM
#define DRV_HAS_DRAW_BMP_MEM 1
#endif
// =======================================================================
// Driver-specific members
// =======================================================================
typedef struct {
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
gslc_tsRect rClipRect; ///< Clipping rectangle
} gslc_tsDriver;
// =======================================================================
// Public APIs to GUIslice core library
// - These functions define the renderer / driver-dependent
// implementations for the core drawing operations within
// GUIslice.
// =======================================================================
// -----------------------------------------------------------------------
// Configuration Functions
// -----------------------------------------------------------------------
///
/// Initialize the SDL library
/// - Performs clean startup workaround (if enabled)
/// - Configures video mode
/// - Initializes font support
///
/// PRE:
/// - The environment variables should be configured before
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
/// or manually in user function.
///
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
bool gslc_DrvInit(gslc_tsGui* pGui);
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
///
/// Free up any members associated with the driver
/// - Eg. renderers, windows, background surfaces, etc.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvDestruct(gslc_tsGui* pGui);
///
/// Get the display driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
///
/// Get the touch driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
///
/// Get the native display driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the display driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
///
/// Get the native touch driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the touch driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Image/surface handling Functions
// -----------------------------------------------------------------------
///
/// Load a bitmap (*.bmp) and create a new image resource.
/// Transparency is enabled by GSLC_BMP_TRANS_EN
/// through use of color (GSLC_BMP_TRANS_RGB).
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return Image pointer (surface/texture) or NULL if error
///
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a bitmap image
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a solid color
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nCol: RGB Color to use
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
///
/// Set an element's normal-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Set an element's glow-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Release an image surface
///
/// \param[in] pvImg: Void ptr to image
///
/// \return none
///
void gslc_DrvImageDestruct(void* pvImg);
///
/// Set the clipping rectangle for future drawing updates
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pRect: Rectangular region to constrain edits
///
/// \return true if success, false if error
///
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
// -----------------------------------------------------------------------
// Font handling Functions
// -----------------------------------------------------------------------
///
/// Load a font from a resource and return pointer to it
///
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_PTR for Arduino)
/// \param[in] pvFontRef: Font reference pointer (Pointer to the GFXFont array)
/// \param[in] nFontSz: Typeface size to use
///
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
///
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
///
/// Release all fonts defined in the GUI
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
///
/// Get the extent (width and height) of a text string
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pFont: Ptr to Font structure
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[out] pnTxtX: Ptr to offset X of text
/// \param[out] pnTxtY: Ptr to offset Y of text
/// \param[out] pnTxtSzW: Ptr to width of text
/// \param[out] pnTxtSzH: Ptr to height of text
///
/// \return true if success, false if failure
///
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
///
/// Draw a text string at the given coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nTxtX: X coordinate of top-left text string
/// \param[in] nTxtY: Y coordinate of top-left text string
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: unused in ADAGFX, defaults to black
///
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
// -----------------------------------------------------------------------
// Screen Management Functions
// -----------------------------------------------------------------------
///
/// Force a page flip to occur. This generally copies active
/// screen surface to the display.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Graphics Primitives Functions
// -----------------------------------------------------------------------
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: X coordinate of point
/// \param[in] nY: Y coordinate of point
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] asPt: Array of points to draw
/// \param[in] nNumPt: Number of points in array
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
///
/// Draw a framed rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a filled rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a framed rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a line
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: Line start (X coordinate)
/// \param[in] nY0: Line start (Y coordinate)
/// \param[in] nX1: Line finish (X coordinate)
/// \param[in] nY1: Line finish (Y coordinate)
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
///
/// Draw a framed circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a framed triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Draw a filled triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Copy all of source image to destination screen at specified coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
///
/// Draw a monochrome bitmap from a memory array
/// - Draw from the bitmap buffer using the foreground color
/// defined in the header (unset bits are transparent)
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
///
/// Draw a color 24-bit depth bitmap from a memory array
/// - Note that users must convert images from their native
/// format (eg. BMP, PNG, etc.) into a C array. Please
/// refer to the following guide for details:
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
/// - The converted file (c array) can then be included in the sketch.
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: X coord for copy
/// \param[in] nDstY: Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
///
/// Copy the background image to destination screen
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Touch Functions (if using display driver library)
// -----------------------------------------------------------------------
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the internal touch handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
// -----------------------------------------------------------------------
// Touch Functions (if using external touch driver library)
// -----------------------------------------------------------------------
// Check for deprecated config option
// - This check will be removed in future releases
#if defined(DRV_TOUCH_XPT2046)
#error "NOTE: DRV_TOUCH_XPT2046 has been renamed to DRV_TOUCH_XPT2046_STM. Please update your config."
#endif
#if defined(DRV_TOUCH_TYPE_EXTERNAL)
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the SDL_Event handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
#endif // DRV_TOUCH_*
// -----------------------------------------------------------------------
// Dynamic Screen rotation and Touch axes swap/flip functions
// -----------------------------------------------------------------------
///
/// Change rotation, automatically adapt touchscreen axes swap/flip
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
///
/// \return true if successful
///
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
// =======================================================================
// Private Functions
// - These functions are not included in the scope of APIs used by
// the core GUIslice library. Instead, these functions are used
// to support the operations within this driver layer.
// =======================================================================
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_DRV_ADAGFX_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,656 @@
#ifndef _GUISLICE_DRV_M5STACK_H_
#define _GUISLICE_DRV_M5STACK_H_
// =======================================================================
// GUIslice library (driver layer for m5stack/M5Stack)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file GUIslice_drv_m5stack.h
/// \brief GUIslice library (driver layer for M5stack)
// =======================================================================
// Driver Layer for m5stack/M5Stack
// - https://github.com/m5stack/M5Stack
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "GUIslice.h"
#include <stdio.h>
// ------------------------------------------------------------------------
// Error Strings
// ------------------------------------------------------------------------
extern const char GSLC_PMEM ERRSTR_NULL[];
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
// =======================================================================
// API support definitions
// - These defines indicate whether the driver includes optimized
// support for various APIs. If a define is set to 0, then the
// GUIslice core emulation will be used instead.
// - At the very minimum, the point draw routine must be available:
// gslc_DrvDrawPoint()
// =======================================================================
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
#define DRV_HAS_DRAW_TRI_FRAME 1 ///< Support gslc_DrvDrawFrameTriangle()
#define DRV_HAS_DRAW_TRI_FILL 1 ///< Support gslc_DrvDrawFillTriangle()
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
#define DRV_OVERRIDE_TXT_ALIGN 1 ///< Driver provides text alignment
// =======================================================================
// Driver-specific members
// =======================================================================
typedef struct {
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
gslc_tsRect rClipRect; ///< Clipping rectangle
} gslc_tsDriver;
// =======================================================================
// Public APIs to GUIslice core library
// - These functions define the renderer / driver-dependent
// implementations for the core drawing operations within
// GUIslice.
// =======================================================================
// -----------------------------------------------------------------------
// Configuration Functions
// -----------------------------------------------------------------------
///
/// Initialize the SDL library
/// - Performs clean startup workaround (if enabled)
/// - Configures video mode
/// - Initializes font support
///
/// PRE:
/// - The environment variables should be configured before
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
/// or manually in user function.
///
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
bool gslc_DrvInit(gslc_tsGui* pGui);
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
///
/// Free up any members associated with the driver
/// - Eg. renderers, windows, background surfaces, etc.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvDestruct(gslc_tsGui* pGui);
///
/// Get the display driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
///
/// Get the touch driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
///
/// Get the native display driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the display driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
///
/// Get the native touch driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the touch driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Image/surface handling Functions
// -----------------------------------------------------------------------
///
/// Load a bitmap (*.bmp) and create a new image resource.
/// Transparency is enabled by GSLC_BMP_TRANS_EN
/// through use of color (GSLC_BMP_TRANS_RGB).
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return Image pointer (surface/texture) or NULL if error
///
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a bitmap image
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a solid color
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nCol: RGB Color to use
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
///
/// Set an element's normal-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Set an element's glow-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Release an image surface
///
/// \param[in] pvImg: Void ptr to image
///
/// \return none
///
void gslc_DrvImageDestruct(void* pvImg);
///
/// Set the clipping rectangle for future drawing updates
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pRect: Rectangular region to constrain edits
///
/// \return true if success, false if error
///
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
// -----------------------------------------------------------------------
// Font handling Functions
// -----------------------------------------------------------------------
///
/// Load a font from a resource and return pointer to it
///
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_PTR for Arduino)
/// \param[in] pvFontRef: Font reference pointer (Pointer to the GFXFont array)
/// \param[in] nFontSz: Typeface size to use
///
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
///
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
///
/// Release all fonts defined in the GUI
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
///
/// Get the extent (width and height) of a text string
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pFont: Ptr to Font structure
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[out] pnTxtX: Ptr to offset X of text
/// \param[out] pnTxtY: Ptr to offset Y of text
/// \param[out] pnTxtSzW: Ptr to width of text
/// \param[out] pnTxtSzH: Ptr to height of text
///
/// \return true if success, false if failure
///
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
///
/// Draw a text string at the given coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nTxtX: X coordinate of top-left text string
/// \param[in] nTxtY: Y coordinate of top-left text string
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: unused in m5stack, defaults to black
///
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
///
/// Draw a text string in a bounding box using the specified alignment
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X coordinate of top-left of bounding box
/// \param[in] nY0: Y coordinate of top-left of bounding box
/// \param[in] nX1: X coordinate of bot-right of bounding box
/// \param[in] nY1: Y coordinate of bot-right of bounding box
/// \param[in] eTxtAlign: Alignment mode]
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: unused in m5stack, defaults to black
///
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxtAlign(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,int8_t eTxtAlign,
gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
// -----------------------------------------------------------------------
// Screen Management Functions
// -----------------------------------------------------------------------
///
/// Force a page flip to occur. This generally copies active
/// screen surface to the display.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Graphics Primitives Functions
// -----------------------------------------------------------------------
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: X coordinate of point
/// \param[in] nY: Y coordinate of point
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] asPt: Array of points to draw
/// \param[in] nNumPt: Number of points in array
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
///
/// Draw a framed rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a filled rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a framed rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a line
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: Line start (X coordinate)
/// \param[in] nY0: Line start (Y coordinate)
/// \param[in] nX1: Line finish (X coordinate)
/// \param[in] nY1: Line finish (Y coordinate)
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
///
/// Draw a framed circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a framed triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Draw a filled triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Copy all of source image to destination screen at specified coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
///
/// Draw a monochrome bitmap from a memory array
/// - Draw from the bitmap buffer using the foreground color
/// defined in the header (unset bits are transparent)
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
///
/// Draw a color 24-bit depth bitmap from a memory array
/// - Note that users must convert images from their native
/// format (eg. BMP, PNG, etc.) into a C array. Please
/// refer to the following guide for details:
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
/// - The converted file (c array) can then be included in the sketch.
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: X coord for copy
/// \param[in] nDstY: Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
///
/// Copy the background image to destination screen
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Touch Functions (if using display driver library)
// -----------------------------------------------------------------------
#if defined(DRV_TOUCH_IN_DISP)
// Use M5stack's integrated button handler
///
/// Perform any touch-specific initialization
/// - This function doesn't do anything in M5stack
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the internal button handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event (UNUSED)
/// \param[out] pnY: Ptr to Y coordinate of last touch event (UNUSED)
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch) (UNUSED)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
#endif // DRV_TOUCH_IN_DISP
// -----------------------------------------------------------------------
// Dynamic Screen rotation and Touch axes swap/flip functions
// -----------------------------------------------------------------------
///
/// Change rotation, automatically adapt touchscreen axes swap/flip
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
///
/// \return true if successful
///
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
// =======================================================================
// Private Functions
// - These functions are not included in the scope of APIs used by
// the core GUIslice library. Instead, these functions are used
// to support the operations within this driver layer.
// =======================================================================
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_DRV_M5STACK_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,722 @@
#ifndef _GUISLICE_DRV_SDL_H_
#define _GUISLICE_DRV_SDL_H_
// =======================================================================
// GUIslice library (driver layer for SDL 1.2 & 2.0)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file GUIslice_drv_sdl.h
/// \brief GUIslice library (driver layer for LINUX / SDL)
// =======================================================================
// Driver Layer for SDL
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "GUIslice.h"
#include <stdio.h>
#if defined(DRV_DISP_SDL1)
#include <SDL/SDL.h>
#include <SDL/SDL_getenv.h>
#include <SDL/SDL_ttf.h>
#endif
#if defined(DRV_DISP_SDL2)
#include <SDL2/SDL.h>
#include <SDL2/SDL_ttf.h>
#endif
// Includes for optional tslib touch handling
#if defined(DRV_TOUCH_TSLIB)
#include "tslib.h"
#endif
// =======================================================================
// API support definitions
// - These defines indicate whether the driver includes optimized
// support for various APIs. If a define is set to 0, then the
// GUIslice core emulation will be used instead.
// - At the very minimum, the point draw routine must be available:
// gslc_DrvDrawPoint()
// =======================================================================
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
#if defined(DRV_DISP_SDL1)
#define DRV_HAS_DRAW_POINTS 1 ///< Support gslc_DrvDrawPoints()
#define DRV_HAS_DRAW_LINE 0 ///< Support gslc_DrvDrawLine()
#define DRV_HAS_DRAW_RECT_FRAME 0 ///< Support gslc_DrvDrawFrameRect()
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0 ///< Support gslc_DrvDrawFrameRoundRect()
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0 ///< Support gslc_DrvDrawFillRoundRect()
#define DRV_HAS_DRAW_CIRCLE_FRAME 0 ///< Support gslc_DrvDrawFrameCircle()
#define DRV_HAS_DRAW_CIRCLE_FILL 0 ///< Support gslc_DrvDrawFillCircle()
#define DRV_HAS_DRAW_TRI_FRAME 0 ///< Support gslc_DrvDrawFrameTriangle()
#define DRV_HAS_DRAW_TRI_FILL 0 ///< Support gslc_DrvDrawFillTriangle()
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
#endif
#if defined(DRV_DISP_SDL2)
#define DRV_HAS_DRAW_POINTS 1 ///< Support gslc_DrvDrawPoints()
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 0 ///< Support gslc_DrvDrawFrameRoundRect()
#define DRV_HAS_DRAW_RECT_ROUND_FILL 0 ///< Support gslc_DrvDrawFillRoundRect()
#define DRV_HAS_DRAW_CIRCLE_FRAME 0 ///< Support gslc_DrvDrawFrameCircle()
#define DRV_HAS_DRAW_CIRCLE_FILL 0 ///< Support gslc_DrvDrawFillCircle()
#define DRV_HAS_DRAW_TRI_FRAME 0 ///< Support gslc_DrvDrawFrameTriangle()
#define DRV_HAS_DRAW_TRI_FILL 0 ///< Support gslc_DrvDrawFillTriangle()
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
#endif
#define DRV_OVERRIDE_TXT_ALIGN 0 ///< Driver provides text alignment
// =======================================================================
// Driver-specific members
// =======================================================================
typedef struct {
#if defined(DRV_DISP_SDL1)
SDL_Surface* pSurfScreen; ///< Surface ptr for screen
#endif
#if defined(DRV_DISP_SDL2)
SDL_Window* pWind; ///< SDL2 Window
SDL_Renderer* pRender; ///< SDL2 Rendering engine
#endif
#if defined(DRV_TOUCH_TSLIB)
struct tsdev* pTsDev; ///< Ptr to touchscreen device
#endif
} gslc_tsDriver;
// =======================================================================
// Public APIs to GUIslice core library
// - These functions define the renderer / driver-dependent
// implementations for the core drawing operations within
// GUIslice.
// =======================================================================
// -----------------------------------------------------------------------
// Configuration Functions
// -----------------------------------------------------------------------
///
/// Initialize the SDL library
/// - Performs clean startup workaround (if enabled)
/// - Configures video mode
/// - Initializes font support
///
/// PRE:
/// - The environment variables should be configured before
/// calling gslc_DrvInit().
///
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
bool gslc_DrvInit(gslc_tsGui* pGui);
///
/// Free up any members associated with the driver
/// - Eg. renderers, windows, background surfaces, etc.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvDestruct(gslc_tsGui* pGui);
///
/// Get the display driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
///
/// Get the touch driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
///
/// Get the native display driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the display driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
///
/// Get the native touch driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the touch driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Image/surface handling Functions
// -----------------------------------------------------------------------
///
/// Load a bitmap (*.bmp) and create a new image resource.
/// Transparency is enabled by GSLC_BMP_TRANS_EN
/// through use of color (GSLC_BMP_TRANS_RGB).
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return Image pointer (surface/texture/path) or NULL if error
///
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a bitmap image
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a solid color
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nCol: RGB Color to use
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
///
/// Set an element's normal-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Set an element's glow-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Release an image surface
///
/// \param[in] pvImg: Void ptr to image
///
/// \return none
///
void gslc_DrvImageDestruct(void* pvImg);
///
/// Set the clipping rectangle for future drawing updates
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pRect: Rectangular region to constrain edits
///
/// \return true if success, false if error
///
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
// -----------------------------------------------------------------------
// Font handling Functions
// -----------------------------------------------------------------------
///
/// Load a font from a resource and return pointer to it
///
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_FNAME for SDL)
/// \param[in] pvFontRef: Font reference pointer (Pointer to the font filename)
/// \param[in] nFontSz: Typeface size to use
///
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
///
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
///
/// Release all fonts defined in the GUI
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
///
/// Get the extent (width and height) of a text string
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pFont: Ptr to Font structure
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[out] pnTxtX: Ptr to offset X of text
/// \param[out] pnTxtY: Ptr to offset Y of text
/// \param[out] pnTxtSzW: Ptr to width of text
/// \param[out] pnTxtSzH: Ptr to height of text
///
/// \return true if success, false if failure
///
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
///
/// Draw a text string at the given coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nTxtX: X coordinate of top-left text string
/// \param[in] nTxtY: Y coordinate of top-left text string
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: unused in SDL, defaults to black
///
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
// -----------------------------------------------------------------------
// Screen Management Functions
// -----------------------------------------------------------------------
///
/// Force a page flip to occur. This generally copies active
/// screen surface to the display.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Graphics Primitives Functions
// -----------------------------------------------------------------------
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: X coordinate of point
/// \param[in] nY: Y coordinate of point
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] asPt: Array of points to draw
/// \param[in] nNumPt: Number of points in array
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
///
/// Draw a framed rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a filled rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a line
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: Line start (X coordinate)
/// \param[in] nY0: Line start (Y coordinate)
/// \param[in] nX1: Line finish (X coordinate)
/// \param[in] nY1: Line finish (Y coordinate)
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
// TODO: Add DrvDrawFrameCircle()
// TODO: Add DrvDrawFillCircle()
// TODO: Add DrvDrawFrameTriangle()
// TODO: Add DrvDrawFillTriangle()
///
/// Copy all of source image to destination screen at specified coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
// TODO: Add DrvDrawMonoFromMem()
// TODO: Add DrvDrawBmp24FromMem()
///
/// Copy the background image to destination screen
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Touch Functions
// -----------------------------------------------------------------------
///
/// Get the last touch event from the SDL_Event handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
// -----------------------------------------------------------------------
// Dynamic Screen rotation and Touch axes swap/flip functions
// -----------------------------------------------------------------------
///
/// Change rotation, automatically adapt touchscreen axes swap/flip
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
///
/// \return true if successful
///
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
// =======================================================================
// Private Functions
// - These functions are not included in the scope of APIs used by
// the core GUIslice library. Instead, these functions are used
// to support the operations within this driver layer.
// =======================================================================
// -----------------------------------------------------------------------
// Private Configuration Functions
// -----------------------------------------------------------------------
///
/// Ensure SDL initializes cleanly to workaround
/// possible issues if previous SDL application
/// failed to close down gracefully.
///
/// \param[in] sTTY: Terminal device (eg. "/dev/tty0")
///
/// \return true if success
///
bool gslc_DrvCleanStart(const char* sTTY);
///
/// Report driver debug info (before initialization)
///
/// \return none
///
void gslc_DrvReportInfoPre();
///
/// Report driver debug info (after initialization)
///
/// \return none
///
void gslc_DrvReportInfoPost();
// -----------------------------------------------------------------------
// Private Conversion Functions
// -----------------------------------------------------------------------
///
/// Translate a gslc_tsRect into an SDL_Rect
///
/// \param[in] rRect: gslc_tsRect
///
/// \return Converted SDL_Rect
///
SDL_Rect gslc_DrvAdaptRect(gslc_tsRect rRect);
///
/// Translate a gslc_tsColor into an SDL_Color
///
/// \param[in] sCol: gslc_tsColor
///
/// \return Converted SDL_Color
///
SDL_Color gslc_DrvAdaptColor(gslc_tsColor sCol);
// -----------------------------------------------------------------------
// Private Drawing Functions
// -----------------------------------------------------------------------
#if defined(DRV_DISP_SDL1)
///
/// Lock an SDL surface so that direct pixel manipulation
/// can be done safely. This function is called before any
/// direct pixel updates.
///
/// POST:
/// - Primary screen surface is locked
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false otherwise
///
bool gslc_DrvScreenLock(gslc_tsGui* pGui);
///
/// Unlock the SDL surface after pixel manipulation is
/// complete. This function is called after all pixel updates
/// are done.
///
/// POST:
/// - Primary screen surface is unlocked
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvScreenUnlock(gslc_tsGui* pGui);
///
/// Convert an RGB color triplet into the surface pixel value.
/// This is called to produce the native pixel value required by
/// the raw pixel manipulation routines.
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nCol: RGB value for conversion
///
/// \return A pixel value for the current screen format
///
uint32_t gslc_DrvAdaptColorRaw(gslc_tsGui* pGui,gslc_tsColor nCol);
///
/// Get the pixel at (X,Y) from the active screen
///
/// PRE:
/// - Screen surface must be locked
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: Pixel X coordinate
/// \param[in] nY: Pixel Y coordinate
///
/// \return Pixel color value from the coordinate or 0 if error
///
uint32_t gslc_DrvDrawGetPixelRaw(gslc_tsGui* pGui,int16_t nX,int16_t nY);
///
/// Set a pixel on the active screen to the given color
///
/// PRE:
/// - Screen surface must be locked
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: Pixel X coordinate to set
/// \param[in] nY: Pixel Y coordinate to set
/// \param[in] nPixelCol: Raw color pixel value to assign
///
/// \return none
///
void gslc_DrvDrawSetPixelRaw(gslc_tsGui* pGui,int16_t nX,int16_t nY,uint32_t nPixelCol);
///
/// Copy one image region to another.
/// - This is typically used to copy an image to the main screen surface
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: Destination X coordinate of copy
/// \param[in] nY: Destination Y coordinate of copy
/// \param[in] pvSrc: Void Ptr to source surface (eg. a loaded image)
/// \param[in] pvDest: Void Ptr to destination surface (typically the screen)
///
/// \return none
///
void gslc_DrvPasteSurface(gslc_tsGui* pGui,int16_t nX, int16_t nY, void* pvSrc, void* pvDest);
#endif // DRV_DISP_SDL1
// -----------------------------------------------------------------------
// Private Touchscreen Functions (if using SDL)
// -----------------------------------------------------------------------
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
// -----------------------------------------------------------------------
// Touchscreen Functions (if using tslib)
// -----------------------------------------------------------------------
#if defined(DRV_TOUCH_TSLIB)
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the tslib handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, >0 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return non-zero if an event was detected or 0 otherwise
///
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
#endif // DRV_TOUCH_TSLIB
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_DRV_SDL_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,755 @@
#ifndef _GUISLICE_DRV_TFT_ESPI_H_
#define _GUISLICE_DRV_TFT_ESPI_H_
// =======================================================================
// GUIslice library (driver layer for bodmer/TFT_eSPI)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file GUIslice_drv_tft_espi.h
/// \brief GUIslice library (driver layer for TFT-eSPI)
// =======================================================================
// Driver Layer for bodmer/TFT_eSPI
// - https://github.com/Bodmer/TFT_eSPI
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "GUIslice.h"
#include <stdio.h>
// Determine characteristics for configured touch driver
// - DRV_TOUCH_TYPE_EXTERNAL: TDrv* external touch APIs are enabled
// - DRV_TOUCH_TYPE_RES: Resistive overlay
// - DRV_TOUCH_TYPE_CAP: Capacitive overlay
// - DRV_TOUCH_TYPE_ANALOG: Analog input
#if defined(DRV_TOUCH_ADA_STMPE610)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_ADA_FT6206)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_CAP // Capacitive
#elif defined(DRV_TOUCH_ADA_SIMPLE)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#define DRV_TOUCH_TYPE_ANALOG // Analog
#elif defined(DRV_TOUCH_XPT2046_STM)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_XPT2046_PS)
#define DRV_TOUCH_TYPE_EXTERNAL
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_TFT_ESPI)
#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_INPUT)
#define DRV_TOUCH_TYPE_EXTERNAL
#elif defined(DRV_TOUCH_HANDLER)
#define DRV_TOUCH_TYPE_EXTERNAL
#elif defined(DRV_TOUCH_NONE)
#endif // DRV_TOUCH_*
// Additional defines
// - Provide default if not in config file
#if !defined(GSLC_SPIFFS_EN)
#define GSLC_SPIFFS_EN 0
#endif // GSLC_SPIFFS_EN
// =======================================================================
// API support definitions
// - These defines indicate whether the driver includes optimized
// support for various APIs. If a define is set to 0, then the
// GUIslice core emulation will be used instead.
// - At the very minimum, the point draw routine must be available:
// gslc_DrvDrawPoint()
// =======================================================================
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
#define DRV_HAS_DRAW_TRI_FRAME 1 ///< Support gslc_DrvDrawFrameTriangle()
#define DRV_HAS_DRAW_TRI_FILL 1 ///< Support gslc_DrvDrawFillTriangle()
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
#define DRV_OVERRIDE_TXT_ALIGN 1 ///< Driver provides text alignment
// =======================================================================
// Driver-specific members
// =======================================================================
typedef struct {
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
gslc_tsRect rClipRect; ///< Clipping rectangle
} gslc_tsDriver;
// =======================================================================
// Public APIs to GUIslice core library
// - These functions define the renderer / driver-dependent
// implementations for the core drawing operations within
// GUIslice.
// =======================================================================
// -----------------------------------------------------------------------
// Configuration Functions
// -----------------------------------------------------------------------
///
/// Initialize the SDL library
/// - Performs clean startup workaround (if enabled)
/// - Configures video mode
/// - Initializes font support
///
/// PRE:
/// - The environment variables should be configured before
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
/// or manually in user function.
///
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
bool gslc_DrvInit(gslc_tsGui* pGui);
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
///
/// Free up any members associated with the driver
/// - Eg. renderers, windows, background surfaces, etc.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvDestruct(gslc_tsGui* pGui);
///
/// Get the display driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
///
/// Get the touch driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
///
/// Get the native display driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the display driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
///
/// Get the native touch driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the touch driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Image/surface handling Functions
// -----------------------------------------------------------------------
///
/// Load a bitmap (*.bmp) and create a new image resource.
/// Transparency is enabled by GSLC_BMP_TRANS_EN
/// through use of color (GSLC_BMP_TRANS_RGB).
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return Image pointer (surface/texture) or NULL if error
///
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a bitmap image
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a solid color
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nCol: RGB Color to use
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
///
/// Set an element's normal-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Set an element's glow-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Release an image surface
///
/// \param[in] pvImg: Void ptr to image
///
/// \return none
///
void gslc_DrvImageDestruct(void* pvImg);
///
/// Set the clipping rectangle for future drawing updates
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pRect: Rectangular region to constrain edits
///
/// \return true if success, false if error
///
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
// -----------------------------------------------------------------------
// Font handling Functions
// -----------------------------------------------------------------------
///
/// Load a font from a resource and return pointer to it
///
/// \param[in] eFontRefType: Font reference type:
/// - GSLC_FONTREF_PTR for Standard TFT_eSPI Fonts
/// - GSLC_FONTREF_FNAME for antialiased Font in SPIFFS
/// \param[in] pvFontRef: Font reference pointer / SPIFFS font filename without ext.
/// \param[in] nFontSz: Typeface size to use, ignored for SPIFFS font
///
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
///
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
///
/// Release all fonts defined in the GUI
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
///
/// Get the extent (width and height) of a text string
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pFont: Ptr to Font structure
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[out] pnTxtX: Ptr to offset X of text
/// \param[out] pnTxtY: Ptr to offset Y of text
/// \param[out] pnTxtSzW: Ptr to width of text
/// \param[out] pnTxtSzH: Ptr to height of text
///
/// \return true if success, false if failure
///
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
///
/// Draw a text string at the given coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nTxtX: X coordinate of top-left text string
/// \param[in] nTxtY: Y coordinate of top-left text string
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: Color of Background for antialias blending
///
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
///
/// Draw a text string in a bounding box using the specified alignment
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X coordinate of top-left of bounding box
/// \param[in] nY0: Y coordinate of top-left of bounding box
/// \param[in] nX1: X coordinate of bot-right of bounding box
/// \param[in] nY1: Y coordinate of bot-right of bounding box
/// \param[in] eTxtAlign: Alignment mode]
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: Color of Background for antialias blending
//
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxtAlign(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,int8_t eTxtAlign,
gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
// -----------------------------------------------------------------------
// Screen Management Functions
// -----------------------------------------------------------------------
///
/// Force a page flip to occur. This generally copies active
/// screen surface to the display.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Graphics Primitives Functions
// -----------------------------------------------------------------------
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: X coordinate of point
/// \param[in] nY: Y coordinate of point
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] asPt: Array of points to draw
/// \param[in] nNumPt: Number of points in array
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
///
/// Draw a framed rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a filled rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a framed rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a line
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: Line start (X coordinate)
/// \param[in] nY0: Line start (Y coordinate)
/// \param[in] nX1: Line finish (X coordinate)
/// \param[in] nY1: Line finish (Y coordinate)
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
///
/// Draw a framed circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a framed triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Draw a filled triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Copy all of source image to destination screen at specified coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
///
/// Draw a monochrome bitmap from a memory array
/// - Draw from the bitmap buffer using the foreground color
/// defined in the header (unset bits are transparent)
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
///
/// Draw a color 24-bit depth bitmap from a memory array
/// - Note that users must convert images from their native
/// format (eg. BMP, PNG, etc.) into a C array. Please
/// refer to the following guide for details:
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
/// - The converted file (c array) can then be included in the sketch.
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: X coord for copy
/// \param[in] nDstY: Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
#if (GSLC_SPIFFS_EN)
///
/// This routine uses TFT_eFEX library to draw a BMP file stored in SPIFFS file system
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawBmpFromFile(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
///
/// This routine uses TFT_eFEX library to draw a JPEG file stored in SPIFFS file system
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawJpegFromFile(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
#endif // end GSLC_SPIFFS_EN
///
/// Copy the background image to destination screen
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Touch Functions (if using display driver library)
// -----------------------------------------------------------------------
#if defined(DRV_TOUCH_IN_DISP)
// Use TFT_eSPI's integrated XPT2046 touch driver
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the internal XPT2046 touch handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
#endif // DRV_TOUCH_IN_DISP
// -----------------------------------------------------------------------
// Touch Functions (if using external touch driver library)
// -----------------------------------------------------------------------
// Check for deprecated config option
// - This check will be removed in future releases
#if defined(DRV_TOUCH_XPT2046)
#error "NOTE: DRV_TOUCH_XPT2046 has been renamed to DRV_TOUCH_XPT2046_STM. Please update your config."
#endif
#if defined(DRV_TOUCH_TYPE_EXTERNAL)
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the SDL_Event handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
#endif // DRV_TOUCH_*
// -----------------------------------------------------------------------
// Dynamic Screen rotation and Touch axes swap/flip functions
// -----------------------------------------------------------------------
///
/// Change rotation, automatically adapt touchscreen axes swap/flip
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
///
/// \return true if successful
///
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
// =======================================================================
// Private Functions
// - These functions are not included in the scope of APIs used by
// the core GUIslice library. Instead, these functions are used
// to support the operations within this driver layer.
// =======================================================================
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_DRV_TFT_ESPI_H_

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,672 @@
#ifndef _GUISLICE_DRV_UTFT_H_
#define _GUISLICE_DRV_UTFT_H_
// =======================================================================
// GUIslice library (driver layer for UTFT)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file GUIslice_drv_utft.h
/// \brief GUIslice library (driver layer for UTFT)
// =======================================================================
// Driver Layer for UTFT
// =======================================================================
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
#include "GUIslice.h"
#include <stdio.h>
// Determine characteristics for configured touch driver
// - DRV_TOUCH_TYPE_EXTERNAL: TDrv* external touch APIs are enabled
// - DRV_TOUCH_TYPE_RES: Resistive overlay
// - DRV_TOUCH_TYPE_CAP: Capacitive overlay
// - DRV_TOUCH_TYPE_ANALOG: Analog input
#if defined(DRV_TOUCH_URTOUCH)
#define DRV_TOUCH_TYPE_EXTERNAL
// Don't set DRV_TOUCH_TYPE_RES since URTouch provides its own calibration
//#define DRV_TOUCH_TYPE_RES // Resistive
#elif defined(DRV_TOUCH_INPUT)
#define DRV_TOUCH_TYPE_EXTERNAL
#elif defined(DRV_TOUCH_NONE)
#endif // DRV_TOUCH_*
// =======================================================================
// API support definitions
// - These defines indicate whether the driver includes optimized
// support for various APIs. If a define is set to 0, then the
// GUIslice core emulation will be used instead.
// - At the very minimum, the point draw routine must be available:
// gslc_DrvDrawPoint()
// =======================================================================
#define DRV_HAS_DRAW_POINT 1 ///< Support gslc_DrvDrawPoint()
#define DRV_HAS_DRAW_POINTS 0 ///< Support gslc_DrvDrawPoints()
#define DRV_HAS_DRAW_LINE 1 ///< Support gslc_DrvDrawLine()
#define DRV_HAS_DRAW_RECT_FRAME 1 ///< Support gslc_DrvDrawFrameRect()
#define DRV_HAS_DRAW_RECT_FILL 1 ///< Support gslc_DrvDrawFillRect()
#define DRV_HAS_DRAW_RECT_ROUND_FRAME 1 ///< Support gslc_DrvDrawFrameRoundRect()
#define DRV_HAS_DRAW_RECT_ROUND_FILL 1 ///< Support gslc_DrvDrawFillRoundRect()
#define DRV_HAS_DRAW_CIRCLE_FRAME 1 ///< Support gslc_DrvDrawFrameCircle()
#define DRV_HAS_DRAW_CIRCLE_FILL 1 ///< Support gslc_DrvDrawFillCircle()
#define DRV_HAS_DRAW_TRI_FRAME 0 ///< Support gslc_DrvDrawFrameTriangle()
#define DRV_HAS_DRAW_TRI_FILL 0 ///< Support gslc_DrvDrawFillTriangle()
#define DRV_HAS_DRAW_TEXT 1 ///< Support gslc_DrvDrawTxt()
#define DRV_HAS_DRAW_BMP_MEM 0 ///< Support gslc_DrvDrawBmp24FromMem()
#define DRV_OVERRIDE_TXT_ALIGN 0 ///< Driver provides text alignment
// =======================================================================
// Driver-specific members
// =======================================================================
typedef struct {
gslc_tsColor nColBkgnd; ///< Background color (if not image-based)
gslc_tsRect rClipRect; ///< Clipping rectangle
} gslc_tsDriver;
// =======================================================================
// Public APIs to GUIslice core library
// - These functions define the renderer / driver-dependent
// implementations for the core drawing operations within
// GUIslice.
// =======================================================================
// -----------------------------------------------------------------------
// Configuration Functions
// -----------------------------------------------------------------------
///
/// Initialize the SDL library
/// - Performs clean startup workaround (if enabled)
/// - Configures video mode
/// - Initializes font support
///
/// PRE:
/// - The environment variables should be configured before
/// calling gslc_DrvInit(). This can be done with gslc_DrvInitEnv()
/// or manually in user function.
///
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
bool gslc_DrvInit(gslc_tsGui* pGui);
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTs(gslc_tsGui* pGui,const char* acDev);
///
/// Free up any members associated with the driver
/// - Eg. renderers, windows, background surfaces, etc.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvDestruct(gslc_tsGui* pGui);
///
/// Get the display driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameDisp(gslc_tsGui* pGui);
///
/// Get the touch driver name
///
/// \param[in] pGui: Pointer to GUI
///
/// \return String containing driver name
///
const char* gslc_DrvGetNameTouch(gslc_tsGui* pGui);
///
/// Get the native display driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the display driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverDisp(gslc_tsGui* pGui);
///
/// Get the native touch driver instance
/// - This can be useful to access special commands
/// available in the selected driver.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return Void pointer to the touch driver instance.
/// This pointer should be typecast to the particular
/// driver being used. If no driver was created then
/// this function will return NULL.
///
void* gslc_DrvGetDriverTouch(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Image/surface handling Functions
// -----------------------------------------------------------------------
///
/// Load a bitmap (*.bmp) and create a new image resource.
/// Transparency is enabled by GSLC_BMP_TRANS_EN
/// through use of color (GSLC_BMP_TRANS_RGB).
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return Image pointer (surface/texture) or NULL if error
///
void* gslc_DrvLoadImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a bitmap image
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndImage(gslc_tsGui* pGui,gslc_tsImgRef sImgRef);
///
/// Configure the background to use a solid color
/// - The background is used when redrawing the entire page
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nCol: RGB Color to use
///
/// \return true if success, false if fail
///
bool gslc_DrvSetBkgndColor(gslc_tsGui* pGui,gslc_tsColor nCol);
///
/// Set an element's normal-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageNorm(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Set an element's glow-state image
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElem: Pointer to Element to update
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if error
///
bool gslc_DrvSetElemImageGlow(gslc_tsGui* pGui,gslc_tsElem* pElem,gslc_tsImgRef sImgRef);
///
/// Release an image surface
///
/// \param[in] pvImg: Void ptr to image
///
/// \return none
///
void gslc_DrvImageDestruct(void* pvImg);
///
/// Set the clipping rectangle for future drawing updates
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pRect: Rectangular region to constrain edits
///
/// \return true if success, false if error
///
bool gslc_DrvSetClipRect(gslc_tsGui* pGui,gslc_tsRect* pRect);
// -----------------------------------------------------------------------
// Font handling Functions
// -----------------------------------------------------------------------
///
/// Load a font from a resource and return pointer to it
///
/// \param[in] eFontRefType: Font reference type (GSLC_FONTREF_PTR for Arduino)
/// \param[in] pvFontRef: Font reference pointer (Pointer to the GFXFont array)
/// \param[in] nFontSz: Typeface size to use
///
/// \return Void ptr to driver-specific font if load was successful, NULL otherwise
///
const void* gslc_DrvFontAdd(gslc_teFontRefType eFontRefType,const void* pvFontRef,uint16_t nFontSz);
///
/// Release all fonts defined in the GUI
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvFontsDestruct(gslc_tsGui* pGui);
///
/// Get the extent (width and height) of a text string
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pFont: Ptr to Font structure
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[out] pnTxtX: Ptr to offset X of text
/// \param[out] pnTxtY: Ptr to offset Y of text
/// \param[out] pnTxtSzW: Ptr to width of text
/// \param[out] pnTxtSzH: Ptr to height of text
///
/// \return true if success, false if failure
///
bool gslc_DrvGetTxtSize(gslc_tsGui* pGui,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,
int16_t* pnTxtX,int16_t* pnTxtY,uint16_t* pnTxtSzW,uint16_t* pnTxtSzH);
///
/// Draw a text string at the given coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nTxtX: X coordinate of top-left text string
/// \param[in] nTxtY: Y coordinate of top-left text string
/// \param[in] pFont: Ptr to Font
/// \param[in] pStr: String to display
/// \param[in] eTxtFlags: Flags associated with text string
/// \param[in] colTxt: Color to draw text
/// \param[in] colBg: unused in ADAGFX, defaults to black
///
/// \return true if success, false if failure
///
bool gslc_DrvDrawTxt(gslc_tsGui* pGui,int16_t nTxtX,int16_t nTxtY,gslc_tsFont* pFont,const char* pStr,gslc_teTxtFlags eTxtFlags,gslc_tsColor colTxt,gslc_tsColor colBg);
// -----------------------------------------------------------------------
// Screen Management Functions
// -----------------------------------------------------------------------
///
/// Force a page flip to occur. This generally copies active
/// screen surface to the display.
///
/// \param[in] pGui: Pointer to GUI
///
/// \return none
///
void gslc_DrvPageFlipNow(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Graphics Primitives Functions
// -----------------------------------------------------------------------
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX: X coordinate of point
/// \param[in] nY: Y coordinate of point
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoint(gslc_tsGui* pGui,int16_t nX,int16_t nY,gslc_tsColor nCol);
///
/// Draw a point
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] asPt: Array of points to draw
/// \param[in] nNumPt: Number of points in array
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawPoints(gslc_tsGui* pGui,gslc_tsPt* asPt,uint16_t nNumPt,gslc_tsColor nCol);
///
/// Draw a framed rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a filled rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRect(gslc_tsGui* pGui,gslc_tsRect rRect,gslc_tsColor nCol);
///
/// Draw a framed rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to frame
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled rounded rectangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] rRect: Rectangular region to fill
/// \param[in] nRadius: Radius for rounded corners
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillRoundRect(gslc_tsGui* pGui,gslc_tsRect rRect,int16_t nRadius,gslc_tsColor nCol);
///
/// Draw a line
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: Line start (X coordinate)
/// \param[in] nY0: Line start (Y coordinate)
/// \param[in] nX1: Line finish (X coordinate)
/// \param[in] nY1: Line finish (Y coordinate)
/// \param[in] nCol: Color RGB value to draw
///
/// \return true if success, false if error
///
bool gslc_DrvDrawLine(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,int16_t nX1,int16_t nY1,gslc_tsColor nCol);
///
/// Draw a framed circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a filled circle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nMidX: Center of circle (X coordinate)
/// \param[in] nMidY: Center of circle (Y coordinate)
/// \param[in] nRadius: Radius of circle
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillCircle(gslc_tsGui* pGui,int16_t nMidX,int16_t nMidY,uint16_t nRadius,gslc_tsColor nCol);
///
/// Draw a framed triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to frame
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFrameTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Draw a filled triangle
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nX0: X Coordinate #1
/// \param[in] nY0: Y Coordinate #1
/// \param[in] nX1: X Coordinate #2
/// \param[in] nY1: Y Coordinate #2
/// \param[in] nX2: X Coordinate #3
/// \param[in] nY2: Y Coordinate #3
/// \param[in] nCol: Color RGB value to fill
///
/// \return true if success, false if error
///
bool gslc_DrvDrawFillTriangle(gslc_tsGui* pGui,int16_t nX0,int16_t nY0,
int16_t nX1,int16_t nY1,int16_t nX2,int16_t nY2,gslc_tsColor nCol);
///
/// Copy all of source image to destination screen at specified coordinate
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] sImgRef: Image reference
///
/// \return true if success, false if fail
///
bool gslc_DrvDrawImage(gslc_tsGui* pGui,int16_t nDstX,int16_t nDstY,gslc_tsImgRef sImgRef);
///
/// Draw a monochrome bitmap from a memory array
/// - Draw from the bitmap buffer using the foreground color
/// defined in the header (unset bits are transparent)
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: Destination X coord for copy
/// \param[in] nDstY: Destination Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawMonoFromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY, const unsigned char *pBitmap,bool bProgMem);
///
/// Draw a color 24-bit depth bitmap from a memory array
/// - Note that users must convert images from their native
/// format (eg. BMP, PNG, etc.) into a C array. Please
/// refer to the following guide for details:
/// https://github.com/ImpulseAdventure/GUIslice/wiki/Display-Images-from-FLASH
/// - The converted file (c array) can then be included in the sketch.
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nDstX: X coord for copy
/// \param[in] nDstY: Y coord for copy
/// \param[in] pBitmap: Pointer to bitmap buffer
/// \param[in] bProgMem: Bitmap is stored in Flash if true, RAM otherwise
///
/// \return none
///
void gslc_DrvDrawBmp24FromMem(gslc_tsGui* pGui,int16_t nDstX, int16_t nDstY,const unsigned char* pBitmap,bool bProgMem);
///
/// Copy the background image to destination screen
///
/// \param[in] pGui: Pointer to GUI
///
/// \return true if success, false if fail
///
void gslc_DrvDrawBkgnd(gslc_tsGui* pGui);
// -----------------------------------------------------------------------
// Touch Functions (if using display driver library)
// -----------------------------------------------------------------------
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_DrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the internal touch handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_DrvGetTouch(gslc_tsGui* pGui,int16_t* pnX,int16_t* pnY,uint16_t* pnPress,gslc_teInputRawEvent* peInputEvent,int16_t* pnInputVal);
// -----------------------------------------------------------------------
// Touch Functions (if using external touch driver library)
// -----------------------------------------------------------------------
#if defined(DRV_TOUCH_TYPE_EXTERNAL)
///
/// Perform any touchscreen-specific initialization
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] acDev: Device path to touchscreen
/// eg. "/dev/input/touchscreen"
///
/// \return true if successful
///
bool gslc_TDrvInitTouch(gslc_tsGui* pGui,const char* acDev);
///
/// Get the last touch event from the SDL_Event handler
///
/// \param[in] pGui: Pointer to GUI
/// \param[out] pnX: Ptr to X coordinate of last touch event
/// \param[out] pnY: Ptr to Y coordinate of last touch event
/// \param[out] pnPress: Ptr to Pressure level of last touch event (0 for none, 1 for touch)
/// \param[out] peInputEvent Indication of event type
/// \param[out] pnInputVal Additional data for event type
///
/// \return true if an event was detected or false otherwise
///
bool gslc_TDrvGetTouch(gslc_tsGui* pGui, int16_t* pnX, int16_t* pnY, uint16_t* pnPress, gslc_teInputRawEvent* peInputEvent, int16_t* pnInputVal);
#endif // DRV_TOUCH_*
// -----------------------------------------------------------------------
// Dynamic Screen rotation and Touch axes swap/flip functions
// -----------------------------------------------------------------------
///
/// Change rotation, automatically adapt touchscreen axes swap/flip
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nRotation: Screen Rotation value (0, 1, 2 or 3)
///
/// \return true if successful
///
bool gslc_DrvRotate(gslc_tsGui* pGui, uint8_t nRotation);
// =======================================================================
// Private Functions
// - These functions are not included in the scope of APIs used by
// the core GUIslice library. Instead, these functions are used
// to support the operations within this driver layer.
// =======================================================================
uint16_t gslc_DrvAdaptColorToRaw(gslc_tsColor nCol);
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_DRV_ADAGFX_H_

View file

@ -0,0 +1,52 @@
#ifndef _GUISLICE_EX_H_
#define _GUISLICE_EX_H_
#include "GUIslice.h"
// =======================================================================
// GUIslice library (extensions)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file GUIslice_ex.h
// Provide backwards compatibility until we have removed GUIslice_ex
#include "XCheckbox.h"
#include "XGauge.h"
#include "XGraph.h"
#include "XSelNum.h"
#include "XSlider.h"
#include "XTextbox.h"
// Warn users that they should update their includes
// #warning "NOTE: Please replace `GUIslice_ex` per https://github.com/ImpulseAdventure/GUIslice/wiki/Note-_-Include-Extended-Elements"
#endif // _GUISLICE_EX_H_

View file

@ -0,0 +1,119 @@
// Abstract touch handler (TH) class
// This is the abstract base class for creating specific touch handlers
// The touch handler performs the adaption in between the GUIslice framework and any touch driver
// The touch handler used is specified in the main program by calling gslc_InitTouchHandler(&touchHandler);
/// \file GUIslice_th.cpp
#include "GUIslice_th.h"
///////////////////////////////////////////////////
// Point x,y,z Class for usage in the touch handler
THPoint::THPoint(void) {
x = y = z = 0;
}
THPoint::THPoint(uint16_t x0, uint16_t y0, uint16_t z0) {
x = x0;
y = y0;
z = z0;
}
bool THPoint::operator==(THPoint p1) {
return ((p1.x == x) && (p1.y == y) && (p1.z == z));
}
bool THPoint::operator!=(THPoint p1) {
return ((p1.x != x) || (p1.y != y) || (p1.z != z));
}
///////////////////////////////////////////////////
// Abstract TouchHandler - you have to inherit this
void TouchHandler::setSize(uint16_t _disp_xSize, uint16_t _disp_ySize)
{
disp_xSize = _disp_xSize;
disp_ySize = _disp_ySize;
}
void TouchHandler::setCalibration(uint16_t _ts_xMin, uint16_t _ts_xMax, uint16_t _ts_yMin, uint16_t _ts_yMax)
{
ts_xMin = _ts_xMin;
ts_xMax = _ts_xMax;
ts_yMin = _ts_yMin;
ts_yMax = _ts_yMax;
}
void TouchHandler::setSwapFlip(bool _swapXY,bool _flipX,bool _flipY)
{
swapXY = _swapXY;
flipX = _flipX;
flipY = _flipY;
}
THPoint TouchHandler::scale(THPoint pIn)
{
THPoint pOut;
pOut.x = map(pIn.x, ts_xMin,ts_xMax, 0,disp_xSize);
pOut.y = map(pIn.y, ts_yMin,ts_yMax, 0,disp_ySize);
pOut.z = pIn.z;
pOut.x = constrain(pOut.x,0,disp_xSize-1);
pOut.y = constrain(pOut.y,0,disp_ySize-1);
pOut.z = constrain(pOut.z,0,4095);
if (swapXY)
{
uint16_t x = pOut.x;
pOut.x = pOut.y;
pOut.y = x;
}
if (flipX)
pOut.x = ( (!swapXY) ? disp_xSize-1 : disp_ySize-1 ) - pOut.x;
if (flipY)
pOut.y = ( (!swapXY) ? disp_ySize-1 : disp_xSize-1 ) - pOut.y;
//Serial.print("disp_xSize= ");Serial.println(disp_xSize);
return pOut;
}
// overwrite this with your code to add initialisation of the touch driver used
void TouchHandler::begin(void) {
return;
}
// overwrite this with your code to return the scaled touch coordinates
THPoint TouchHandler::getPoint(void) {
return THPoint();
}
/////////////////////////////////
// init and set the touch handler
// Pointer to touch handler used by GUIslice
TouchHandler *pTouchHandler = NULL; // NULL => no handler is available
// Init and set the touch hander
void gslc_InitTouchHandler(TouchHandler *pTH) {
//begin
pTH->begin();
//set the touch handler to be used by GUIslice_drv_...
pTouchHandler = pTH;
}
// Get the touch handler
TouchHandler* gslc_getTouchHandler(void)
{
return pTouchHandler;
}

View file

@ -0,0 +1,71 @@
// Abstract touch handler (TH) class
// This is the abstract base class for creating specific touch handlers
// The touch handler performs the adaption in between the GUIslice framework and any touch driver
// The touch handler used is specified in the main program by calling gslc_InitTouchHandler(&touchHandler);
/// \file GUIslice_th.h
#ifndef _GUISLICE_TH_H_
#define _GUISLICE_TH_H_
#include <Arduino.h>
///////////////////////////////////////////////////
// Point x,y,z Class for usage in the touch handler
class THPoint {
public:
THPoint(void);
THPoint(uint16_t x, uint16_t y, uint16_t z);
bool operator==(THPoint);
bool operator!=(THPoint);
uint16_t x, y, z;
};
///////////////////////////////////////////////////
// Abstract TouchHandler - you have to inherit this
class TouchHandler {
public:
//in order to create a specific touch handler you have to write your own constructor
TouchHandler() {};
void setSize(uint16_t _disp_xSize, uint16_t _disp_ySize);
void setCalibration(uint16_t ts_xMin, uint16_t ts_xMax, uint16_t ts_yMin, uint16_t ts_yMax);
//order of operations: map, swap, constraint, flip
void setSwapFlip(bool _swapXY,bool _flipX,bool _flipY);
THPoint scale(THPoint pIn);
//in order to create a specific touch handler you have to overwrite this methods
virtual void begin(void);
virtual THPoint getPoint(void);
private:
//landscape perspective: x: width, y: heigth
uint16_t disp_xSize = 320;
uint16_t disp_ySize = 240;
uint16_t ts_xMin = 0;
uint16_t ts_xMax = 4095;
uint16_t ts_yMin = 0;
uint16_t ts_yMax = 4095;
bool swapXY = false;
bool flipX = false;
bool flipY = false;
};
/////////////////////////////////
// init and set the touch handler
void gslc_InitTouchHandler(TouchHandler *pTHO);
TouchHandler* gslc_getTouchHandler(void);
#endif

View file

@ -0,0 +1,52 @@
// touch handler (TH) for XPT2046 using the arduino built in driver <XPT2046_touch.h>
// The touch handler performs the adaption in between the GUIslice framework and any touch driver
// The touch handler used is specified in the main program by calling gslc_InitTouchHandler(&touchHandler);
/// \file GUIslice_th_XPT2046.h
#ifndef _GUISLICE_TH_XPT2046_H_
#define _GUISLICE_TH_XPT2046_H_
#include <Arduino.h>
#include <GUIslice_th.h>
#include <XPT2046_touch.h>
class TouchHandler_XPT2046: public TouchHandler {
public:
// parameters:
// spi object to be used
// chip select pin for spi
TouchHandler_XPT2046(SPIClass &spi, uint8_t spi_cs_pin) : spi(spi), touchDriver(XPT2046_touch(spi_cs_pin, spi)) {
//empirical calibration values, can be updated by calling setCalibration in the user program
setCalibration(398,3877,280,3805);
//swapping and flipping to adopt to default GUIslice orientation
setSwapFlip(true,false,true);
}
//begin is called by gslc_InitTouchHandler
void begin(void) {
//init the touch driver
touchDriver.begin();
}
//this method returns the scaled point provided by the touch driver
THPoint getPoint(void) {
//get the coordinates from the touch driver
TS_Point pt = touchDriver.getPoint();
//Serial.print("pt= ");Serial.print(pt.x);Serial.print(",");Serial.print(pt.y);Serial.print(",");Serial.println(pt.z);
//perform scaling (this includes swapping and flipping)
THPoint ps = scale( THPoint(pt.x,pt.y,pt.z) );
//Serial.print("ps= ");Serial.print(ps.x);Serial.print(",");Serial.print(ps.y);Serial.print(",");Serial.println(ps.z);
return ps;
};
SPIClass spi;
XPT2046_touch touchDriver;
};
#endif

View file

@ -0,0 +1,42 @@
#ifndef _GUISLICE_VERSION_H_
#define _GUISLICE_VERSION_H_
// =======================================================================
// GUIslice library (version control)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
// =======================================================================
// Define current release (X.Y.Z) & build number
// =======================================================================
#define GUISLICE_VER "0.15.0"
#endif // _GUISLICE_VERSION_H_

View file

@ -0,0 +1,219 @@
const uint8_t NotoMono10pt7bBitmaps[] PROGMEM = {
0x00, 0xFF, 0x6D, 0x92, 0x48, 0x6F, 0xC0, 0xCF, 0x3C, 0xF3, 0xCC, 0x0C,
0x60, 0xC6, 0x08, 0x40, 0x84, 0x7F, 0xF1, 0x8C, 0x10, 0x81, 0x08, 0x31,
0x8F, 0xFE, 0x21, 0x02, 0x10, 0x63, 0x06, 0x30, 0x08, 0x04, 0x0F, 0xCF,
0x6C, 0x86, 0x43, 0xA0, 0xF8, 0x0F, 0x05, 0xC2, 0x61, 0x3E, 0xF7, 0xF0,
0x20, 0x10, 0x78, 0xCC, 0xC8, 0xCD, 0x8C, 0xD0, 0xCF, 0x0C, 0xE0, 0x7E,
0x00, 0x7E, 0x07, 0x30, 0xF3, 0x0B, 0x31, 0xB3, 0x13, 0x33, 0x1E, 0x3E,
0x0E, 0xE1, 0x8C, 0x31, 0x86, 0x30, 0x7C, 0x0E, 0x03, 0xE6, 0xCC, 0xD8,
0xD3, 0x0E, 0x61, 0xC7, 0xFC, 0x79, 0xC0, 0xFF, 0xC0, 0x08, 0x43, 0x18,
0x63, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0x61, 0x83, 0x04, 0x08, 0x40, 0x83,
0x06, 0x18, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x18, 0x63, 0x08, 0x40, 0x08,
0x04, 0x02, 0x1D, 0x7F, 0xF8, 0xE0, 0xD8, 0x6E, 0x22, 0x00, 0x08, 0x04,
0x02, 0x01, 0x0F, 0xF8, 0x40, 0x20, 0x10, 0x08, 0x00, 0x6F, 0x6C, 0xFF,
0xF0, 0xFF, 0x80, 0x03, 0x02, 0x06, 0x04, 0x0C, 0x0C, 0x18, 0x18, 0x30,
0x30, 0x20, 0x60, 0x40, 0xC0, 0x3E, 0x3B, 0x98, 0xD8, 0x3C, 0x1E, 0x0F,
0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x6C, 0x67, 0x71, 0xF0, 0x19, 0xF7, 0x31,
0x8C, 0x63, 0x18, 0xC6, 0x31, 0x8C, 0x3E, 0x7B, 0x90, 0x60, 0x30, 0x18,
0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x0C, 0x07, 0xFC, 0x3E, 0x7B,
0x80, 0x60, 0x30, 0x18, 0x18, 0xF0, 0x1E, 0x01, 0x80, 0xC0, 0x60, 0x3E,
0xF3, 0xF0, 0x03, 0x01, 0xC0, 0xF0, 0x2C, 0x1B, 0x0C, 0xC2, 0x31, 0x8C,
0xC3, 0x3F, 0xF0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0xFF, 0x60, 0x30, 0x18,
0x0C, 0x07, 0xF3, 0xBC, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x3E, 0xF3, 0xE0,
0x0F, 0x8F, 0x27, 0x01, 0x80, 0xC0, 0x37, 0xCF, 0x3B, 0x03, 0xC0, 0xF0,
0x3C, 0x0D, 0x83, 0x7B, 0x87, 0xC0, 0xFF, 0xC0, 0x30, 0x08, 0x06, 0x01,
0x00, 0xC0, 0x20, 0x18, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x18, 0x0C, 0x00,
0x1E, 0x0D, 0xC6, 0x19, 0x86, 0x61, 0x8C, 0xC1, 0xE0, 0xCC, 0x61, 0xB0,
0x3C, 0x0F, 0x03, 0x73, 0x8F, 0xC0, 0x3E, 0x1D, 0xEC, 0x1B, 0x03, 0xC0,
0xF0, 0x3C, 0x0D, 0xCF, 0x3E, 0xC0, 0x30, 0x18, 0x06, 0x4F, 0x1F, 0x00,
0xFF, 0x80, 0x00, 0xFF, 0x80, 0xFF, 0x80, 0x00, 0x0D, 0xED, 0x80, 0x00,
0x81, 0xC3, 0x87, 0x0E, 0x07, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x40, 0xFF,
0x80, 0x00, 0x00, 0x0F, 0xF8, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x1C,
0x38, 0x70, 0xE0, 0x40, 0x00, 0x7C, 0xEE, 0x03, 0x03, 0x03, 0x06, 0x0C,
0x18, 0x10, 0x30, 0x00, 0x10, 0x38, 0x38, 0x0F, 0x83, 0x8C, 0x20, 0x64,
0x02, 0x47, 0xBC, 0xC9, 0x98, 0x99, 0x09, 0x90, 0x99, 0x1B, 0xD9, 0xAC,
0xE6, 0x40, 0x06, 0x00, 0x38, 0x40, 0xFC, 0x06, 0x00, 0x60, 0x0F, 0x00,
0x90, 0x09, 0x01, 0x98, 0x10, 0x83, 0x0C, 0x3F, 0xC3, 0xFC, 0x60, 0x66,
0x06, 0x40, 0x2C, 0x03, 0xFF, 0x3F, 0xEC, 0x0F, 0x03, 0xC0, 0xF0, 0x6F,
0xF3, 0xFE, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xFF, 0xBF, 0xC0, 0x0F, 0x8F,
0xF7, 0x01, 0x80, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x06, 0x01,
0xC0, 0x3F, 0xC3, 0xF0, 0xFC, 0x3F, 0xCC, 0x3B, 0x06, 0xC0, 0xF0, 0x3C,
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x1B, 0x0E, 0xFF, 0x3F, 0x00, 0xFF, 0xFF,
0xF0, 0x18, 0x0C, 0x06, 0x03, 0xFF, 0xFF, 0xC0, 0x60, 0x30, 0x18, 0x0F,
0xFF, 0xFC, 0xFF, 0xFF, 0xF0, 0x18, 0x0C, 0x06, 0x03, 0xFF, 0xFF, 0xC0,
0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x0F, 0x8F, 0xE7, 0x01, 0x80, 0xC0,
0x30, 0x0C, 0x3F, 0x0F, 0xC0, 0xF0, 0x36, 0x0D, 0x83, 0x3F, 0xC7, 0xE0,
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3F, 0xFF, 0xFF, 0xC0, 0xF0,
0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x30, 0xFF, 0x38, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x38, 0xFF, 0x01, 0x80, 0xC0, 0x60,
0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x7F, 0xF7, 0xE0,
0xC0, 0xF0, 0x6C, 0x33, 0x18, 0xCC, 0x36, 0x0F, 0x83, 0xA0, 0xCC, 0x31,
0x8C, 0x33, 0x0C, 0xC1, 0xB0, 0x30, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06,
0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0F, 0xFF, 0xFC, 0xC0, 0xF0,
0x3E, 0x1F, 0x87, 0xE1, 0xF4, 0xBD, 0x2F, 0x4B, 0xD2, 0xF5, 0x3C, 0xCF,
0x33, 0xCC, 0xF3, 0x30, 0xC0, 0xF8, 0x3E, 0x0F, 0xC3, 0xD0, 0xF6, 0x3C,
0xCF, 0x33, 0xC6, 0xF0, 0xBC, 0x3F, 0x07, 0xC1, 0xF0, 0x30, 0x1E, 0x1F,
0xC6, 0x1B, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0D,
0x86, 0x7F, 0x07, 0x80, 0xFE, 0x7F, 0xB0, 0x78, 0x3C, 0x1E, 0x0F, 0x0D,
0xFC, 0xF8, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x00, 0x1E, 0x1F, 0xC6, 0x1B,
0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0D, 0x86, 0x7F,
0x07, 0x80, 0x30, 0x06, 0x01, 0xC0, 0x20, 0xFE, 0x3F, 0xCC, 0x1B, 0x06,
0xC1, 0xB0, 0x6C, 0x33, 0xF8, 0xFC, 0x31, 0x8C, 0x33, 0x0C, 0xC1, 0xB0,
0x30, 0x3E, 0x7F, 0xC0, 0xC0, 0xC0, 0xE0, 0x78, 0x1E, 0x07, 0x03, 0x03,
0x03, 0xFE, 0xFC, 0xFF, 0xFF, 0xF0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0,
0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0xF0, 0x3C,
0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x87,
0x7F, 0x8F, 0xC0, 0xC0, 0x34, 0x02, 0x60, 0x66, 0x06, 0x20, 0x43, 0x0C,
0x30, 0xC1, 0x98, 0x19, 0x80, 0x90, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0x60,
0xC0, 0x3C, 0x03, 0xC0, 0x34, 0x03, 0x46, 0x24, 0x62, 0x66, 0x26, 0x92,
0x69, 0x66, 0x96, 0x30, 0xE3, 0x0C, 0x30, 0xC2, 0x04, 0xC0, 0xD8, 0x66,
0x18, 0xCC, 0x12, 0x07, 0x80, 0xC0, 0x30, 0x1E, 0x04, 0x83, 0x31, 0x86,
0x61, 0xB0, 0x30, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x0C, 0x30, 0x81, 0x98,
0x09, 0x00, 0xF0, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60,
0xFF, 0xFF, 0xF0, 0x18, 0x04, 0x03, 0x01, 0x80, 0xC0, 0x30, 0x18, 0x0C,
0x02, 0x01, 0x80, 0xFF, 0xFF, 0xF0, 0xFC, 0xCC, 0xCC, 0xCC, 0xCC, 0xCC,
0xCC, 0xCC, 0xF0, 0xC0, 0x40, 0x60, 0x20, 0x30, 0x30, 0x18, 0x18, 0x0C,
0x0C, 0x04, 0x06, 0x02, 0x03, 0xF3, 0x33, 0x33, 0x33, 0x33, 0x33, 0x33,
0x33, 0xF0, 0x0C, 0x03, 0x01, 0xE0, 0x48, 0x33, 0x08, 0x46, 0x19, 0x02,
0xC0, 0xC0, 0xFF, 0xF0, 0xC6, 0x30, 0x3E, 0x3B, 0xC0, 0x60, 0x33, 0xFB,
0x8F, 0x07, 0x83, 0xC1, 0xF3, 0xDF, 0x20, 0xC0, 0x30, 0x0C, 0x03, 0x00,
0xDF, 0x3E, 0xEC, 0x1B, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC1, 0xBE,
0xE9, 0xF0, 0x1F, 0x7B, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x60, 0x7B,
0x1F, 0x01, 0x80, 0xC0, 0x60, 0x33, 0xDB, 0xBD, 0x07, 0x83, 0xC1, 0xE0,
0xF0, 0x78, 0x34, 0x1B, 0xBC, 0xF6, 0x1F, 0x1E, 0xE4, 0x0F, 0x03, 0xFF,
0xF0, 0x0C, 0x03, 0x00, 0x60, 0x1E, 0xE1, 0xF8, 0x0F, 0xC7, 0x31, 0x80,
0x60, 0xFF, 0x86, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01, 0x80, 0x60, 0x18,
0x06, 0x01, 0x80, 0x1F, 0xCC, 0xC6, 0x19, 0x86, 0x61, 0x8C, 0xC1, 0xE0,
0xC0, 0x30, 0x0F, 0xE6, 0x1F, 0x03, 0xC0, 0xF0, 0x36, 0x38, 0xFC, 0xC0,
0x60, 0x30, 0x18, 0x0D, 0xE7, 0xBB, 0x87, 0x83, 0xC1, 0xE0, 0xF0, 0x78,
0x3C, 0x1E, 0x0F, 0x06, 0x18, 0x18, 0x00, 0x00, 0xF8, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0x06, 0x0C, 0x00, 0x07, 0xE0,
0xC1, 0x83, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1, 0x83, 0x06, 0x0F, 0x77,
0xC0, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x36, 0x33, 0x31, 0xB0, 0xF0, 0x78,
0x36, 0x19, 0x8C, 0x66, 0x1B, 0x06, 0xF8, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xFF, 0xBB, 0xBE, 0xFC,
0xCF, 0x33, 0xCC, 0xF3, 0x3C, 0xCF, 0x33, 0xCC, 0xF3, 0x3C, 0xCC, 0xDE,
0x7B, 0xB8, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0xC1, 0xE0, 0xF0, 0x60,
0x1E, 0x1D, 0xE6, 0x1B, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0x61, 0x9F,
0xE1, 0xE0, 0xDF, 0x3E, 0xEC, 0x1B, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
0xC1, 0xBE, 0xED, 0xF3, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0x3D, 0xBB,
0xD0, 0x78, 0x3C, 0x1E, 0x0F, 0x07, 0x83, 0x41, 0xBB, 0xCF, 0x60, 0x30,
0x18, 0x0C, 0x06, 0x03, 0x9F, 0xEF, 0x06, 0x0C, 0x18, 0x30, 0x60, 0xC1,
0x83, 0x00, 0x3E, 0xE7, 0xC0, 0xC0, 0x70, 0x3C, 0x07, 0x03, 0x03, 0xEF,
0xFC, 0x08, 0x0C, 0x06, 0x1F, 0xF1, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C,
0x06, 0x03, 0x01, 0xD8, 0x7C, 0xC1, 0xE0, 0xF0, 0x78, 0x3C, 0x1E, 0x0F,
0x07, 0x83, 0xC1, 0xBB, 0xCF, 0x60, 0xC0, 0xD0, 0x26, 0x19, 0x86, 0x21,
0x0C, 0xC3, 0x30, 0x48, 0x1E, 0x07, 0x80, 0xC0, 0xC6, 0x3C, 0x63, 0xC7,
0x34, 0xB2, 0x49, 0x24, 0x92, 0x59, 0xA5, 0x0A, 0x50, 0xA3, 0x0C, 0x20,
0x40, 0x61, 0x98, 0x63, 0x30, 0x48, 0x1E, 0x03, 0x01, 0xE0, 0xCC, 0x33,
0x18, 0x6C, 0x0C, 0xC0, 0xD0, 0x26, 0x19, 0x86, 0x21, 0x0C, 0xC3, 0x30,
0x68, 0x1E, 0x03, 0x80, 0xC0, 0x30, 0x08, 0x06, 0x0B, 0x03, 0x80, 0xFF,
0x03, 0x06, 0x04, 0x0C, 0x18, 0x30, 0x30, 0x60, 0xC0, 0xFF, 0x07, 0x1E,
0x18, 0x18, 0x18, 0x18, 0x38, 0xE0, 0x70, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x1E, 0x07, 0xFF, 0xFF, 0xF0, 0xE0, 0x78, 0x18, 0x18, 0x18, 0x18,
0x1C, 0x07, 0x0E, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0xE0, 0x70,
0x7F, 0xC1, 0xC0 };
const GFXglyph NotoMono10pt7bGlyphs[] PROGMEM = {
{ 0, 1, 1, 12, 0, 0 }, // 0x20 ' '
{ 1, 3, 14, 12, 5, -13 }, // 0x21 '!'
{ 7, 6, 5, 12, 3, -13 }, // 0x22 '"'
{ 11, 12, 14, 12, 0, -13 }, // 0x23 '#'
{ 32, 9, 16, 12, 2, -14 }, // 0x24 '$'
{ 50, 12, 14, 12, 0, -13 }, // 0x25 '%'
{ 71, 11, 14, 12, 1, -13 }, // 0x26 '&'
{ 91, 2, 5, 12, 5, -13 }, // 0x27 '''
{ 93, 6, 17, 12, 3, -13 }, // 0x28 '('
{ 106, 6, 17, 12, 3, -13 }, // 0x29 ')'
{ 119, 9, 9, 12, 1, -14 }, // 0x2A '*'
{ 130, 9, 9, 12, 1, -11 }, // 0x2B '+'
{ 141, 3, 5, 12, 4, -2 }, // 0x2C ','
{ 143, 6, 2, 12, 3, -5 }, // 0x2D '-'
{ 145, 3, 3, 12, 4, -2 }, // 0x2E '.'
{ 147, 8, 14, 12, 2, -13 }, // 0x2F '/'
{ 161, 9, 14, 12, 1, -13 }, // 0x30 '0'
{ 177, 5, 14, 12, 3, -13 }, // 0x31 '1'
{ 186, 9, 14, 12, 1, -13 }, // 0x32 '2'
{ 202, 9, 14, 12, 1, -13 }, // 0x33 '3'
{ 218, 10, 14, 12, 1, -13 }, // 0x34 '4'
{ 236, 9, 14, 12, 1, -13 }, // 0x35 '5'
{ 252, 10, 14, 12, 1, -13 }, // 0x36 '6'
{ 270, 10, 14, 12, 1, -13 }, // 0x37 '7'
{ 288, 10, 14, 12, 1, -13 }, // 0x38 '8'
{ 306, 10, 14, 12, 1, -13 }, // 0x39 '9'
{ 324, 3, 11, 12, 4, -10 }, // 0x3A ':'
{ 329, 3, 14, 12, 4, -10 }, // 0x3B ';'
{ 335, 9, 10, 12, 1, -11 }, // 0x3C '<'
{ 347, 9, 5, 12, 1, -9 }, // 0x3D '='
{ 353, 9, 10, 12, 1, -11 }, // 0x3E '>'
{ 365, 8, 14, 12, 2, -13 }, // 0x3F '?'
{ 379, 12, 16, 12, 0, -13 }, // 0x40 '@'
{ 403, 12, 14, 12, 0, -13 }, // 0x41 'A'
{ 424, 10, 14, 12, 1, -13 }, // 0x42 'B'
{ 442, 10, 14, 12, 1, -13 }, // 0x43 'C'
{ 460, 10, 14, 12, 1, -13 }, // 0x44 'D'
{ 478, 9, 14, 12, 2, -13 }, // 0x45 'E'
{ 494, 9, 14, 12, 2, -13 }, // 0x46 'F'
{ 510, 10, 14, 12, 1, -13 }, // 0x47 'G'
{ 528, 10, 14, 12, 1, -13 }, // 0x48 'H'
{ 546, 8, 14, 12, 2, -13 }, // 0x49 'I'
{ 560, 9, 14, 12, 1, -13 }, // 0x4A 'J'
{ 576, 10, 14, 12, 2, -13 }, // 0x4B 'K'
{ 594, 9, 14, 12, 2, -13 }, // 0x4C 'L'
{ 610, 10, 14, 12, 1, -13 }, // 0x4D 'M'
{ 628, 10, 14, 12, 1, -13 }, // 0x4E 'N'
{ 646, 10, 14, 12, 1, -13 }, // 0x4F 'O'
{ 664, 9, 14, 12, 2, -13 }, // 0x50 'P'
{ 680, 10, 18, 12, 1, -13 }, // 0x51 'Q'
{ 703, 10, 14, 12, 2, -13 }, // 0x52 'R'
{ 721, 8, 14, 12, 2, -13 }, // 0x53 'S'
{ 735, 10, 14, 12, 1, -13 }, // 0x54 'T'
{ 753, 10, 14, 12, 1, -13 }, // 0x55 'U'
{ 771, 12, 14, 12, 0, -13 }, // 0x56 'V'
{ 792, 12, 14, 12, 0, -13 }, // 0x57 'W'
{ 813, 10, 14, 12, 1, -13 }, // 0x58 'X'
{ 831, 12, 14, 12, 0, -13 }, // 0x59 'Y'
{ 852, 10, 14, 12, 1, -13 }, // 0x5A 'Z'
{ 870, 4, 17, 12, 5, -13 }, // 0x5B '['
{ 879, 8, 14, 12, 2, -13 }, // 0x5C '\'
{ 893, 4, 17, 12, 3, -13 }, // 0x5D ']'
{ 902, 10, 9, 12, 1, -13 }, // 0x5E '^'
{ 914, 12, 1, 12, 0, 3 }, // 0x5F '_'
{ 916, 4, 3, 12, 4, -14 }, // 0x60 '`'
{ 918, 9, 11, 12, 1, -10 }, // 0x61 'a'
{ 931, 10, 15, 12, 1, -14 }, // 0x62 'b'
{ 950, 8, 11, 12, 2, -10 }, // 0x63 'c'
{ 961, 9, 15, 12, 1, -14 }, // 0x64 'd'
{ 978, 10, 11, 12, 1, -10 }, // 0x65 'e'
{ 992, 10, 15, 12, 1, -14 }, // 0x66 'f'
{ 1011, 10, 16, 12, 1, -10 }, // 0x67 'g'
{ 1031, 9, 15, 12, 1, -14 }, // 0x68 'h'
{ 1048, 8, 15, 12, 2, -14 }, // 0x69 'i'
{ 1063, 7, 20, 12, 1, -14 }, // 0x6A 'j'
{ 1081, 9, 15, 12, 2, -14 }, // 0x6B 'k'
{ 1098, 8, 15, 12, 2, -14 }, // 0x6C 'l'
{ 1113, 10, 11, 12, 1, -10 }, // 0x6D 'm'
{ 1127, 9, 11, 12, 1, -10 }, // 0x6E 'n'
{ 1140, 10, 11, 12, 1, -10 }, // 0x6F 'o'
{ 1154, 10, 16, 12, 1, -10 }, // 0x70 'p'
{ 1174, 9, 16, 12, 1, -10 }, // 0x71 'q'
{ 1192, 7, 11, 12, 3, -10 }, // 0x72 'r'
{ 1202, 8, 11, 12, 2, -10 }, // 0x73 's'
{ 1213, 9, 14, 12, 1, -13 }, // 0x74 't'
{ 1229, 9, 11, 12, 1, -10 }, // 0x75 'u'
{ 1242, 10, 11, 12, 1, -10 }, // 0x76 'v'
{ 1256, 12, 11, 12, 0, -10 }, // 0x77 'w'
{ 1273, 10, 11, 12, 1, -10 }, // 0x78 'x'
{ 1287, 10, 16, 12, 1, -10 }, // 0x79 'y'
{ 1307, 8, 11, 12, 2, -10 }, // 0x7A 'z'
{ 1318, 8, 17, 12, 2, -13 }, // 0x7B '{'
{ 1335, 1, 20, 12, 5, -14 }, // 0x7C '|'
{ 1338, 8, 17, 12, 2, -13 }, // 0x7D '}'
{ 1355, 9, 3, 12, 1, -8 } }; // 0x7E '~'
const GFXfont NotoMono10pt7b PROGMEM = {
(uint8_t *)NotoMono10pt7bBitmaps,
(GFXglyph *)NotoMono10pt7bGlyphs,
0x20, 0x7E, 23 };
// Approx. 2031 bytes

View file

@ -0,0 +1,265 @@
const uint8_t NotoMono12pt7bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFF, 0xD2, 0x49, 0x20, 0x3F, 0xE0, 0xE7, 0xE7, 0xE7, 0xE7,
0xC6, 0xC6, 0x0C, 0x60, 0x63, 0x03, 0x18, 0x10, 0xC0, 0x84, 0x3F, 0xFD,
0xFF, 0xE3, 0x18, 0x18, 0xC0, 0xC6, 0x3F, 0xFD, 0xFF, 0xE1, 0x08, 0x18,
0xC0, 0xC6, 0x06, 0x30, 0x31, 0x80, 0x0C, 0x03, 0x03, 0xF9, 0xFE, 0xEC,
0x33, 0x0C, 0xC3, 0xB0, 0x7C, 0x0F, 0xC0, 0xF8, 0x37, 0x0C, 0xC3, 0x38,
0xDF, 0xFE, 0x7E, 0x03, 0x00, 0xC0, 0x30, 0x38, 0x33, 0x63, 0x31, 0x99,
0x8D, 0x8C, 0x6C, 0x63, 0xC1, 0xB6, 0x07, 0x60, 0x02, 0x00, 0x37, 0x03,
0x6C, 0x1E, 0x31, 0xB1, 0x8D, 0x8C, 0xCC, 0x66, 0x36, 0x60, 0xE0, 0x1E,
0x01, 0xF8, 0x18, 0x60, 0xC3, 0x06, 0x18, 0x39, 0x80, 0xDC, 0x03, 0xC0,
0x3C, 0x03, 0xF1, 0xB9, 0xCD, 0x87, 0xCC, 0x1E, 0x60, 0x63, 0x87, 0x8F,
0xEE, 0x3E, 0x38, 0xFF, 0xFD, 0x80, 0x06, 0x0C, 0x18, 0x30, 0x30, 0x60,
0x60, 0xE0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xE0, 0x60, 0x60, 0x30, 0x30,
0x18, 0x0C, 0x06, 0x60, 0x30, 0x18, 0x1C, 0x0C, 0x06, 0x06, 0x07, 0x03,
0x03, 0x03, 0x03, 0x03, 0x07, 0x06, 0x06, 0x0C, 0x0C, 0x18, 0x30, 0x60,
0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x7F, 0xFF, 0xFF, 0x0F, 0x00, 0xF0,
0x19, 0x83, 0x9C, 0x10, 0x80, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x61,
0xFF, 0xFF, 0xF8, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x00, 0x77, 0x66, 0xCC,
0xFF, 0xFF, 0xFF, 0x80, 0x00, 0xC0, 0x60, 0x18, 0x0C, 0x03, 0x01, 0x80,
0x60, 0x38, 0x0C, 0x07, 0x01, 0x80, 0x60, 0x30, 0x0C, 0x06, 0x01, 0x80,
0xC0, 0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x6E, 0x0F, 0x80, 0xF0, 0x1E,
0x03, 0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3E, 0x0E, 0xC1, 0x9C, 0x71, 0xFC,
0x1F, 0x00, 0x0C, 0xF7, 0xFB, 0x4C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C,
0x30, 0xC3, 0x0C, 0x1F, 0x0F, 0xF1, 0x87, 0x00, 0x60, 0x0C, 0x01, 0x80,
0x70, 0x0C, 0x03, 0x80, 0xE0, 0x38, 0x06, 0x01, 0x80, 0x60, 0x18, 0x07,
0xFF, 0xFF, 0xE0, 0x3E, 0x3F, 0xC4, 0x38, 0x06, 0x01, 0x80, 0xE0, 0x70,
0xF0, 0x3F, 0x00, 0x60, 0x0C, 0x03, 0x00, 0xC0, 0x78, 0x1B, 0xFE, 0x7E,
0x00, 0x03, 0x80, 0x38, 0x07, 0x80, 0x58, 0x0D, 0x81, 0x98, 0x19, 0x83,
0x18, 0x31, 0x86, 0x18, 0xC1, 0x8F, 0xFF, 0xFF, 0xF0, 0x18, 0x01, 0x80,
0x18, 0x01, 0x80, 0x7F, 0x9F, 0xEC, 0x03, 0x00, 0xC0, 0x30, 0x0F, 0xE3,
0xFE, 0x01, 0x80, 0x70, 0x0C, 0x03, 0x00, 0xC0, 0x78, 0x1B, 0xFC, 0x7E,
0x00, 0x07, 0xC3, 0xF8, 0xE0, 0x38, 0x06, 0x01, 0xC0, 0x33, 0xC6, 0xFE,
0xE0, 0xDC, 0x0F, 0x01, 0xE0, 0x3C, 0x06, 0xC1, 0xDC, 0x31, 0xFE, 0x1F,
0x00, 0xFF, 0xFF, 0xFC, 0x03, 0x80, 0x60, 0x0C, 0x03, 0x00, 0x60, 0x18,
0x03, 0x00, 0xE0, 0x18, 0x07, 0x00, 0xC0, 0x18, 0x06, 0x00, 0xC0, 0x38,
0x00, 0x1F, 0x07, 0xF1, 0xC7, 0x30, 0x66, 0x0C, 0xE1, 0x8E, 0x60, 0xF8,
0x1F, 0x0E, 0x39, 0x83, 0x60, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0xFE, 0x1F,
0x00, 0x1F, 0x0F, 0xF1, 0x87, 0x70, 0x6C, 0x07, 0x80, 0xF0, 0x1E, 0x07,
0x60, 0xEF, 0xEC, 0x79, 0x80, 0x70, 0x0C, 0x03, 0x80, 0xE3, 0xF8, 0x7C,
0x00, 0xFF, 0x80, 0x00, 0x03, 0xFE, 0x77, 0x70, 0x00, 0x00, 0x00, 0x77,
0x66, 0xCC, 0x00, 0x40, 0x70, 0x78, 0x78, 0x38, 0x38, 0x0E, 0x00, 0xE0,
0x0E, 0x01, 0xE0, 0x1C, 0x01, 0xFF, 0xFF, 0xF0, 0x00, 0x00, 0x00, 0x3F,
0xFF, 0xFC, 0x80, 0x38, 0x07, 0x80, 0x70, 0x07, 0x00, 0x70, 0x1C, 0x1C,
0x1C, 0x1E, 0x0E, 0x02, 0x00, 0x3F, 0x3F, 0xE4, 0x1C, 0x03, 0x00, 0xC0,
0x30, 0x18, 0x0E, 0x06, 0x03, 0x00, 0xC0, 0x60, 0x00, 0x00, 0x01, 0xC0,
0x70, 0x1C, 0x00, 0x07, 0xC0, 0x7F, 0xC3, 0x03, 0x18, 0x06, 0x60, 0x09,
0x1F, 0x3C, 0xFC, 0xF6, 0x33, 0xD8, 0xCF, 0x63, 0x3D, 0x8C, 0xF6, 0x33,
0xCF, 0xFB, 0x3C, 0xC6, 0x00, 0x18, 0x00, 0x30, 0x00, 0x7F, 0xC0, 0x7E,
0x00, 0x03, 0x00, 0x1E, 0x00, 0x78, 0x01, 0xE0, 0x0C, 0xC0, 0x33, 0x00,
0xCC, 0x06, 0x18, 0x18, 0x60, 0x61, 0x83, 0xFF, 0x0F, 0xFC, 0x30, 0x31,
0x80, 0x66, 0x01, 0x98, 0x06, 0xC0, 0x0C, 0xFF, 0x8F, 0xFE, 0xC0, 0x7C,
0x03, 0xC0, 0x3C, 0x07, 0xC0, 0xEF, 0xF8, 0xFF, 0xCC, 0x0E, 0xC0, 0x7C,
0x03, 0xC0, 0x3C, 0x07, 0xC0, 0xEF, 0xFE, 0xFF, 0x80, 0x07, 0xE1, 0xFF,
0x38, 0x27, 0x00, 0x60, 0x0E, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00,
0xC0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x38, 0x01, 0xFF, 0x07, 0xE0, 0xFE,
0x0F, 0xF8, 0xC1, 0xCC, 0x0E, 0xC0, 0x6C, 0x07, 0xC0, 0x3C, 0x03, 0xC0,
0x3C, 0x03, 0xC0, 0x7C, 0x07, 0xC0, 0x6C, 0x0E, 0xC1, 0xCF, 0xF8, 0xFE,
0x00, 0xFF, 0xFF, 0xFC, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0xFF, 0xFF,
0xF0, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0xFF, 0xFF, 0xC0, 0xFF,
0xFF, 0xFC, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0xFF, 0xFF, 0xF0, 0x0C,
0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, 0x0F, 0xC3, 0xFC,
0xE1, 0x38, 0x06, 0x01, 0xC0, 0x30, 0x06, 0x1F, 0xC3, 0xF8, 0x0F, 0x01,
0xF0, 0x36, 0x06, 0xC0, 0xDC, 0x19, 0xFF, 0x0F, 0xC0, 0xC0, 0x78, 0x0F,
0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1F, 0xFF, 0xFF, 0xF8, 0x0F, 0x01,
0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x60, 0xFF, 0xFF, 0xC6,
0x03, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x01, 0x80,
0xC0, 0x61, 0xFF, 0xFF, 0x80, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0,
0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x70, 0x3B,
0xFC, 0xFE, 0x00, 0xC0, 0x78, 0x1B, 0x06, 0x61, 0x8C, 0x61, 0x9C, 0x33,
0x06, 0xC0, 0xFC, 0x1D, 0x83, 0x18, 0x63, 0x8C, 0x31, 0x83, 0x30, 0x76,
0x06, 0xC0, 0x60, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03,
0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0xFF, 0xFF,
0xC0, 0xE0, 0xFC, 0x1F, 0x83, 0xF0, 0x7E, 0x17, 0xA2, 0xF4, 0x5E, 0x8B,
0xD1, 0x7A, 0x6F, 0x29, 0xE5, 0x3C, 0xA7, 0x94, 0xF3, 0x9E, 0x23, 0xC4,
0x60, 0xE0, 0x7C, 0x0F, 0xC1, 0xF8, 0x3D, 0x07, 0xB0, 0xF2, 0x1E, 0x63,
0xC4, 0x78, 0xCF, 0x09, 0xE1, 0xBC, 0x17, 0x83, 0xF0, 0x7E, 0x07, 0xC0,
0xE0, 0x1F, 0x03, 0xFC, 0x70, 0xE6, 0x06, 0xE0, 0x6E, 0x07, 0xC0, 0x3C,
0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x07, 0xE0, 0x66, 0x06, 0x70, 0xE3,
0xFC, 0x1F, 0x00, 0xFF, 0x1F, 0xFB, 0x07, 0x60, 0x7C, 0x07, 0x80, 0xF0,
0x1E, 0x07, 0xC1, 0xDF, 0xF3, 0xF8, 0x60, 0x0C, 0x01, 0x80, 0x30, 0x06,
0x00, 0xC0, 0x00, 0x1F, 0x03, 0xFC, 0x70, 0xE6, 0x06, 0xE0, 0x6E, 0x07,
0xC0, 0x3C, 0x03, 0xC0, 0x3C, 0x03, 0xC0, 0x3E, 0x07, 0xE0, 0x76, 0x06,
0x70, 0xE3, 0xFC, 0x1F, 0x80, 0x18, 0x00, 0xC0, 0x0E, 0x00, 0x70, 0x02,
0xFE, 0x1F, 0xF3, 0x07, 0x60, 0xEC, 0x0D, 0x81, 0xB0, 0x76, 0x1C, 0xFF,
0x1F, 0xC3, 0x18, 0x61, 0x8C, 0x39, 0x83, 0x30, 0x76, 0x06, 0xC0, 0x60,
0x1F, 0x9F, 0xFE, 0x0B, 0x00, 0xC0, 0x30, 0x0E, 0x01, 0xF0, 0x1F, 0x01,
0xE0, 0x1C, 0x03, 0x00, 0xC0, 0x38, 0x1F, 0xFE, 0x7E, 0x00, 0xFF, 0xFF,
0xFF, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00,
0xC0, 0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0,
0x78, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0xC1, 0xDC, 0x73, 0xFE, 0x1F, 0x00,
0xC0, 0x1D, 0x80, 0x66, 0x01, 0x98, 0x06, 0x30, 0x30, 0xC0, 0xC3, 0x03,
0x06, 0x18, 0x18, 0x60, 0x61, 0x80, 0xCC, 0x03, 0x30, 0x0C, 0xC0, 0x1E,
0x00, 0x78, 0x01, 0xE0, 0x03, 0x00, 0xC0, 0x0F, 0x00, 0x3C, 0x00, 0xF0,
0x03, 0x60, 0x09, 0x8C, 0x66, 0x31, 0x99, 0xE6, 0x67, 0x99, 0x92, 0x66,
0xC9, 0x9B, 0x36, 0x2C, 0xD0, 0xA1, 0x42, 0x87, 0x0E, 0x1C, 0x30, 0x30,
0xE0, 0x76, 0x06, 0x70, 0xE3, 0x0C, 0x19, 0x81, 0x98, 0x0F, 0x00, 0xF0,
0x06, 0x00, 0xF0, 0x0F, 0x01, 0x98, 0x39, 0xC3, 0x0C, 0x70, 0xE6, 0x06,
0xE0, 0x70, 0xC0, 0x36, 0x06, 0x60, 0x63, 0x0C, 0x30, 0xC1, 0x98, 0x19,
0x80, 0xF0, 0x0F, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06, 0x00, 0x60, 0x06,
0x00, 0x60, 0x06, 0x00, 0xFF, 0xFF, 0xFF, 0x00, 0x60, 0x0E, 0x00, 0xC0,
0x18, 0x03, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x1C, 0x01, 0x80, 0x30, 0x07,
0x00, 0x60, 0x0F, 0xFF, 0xFF, 0xF0, 0xFF, 0xFC, 0x30, 0xC3, 0x0C, 0x30,
0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x3F, 0xFC, 0xC0, 0x18,
0x06, 0x00, 0xC0, 0x30, 0x06, 0x01, 0x80, 0x70, 0x0C, 0x03, 0x80, 0x60,
0x18, 0x03, 0x00, 0xC0, 0x18, 0x06, 0x00, 0xC0, 0xFF, 0xF0, 0xC3, 0x0C,
0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xC3, 0x0C, 0x30, 0xFF, 0xFC,
0x06, 0x00, 0x60, 0x0F, 0x00, 0x90, 0x19, 0x81, 0x08, 0x30, 0xC3, 0x0C,
0x60, 0x66, 0x06, 0xC0, 0x30, 0xFF, 0xFC, 0xE3, 0x0C, 0x30, 0x3F, 0x1F,
0xE0, 0x1C, 0x03, 0x00, 0xC7, 0xF7, 0xEF, 0x83, 0xC0, 0xF0, 0x7E, 0x1D,
0xFF, 0x3C, 0xC0, 0xC0, 0x18, 0x03, 0x00, 0x60, 0x0C, 0x01, 0x9E, 0x3F,
0xE7, 0x06, 0xE0, 0xF8, 0x0F, 0x01, 0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3F,
0x06, 0xFF, 0x99, 0xE0, 0x1F, 0x8F, 0xF7, 0x03, 0x80, 0xC0, 0x30, 0x0C,
0x03, 0x00, 0xC0, 0x38, 0x07, 0x00, 0xFF, 0x1F, 0x80, 0x00, 0x60, 0x0C,
0x01, 0x80, 0x30, 0x06, 0x3C, 0xCF, 0xFB, 0x07, 0xE0, 0xF8, 0x0F, 0x01,
0xE0, 0x3C, 0x07, 0x80, 0xF8, 0x3B, 0x07, 0x3F, 0xE3, 0xCC, 0x0F, 0x83,
0xFC, 0x70, 0x66, 0x03, 0xC0, 0x3F, 0xFF, 0xFF, 0xFC, 0x00, 0xC0, 0x06,
0x00, 0x70, 0x03, 0xFE, 0x0F, 0xC0, 0x03, 0xF0, 0x7F, 0x0E, 0x00, 0xC0,
0x0C, 0x0F, 0xFE, 0xFF, 0xE0, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0,
0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x0C, 0x00, 0xC0, 0x1F, 0xF9, 0xFF,
0x1C, 0x38, 0xC0, 0xC6, 0x06, 0x30, 0x30, 0xFF, 0x03, 0xF0, 0x30, 0x01,
0x80, 0x0C, 0x00, 0x3F, 0x83, 0xFE, 0x30, 0x1B, 0x00, 0xD8, 0x06, 0xE0,
0x73, 0xFF, 0x0F, 0xE0, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x33, 0xCF,
0xFB, 0x87, 0xE0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
0xC0, 0xF0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x00, 0x00, 0x1F, 0x03, 0xC0,
0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x7F,
0xBF, 0xF0, 0x03, 0x07, 0x03, 0x00, 0x00, 0x7F, 0x1F, 0x03, 0x03, 0x03,
0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x07,
0xFE, 0xFC, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x7C, 0x3B, 0x1C,
0xCE, 0x33, 0x0D, 0x83, 0xE0, 0xEC, 0x31, 0x8C, 0x63, 0x0C, 0xC1, 0xB0,
0x70, 0x7C, 0x0F, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x0C,
0x03, 0x00, 0xC0, 0x30, 0x0C, 0x03, 0x00, 0xC0, 0x30, 0x7F, 0xBF, 0xF0,
0xDC, 0xEF, 0xFF, 0xE7, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63,
0xC6, 0x3C, 0x63, 0xC6, 0x3C, 0x63, 0xC6, 0x30, 0xCF, 0x3F, 0xEE, 0x1F,
0x83, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0,
0xC0, 0x1F, 0x83, 0xFC, 0x70, 0xEE, 0x06, 0xC0, 0x3C, 0x03, 0xC0, 0x3C,
0x03, 0xC0, 0x36, 0x06, 0x70, 0xE3, 0xFC, 0x1F, 0x80, 0xCF, 0x1F, 0xF3,
0x83, 0x70, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0, 0x7C, 0x1F, 0x83,
0x7F, 0xCC, 0xF1, 0x80, 0x30, 0x06, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x00,
0x1E, 0x67, 0xED, 0x83, 0xF0, 0x7C, 0x07, 0x80, 0xF0, 0x1E, 0x03, 0xC0,
0x7C, 0x1D, 0x83, 0x9F, 0xF1, 0xE6, 0x00, 0xC0, 0x18, 0x03, 0x00, 0x60,
0x0C, 0x01, 0x80, 0xCF, 0xEF, 0xFC, 0x1C, 0x0C, 0x06, 0x03, 0x01, 0x80,
0xC0, 0x60, 0x30, 0x18, 0x0C, 0x00, 0x3F, 0x9F, 0xFC, 0x03, 0x00, 0xE0,
0x1F, 0x01, 0xF0, 0x0E, 0x01, 0xC0, 0x38, 0x1F, 0xFE, 0x7F, 0x00, 0x08,
0x06, 0x01, 0x83, 0xFF, 0xFF, 0xC6, 0x01, 0x80, 0x60, 0x18, 0x06, 0x01,
0x80, 0x60, 0x18, 0x07, 0x00, 0xFC, 0x1F, 0xC0, 0xF0, 0x3C, 0x0F, 0x03,
0xC0, 0xF0, 0x3C, 0x0F, 0x03, 0xC0, 0xF0, 0x7E, 0x1D, 0xFF, 0x3C, 0xC0,
0xC0, 0x36, 0x06, 0x60, 0x66, 0x06, 0x30, 0xC3, 0x0C, 0x30, 0xC1, 0x98,
0x19, 0x80, 0x98, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0xC3, 0x0F, 0x0C, 0x3C,
0x78, 0x91, 0xE2, 0x65, 0x99, 0x92, 0x66, 0xCD, 0x8B, 0x34, 0x2C, 0xD0,
0xA1, 0x42, 0x85, 0x0E, 0x1C, 0x10, 0x60, 0x60, 0x67, 0x0E, 0x30, 0xC1,
0x98, 0x1F, 0x80, 0xF0, 0x06, 0x00, 0xF0, 0x1F, 0x81, 0x98, 0x30, 0xC6,
0x06, 0xE0, 0x70, 0xC0, 0x36, 0x06, 0x60, 0x66, 0x06, 0x30, 0xC3, 0x0C,
0x19, 0xC1, 0x98, 0x19, 0x80, 0xF8, 0x0F, 0x00, 0xF0, 0x06, 0x00, 0x60,
0x0E, 0x00, 0xC0, 0x1C, 0x0F, 0x80, 0xF0, 0x00, 0xFF, 0xFF, 0xF0, 0x18,
0x0E, 0x03, 0x01, 0x80, 0xC0, 0x60, 0x38, 0x0C, 0x06, 0x03, 0xFF, 0xFF,
0xC0, 0x03, 0x83, 0xC3, 0x01, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x1C, 0x7C,
0x3E, 0x03, 0x80, 0xC0, 0x60, 0x30, 0x18, 0x0C, 0x06, 0x03, 0x80, 0xF0,
0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xE0, 0x78, 0x0E, 0x03, 0x01,
0x80, 0xC0, 0x60, 0x30, 0x1C, 0x07, 0xC3, 0xE3, 0x81, 0x80, 0xC0, 0x60,
0x30, 0x18, 0x0C, 0x0E, 0x1E, 0x0E, 0x00, 0x78, 0x7F, 0xF8, 0x78 };
const GFXglyph NotoMono12pt7bGlyphs[] PROGMEM = {
{ 0, 1, 1, 14, 0, 0 }, // 0x20 ' '
{ 1, 3, 17, 14, 6, -16 }, // 0x21 '!'
{ 8, 8, 6, 14, 3, -16 }, // 0x22 '"'
{ 14, 13, 17, 14, 0, -16 }, // 0x23 '#'
{ 42, 10, 20, 14, 2, -17 }, // 0x24 '$'
{ 67, 13, 17, 14, 0, -16 }, // 0x25 '%'
{ 95, 13, 17, 14, 1, -16 }, // 0x26 '&'
{ 123, 3, 6, 14, 5, -16 }, // 0x27 '''
{ 126, 8, 21, 14, 3, -16 }, // 0x28 '('
{ 147, 8, 21, 14, 3, -16 }, // 0x29 ')'
{ 168, 12, 11, 14, 1, -17 }, // 0x2A '*'
{ 185, 11, 11, 14, 1, -13 }, // 0x2B '+'
{ 201, 4, 6, 14, 4, -2 }, // 0x2C ','
{ 204, 8, 2, 14, 3, -6 }, // 0x2D '-'
{ 206, 3, 3, 14, 5, -2 }, // 0x2E '.'
{ 208, 10, 17, 14, 2, -16 }, // 0x2F '/'
{ 230, 11, 17, 14, 1, -16 }, // 0x30 '0'
{ 254, 6, 17, 14, 3, -16 }, // 0x31 '1'
{ 267, 11, 17, 14, 2, -16 }, // 0x32 '2'
{ 291, 10, 17, 14, 2, -16 }, // 0x33 '3'
{ 313, 12, 17, 14, 1, -16 }, // 0x34 '4'
{ 339, 10, 17, 14, 2, -16 }, // 0x35 '5'
{ 361, 11, 17, 14, 1, -16 }, // 0x36 '6'
{ 385, 11, 17, 14, 1, -16 }, // 0x37 '7'
{ 409, 11, 17, 14, 1, -16 }, // 0x38 '8'
{ 433, 11, 17, 14, 1, -16 }, // 0x39 '9'
{ 457, 3, 13, 14, 5, -12 }, // 0x3A ':'
{ 462, 4, 16, 14, 4, -12 }, // 0x3B ';'
{ 470, 10, 12, 14, 2, -13 }, // 0x3C '<'
{ 485, 10, 7, 14, 2, -11 }, // 0x3D '='
{ 494, 10, 12, 14, 2, -13 }, // 0x3E '>'
{ 509, 10, 17, 14, 2, -16 }, // 0x3F '?'
{ 531, 14, 19, 14, 0, -16 }, // 0x40 '@'
{ 565, 14, 17, 14, 0, -16 }, // 0x41 'A'
{ 595, 12, 17, 14, 1, -16 }, // 0x42 'B'
{ 621, 12, 17, 14, 1, -16 }, // 0x43 'C'
{ 647, 12, 17, 14, 1, -16 }, // 0x44 'D'
{ 673, 10, 17, 14, 2, -16 }, // 0x45 'E'
{ 695, 10, 17, 14, 2, -16 }, // 0x46 'F'
{ 717, 11, 17, 14, 1, -16 }, // 0x47 'G'
{ 741, 11, 17, 14, 1, -16 }, // 0x48 'H'
{ 765, 9, 17, 14, 3, -16 }, // 0x49 'I'
{ 785, 10, 17, 14, 1, -16 }, // 0x4A 'J'
{ 807, 11, 17, 14, 2, -16 }, // 0x4B 'K'
{ 831, 10, 17, 14, 2, -16 }, // 0x4C 'L'
{ 853, 11, 17, 14, 1, -16 }, // 0x4D 'M'
{ 877, 11, 17, 14, 1, -16 }, // 0x4E 'N'
{ 901, 12, 17, 14, 1, -16 }, // 0x4F 'O'
{ 927, 11, 17, 14, 2, -16 }, // 0x50 'P'
{ 951, 12, 22, 14, 1, -16 }, // 0x51 'Q'
{ 984, 11, 17, 14, 2, -16 }, // 0x52 'R'
{ 1008, 10, 17, 14, 2, -16 }, // 0x53 'S'
{ 1030, 12, 17, 14, 1, -16 }, // 0x54 'T'
{ 1056, 11, 17, 14, 1, -16 }, // 0x55 'U'
{ 1080, 14, 17, 14, 0, -16 }, // 0x56 'V'
{ 1110, 14, 17, 14, 0, -16 }, // 0x57 'W'
{ 1140, 12, 17, 14, 1, -16 }, // 0x58 'X'
{ 1166, 12, 17, 14, 1, -16 }, // 0x59 'Y'
{ 1192, 12, 17, 14, 1, -16 }, // 0x5A 'Z'
{ 1218, 6, 21, 14, 5, -16 }, // 0x5B '['
{ 1234, 10, 17, 14, 2, -16 }, // 0x5C '\'
{ 1256, 6, 21, 14, 2, -16 }, // 0x5D ']'
{ 1272, 12, 11, 14, 1, -16 }, // 0x5E '^'
{ 1289, 14, 1, 14, 0, 3 }, // 0x5F '_'
{ 1291, 5, 4, 14, 4, -18 }, // 0x60 '`'
{ 1294, 10, 13, 14, 2, -12 }, // 0x61 'a'
{ 1311, 11, 18, 14, 2, -17 }, // 0x62 'b'
{ 1336, 10, 13, 14, 2, -12 }, // 0x63 'c'
{ 1353, 11, 18, 14, 1, -17 }, // 0x64 'd'
{ 1378, 12, 13, 14, 1, -12 }, // 0x65 'e'
{ 1398, 12, 18, 14, 1, -17 }, // 0x66 'f'
{ 1425, 13, 19, 14, 1, -12 }, // 0x67 'g'
{ 1456, 10, 18, 14, 2, -17 }, // 0x68 'h'
{ 1479, 10, 18, 14, 2, -17 }, // 0x69 'i'
{ 1502, 8, 24, 14, 2, -17 }, // 0x6A 'j'
{ 1526, 10, 18, 14, 3, -17 }, // 0x6B 'k'
{ 1549, 10, 18, 14, 2, -17 }, // 0x6C 'l'
{ 1572, 12, 13, 14, 1, -12 }, // 0x6D 'm'
{ 1592, 10, 13, 14, 2, -12 }, // 0x6E 'n'
{ 1609, 12, 13, 14, 1, -12 }, // 0x6F 'o'
{ 1629, 11, 19, 14, 2, -12 }, // 0x70 'p'
{ 1656, 11, 19, 14, 1, -12 }, // 0x71 'q'
{ 1683, 9, 13, 14, 3, -12 }, // 0x72 'r'
{ 1698, 10, 13, 14, 2, -12 }, // 0x73 's'
{ 1715, 10, 16, 14, 2, -15 }, // 0x74 't'
{ 1735, 10, 13, 14, 2, -12 }, // 0x75 'u'
{ 1752, 12, 13, 14, 1, -12 }, // 0x76 'v'
{ 1772, 14, 13, 14, 0, -12 }, // 0x77 'w'
{ 1795, 12, 13, 14, 1, -12 }, // 0x78 'x'
{ 1815, 12, 19, 14, 1, -12 }, // 0x79 'y'
{ 1844, 10, 13, 14, 2, -12 }, // 0x7A 'z'
{ 1861, 9, 21, 14, 2, -16 }, // 0x7B '{'
{ 1885, 2, 24, 14, 6, -17 }, // 0x7C '|'
{ 1891, 9, 21, 14, 3, -16 }, // 0x7D '}'
{ 1915, 10, 3, 14, 2, -9 } }; // 0x7E '~'
const GFXfont NotoMono12pt7b PROGMEM = {
(uint8_t *)NotoMono12pt7bBitmaps,
(GFXglyph *)NotoMono12pt7bGlyphs,
0x20, 0x7E, 28 };
// Approx. 2591 bytes

View file

@ -0,0 +1,382 @@
const uint8_t NotoMono16pt7bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFE, 0xE6, 0x66, 0x66, 0x66, 0x66, 0x60, 0x00, 0xEF, 0xFE,
0xF1, 0xFC, 0x3B, 0x87, 0x70, 0xEE, 0x1D, 0xC3, 0xB8, 0x73, 0x06, 0x03,
0x06, 0x03, 0x83, 0x01, 0xC3, 0x80, 0xC1, 0x80, 0x60, 0xC0, 0x30, 0x61,
0xFF, 0xFE, 0xFF, 0xFF, 0x0C, 0x18, 0x06, 0x0C, 0x03, 0x06, 0x01, 0x83,
0x00, 0xC1, 0x87, 0xFF, 0xFB, 0xFF, 0xFC, 0x30, 0x60, 0x18, 0x30, 0x0C,
0x18, 0x06, 0x0C, 0x07, 0x0E, 0x03, 0x07, 0x01, 0x83, 0x00, 0x03, 0x00,
0x18, 0x00, 0xC0, 0x1F, 0xC3, 0xFF, 0x3D, 0xBB, 0x8C, 0x1C, 0x60, 0xE3,
0x07, 0x18, 0x1E, 0xC0, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x0D, 0xC0, 0x67,
0x03, 0x38, 0x19, 0xC0, 0xCF, 0xF7, 0xEF, 0xFE, 0x1F, 0xC0, 0x0C, 0x00,
0x60, 0x03, 0x00, 0x3E, 0x07, 0x0F, 0xE0, 0xC1, 0x8C, 0x38, 0x71, 0xC6,
0x0C, 0x19, 0xC1, 0x83, 0x30, 0x30, 0x6E, 0x07, 0x1D, 0x80, 0x63, 0x70,
0x0F, 0xEC, 0x00, 0xF9, 0x80, 0x00, 0x67, 0xC0, 0x0D, 0xFC, 0x03, 0xB1,
0x80, 0x6E, 0x38, 0x1D, 0x83, 0x03, 0x30, 0x60, 0xE6, 0x0C, 0x18, 0xE3,
0x87, 0x0C, 0x60, 0xC1, 0xFC, 0x38, 0x1F, 0x00, 0x07, 0xC0, 0x07, 0xFC,
0x03, 0xC7, 0x80, 0xE0, 0xE0, 0x38, 0x38, 0x0E, 0x0E, 0x03, 0x83, 0x80,
0x71, 0xC0, 0x1F, 0xE0, 0x03, 0xF0, 0x00, 0xF0, 0x00, 0xFE, 0x00, 0x79,
0xC3, 0x9C, 0x78, 0xEE, 0x0F, 0x73, 0x81, 0xFC, 0xE0, 0x3E, 0x38, 0x07,
0x8F, 0x03, 0xE1, 0xF7, 0xFC, 0x3F, 0xE7, 0x87, 0xE0, 0xF0, 0xFE, 0xEE,
0xEE, 0xE6, 0x01, 0xC0, 0x70, 0x1C, 0x07, 0x01, 0xC0, 0x70, 0x0E, 0x03,
0x80, 0x70, 0x0C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00,
0xE0, 0x0C, 0x01, 0xC0, 0x38, 0x03, 0x80, 0x70, 0x07, 0x00, 0x70, 0x07,
0x00, 0x70, 0x07, 0x00, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x0E, 0x01, 0xC0,
0x70, 0x0E, 0x03, 0x80, 0x70, 0x1C, 0x07, 0x01, 0xC0, 0x70, 0x1C, 0x07,
0x01, 0xC0, 0x70, 0x38, 0x0E, 0x03, 0x01, 0xC0, 0xE0, 0x38, 0x1C, 0x0E,
0x07, 0x00, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x04, 0x18, 0x2F,
0x37, 0xFF, 0xFF, 0x83, 0xF0, 0x07, 0xC0, 0x0D, 0xC0, 0x3B, 0x80, 0xE3,
0x83, 0xC7, 0x81, 0x04, 0x00, 0x03, 0x00, 0x0C, 0x00, 0x30, 0x00, 0xC0,
0x03, 0x00, 0x0C, 0x0F, 0xFF, 0xFF, 0xFF, 0x03, 0x00, 0x0C, 0x00, 0x30,
0x00, 0xC0, 0x03, 0x00, 0x0C, 0x00, 0x7B, 0xDC, 0xE7, 0x73, 0x98, 0xFF,
0xFF, 0xFF, 0xFF, 0x80, 0x77, 0xFF, 0xF7, 0x00, 0x00, 0x38, 0x01, 0x80,
0x1C, 0x00, 0xC0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x38, 0x03, 0x80, 0x1C,
0x01, 0xC0, 0x0E, 0x00, 0xE0, 0x07, 0x00, 0x30, 0x03, 0x80, 0x18, 0x01,
0xC0, 0x0C, 0x00, 0xE0, 0x06, 0x00, 0x70, 0x00, 0x07, 0xC0, 0x3F, 0xE0,
0xF1, 0xE3, 0xC1, 0xC7, 0x01, 0xCC, 0x01, 0xB8, 0x03, 0xF0, 0x07, 0xE0,
0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03,
0xF0, 0x07, 0x60, 0x0C, 0xE0, 0x39, 0xE0, 0xF1, 0xE3, 0xC1, 0xFF, 0x00,
0xF8, 0x00, 0x07, 0x1F, 0x3F, 0x77, 0xE7, 0x47, 0x07, 0x07, 0x07, 0x07,
0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07, 0x07,
0x0F, 0xC0, 0x7F, 0xE3, 0xF3, 0xE3, 0x01, 0xE0, 0x01, 0xC0, 0x03, 0x80,
0x07, 0x00, 0x0E, 0x00, 0x18, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1E,
0x00, 0x78, 0x01, 0xE0, 0x07, 0x80, 0x1C, 0x00, 0x70, 0x01, 0xC0, 0x07,
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x1F, 0xC1, 0xFF, 0x8F, 0xCF, 0x10,
0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x1C, 0x00, 0xF0, 0x7F, 0x01,
0xFC, 0x00, 0x7C, 0x00, 0x38, 0x00, 0x70, 0x01, 0xC0, 0x07, 0x00, 0x1C,
0x00, 0x78, 0x03, 0xBE, 0x7E, 0xFF, 0xF0, 0xFE, 0x00, 0x00, 0x38, 0x00,
0x78, 0x00, 0xF8, 0x00, 0xF8, 0x01, 0xF8, 0x03, 0xB8, 0x03, 0x38, 0x07,
0x38, 0x0E, 0x38, 0x0C, 0x38, 0x1C, 0x38, 0x38, 0x38, 0x30, 0x38, 0x70,
0x38, 0xE0, 0x38, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x38, 0x00,
0x38, 0x00, 0x38, 0x00, 0x38, 0x7F, 0xE3, 0xFF, 0x1F, 0xF8, 0xC0, 0x0E,
0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xFF, 0x87, 0xFF, 0x18, 0xFC, 0x00,
0xE0, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x1D,
0xE7, 0xCF, 0xFC, 0x1F, 0xC0, 0x01, 0xF8, 0x1F, 0xF0, 0x7E, 0x21, 0xE0,
0x03, 0x80, 0x0E, 0x00, 0x1C, 0x00, 0x30, 0x00, 0xE3, 0xE1, 0xDF, 0xF3,
0xF0, 0xF7, 0x80, 0xEE, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0,
0x0E, 0xE0, 0x1D, 0xE0, 0x71, 0xF3, 0xC1, 0xFF, 0x00, 0xFC, 0x00, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xF8, 0x00, 0x60, 0x01, 0xC0, 0x03, 0x80, 0x0E,
0x00, 0x1C, 0x00, 0x70, 0x00, 0xE0, 0x03, 0x80, 0x07, 0x00, 0x1C, 0x00,
0x38, 0x00, 0x60, 0x01, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x70,
0x00, 0xE0, 0x03, 0x80, 0x00, 0x07, 0xE0, 0x3F, 0xE0, 0xF1, 0xE3, 0x80,
0xE7, 0x01, 0xCE, 0x03, 0x9C, 0x07, 0x1C, 0x1C, 0x3C, 0x78, 0x3F, 0xC0,
0x1F, 0x00, 0xFF, 0x83, 0x87, 0x8E, 0x03, 0xB8, 0x03, 0xF0, 0x07, 0xE0,
0x0F, 0xC0, 0x1F, 0xC0, 0x73, 0xE3, 0xE3, 0xFF, 0x81, 0xFC, 0x00, 0x0F,
0xC0, 0x7F, 0xE1, 0xF3, 0xE3, 0x81, 0xEE, 0x01, 0xDC, 0x01, 0xB8, 0x03,
0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1D, 0xC0, 0x7B, 0xC3, 0xF3, 0xFE, 0xE1,
0xF1, 0xC0, 0x03, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xE1, 0x0F,
0x83, 0xFE, 0x07, 0xE0, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x0F,
0xFF, 0xF0, 0x7B, 0xDE, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3D, 0xEE,
0x73, 0xB9, 0xCC, 0x00, 0x00, 0x02, 0x00, 0x1C, 0x01, 0xF8, 0x0F, 0xC0,
0x7C, 0x03, 0xE0, 0x3F, 0x00, 0x70, 0x00, 0x7C, 0x00, 0x3E, 0x00, 0x1F,
0x00, 0x0F, 0xC0, 0x07, 0xE0, 0x01, 0xC0, 0x00, 0x80, 0xFF, 0xFF, 0xFF,
0xFC, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3F, 0xFF, 0xFF, 0xFF,
0x80, 0x01, 0xC0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0x7C, 0x00, 0x3E, 0x00,
0x1F, 0x80, 0x07, 0x00, 0x7C, 0x03, 0xE0, 0x1F, 0x01, 0xF8, 0x0F, 0xC0,
0x1C, 0x00, 0x20, 0x00, 0x00, 0x1F, 0x87, 0xFF, 0x3F, 0x7C, 0x80, 0x70,
0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x70, 0x0F, 0x00, 0xF0, 0x0F,
0x00, 0x70, 0x03, 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xC0,
0x1E, 0x00, 0xF0, 0x03, 0x00, 0x01, 0xF8, 0x00, 0xFF, 0xC0, 0x38, 0x1C,
0x0E, 0x01, 0xC3, 0x80, 0x1C, 0xE0, 0x01, 0x98, 0x3F, 0x33, 0x1F, 0xE7,
0xE7, 0x0C, 0x78, 0xC1, 0x8F, 0x38, 0x31, 0xE7, 0x06, 0x3C, 0xC0, 0xC7,
0x98, 0x38, 0xF3, 0x07, 0x1E, 0x70, 0xE6, 0xC6, 0x34, 0xDC, 0xFE, 0xF9,
0x8F, 0x8E, 0x38, 0x00, 0x03, 0x00, 0x00, 0x70, 0x00, 0x07, 0x80, 0xC0,
0x3F, 0xF8, 0x01, 0xFC, 0x00, 0x01, 0xE0, 0x00, 0x78, 0x00, 0x1E, 0x00,
0x0F, 0xC0, 0x03, 0xF0, 0x00, 0xCC, 0x00, 0x73, 0x80, 0x1C, 0xE0, 0x06,
0x18, 0x03, 0x87, 0x00, 0xE1, 0xC0, 0x38, 0x30, 0x1C, 0x0E, 0x07, 0xFF,
0x81, 0xFF, 0xE0, 0xE0, 0x1C, 0x38, 0x07, 0x0C, 0x00, 0xC7, 0x00, 0x39,
0xC0, 0x0E, 0xE0, 0x01, 0xB8, 0x00, 0x70, 0xFF, 0xE0, 0xFF, 0xF8, 0xE0,
0xFC, 0xE0, 0x1E, 0xE0, 0x0E, 0xE0, 0x0E, 0xE0, 0x0E, 0xE0, 0x0E, 0xE0,
0x3C, 0xFF, 0xF0, 0xFF, 0xF0, 0xE0, 0x7C, 0xE0, 0x0E, 0xE0, 0x07, 0xE0,
0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x0E, 0xE0, 0x7E, 0xFF,
0xFC, 0xFF, 0xF0, 0x01, 0xFC, 0x0F, 0xFF, 0x1F, 0xFE, 0x3C, 0x02, 0x38,
0x00, 0x70, 0x00, 0x70, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0,
0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x70,
0x00, 0x78, 0x00, 0x3C, 0x00, 0x1F, 0xFE, 0x0F, 0xFE, 0x03, 0xFC, 0xFF,
0x80, 0xFF, 0xF0, 0xE3, 0xF8, 0xE0, 0x3C, 0xE0, 0x1C, 0xE0, 0x0E, 0xE0,
0x0E, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0,
0x07, 0xE0, 0x07, 0xE0, 0x07, 0xE0, 0x0E, 0xE0, 0x0E, 0xE0, 0x1C, 0xE0,
0x7C, 0xE3, 0xF8, 0xFF, 0xE0, 0xFF, 0x80, 0xFF, 0xFF, 0xFF, 0xF8, 0x01,
0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0xFF, 0xBF,
0xFD, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00,
0x38, 0x01, 0xC0, 0x0F, 0xFF, 0xFF, 0xFC, 0xFF, 0xFF, 0xFF, 0xF8, 0x01,
0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x3F,
0xFD, 0xFF, 0xEE, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00,
0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x00, 0x03, 0xF8, 0x1F, 0xFC, 0x7F,
0xF1, 0xE0, 0x27, 0x80, 0x0E, 0x00, 0x1C, 0x00, 0x70, 0x00, 0xE0, 0x01,
0xC0, 0x03, 0x81, 0xFF, 0x03, 0xFE, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xB8,
0x07, 0x70, 0x0E, 0xF0, 0x1C, 0xF0, 0x38, 0xFF, 0xF0, 0xFF, 0xE0, 0xFF,
0x00, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01,
0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x7E,
0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80,
0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xC0, 0xFF, 0xFF, 0xFC, 0x38, 0x07,
0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00,
0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x0F, 0xFF,
0xFF, 0xC0, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C,
0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80,
0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x03, 0xC0, 0x1D, 0xFF, 0xCF, 0xFC,
0x3F, 0x80, 0xE0, 0x0F, 0xC0, 0x3B, 0x80, 0xE7, 0x03, 0x8E, 0x0E, 0x1C,
0x38, 0x38, 0xF0, 0x71, 0xC0, 0xE7, 0x01, 0xDC, 0x03, 0xFC, 0x07, 0xF8,
0x0F, 0x38, 0x1C, 0x78, 0x38, 0x70, 0x70, 0x70, 0xE0, 0xF1, 0xC0, 0xE3,
0x80, 0xE7, 0x01, 0xEE, 0x01, 0xDC, 0x01, 0xC0, 0xE0, 0x0E, 0x00, 0xE0,
0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0,
0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0,
0x0E, 0x00, 0xFF, 0xFF, 0xFF, 0xF0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7F, 0x81,
0xFD, 0x83, 0x7B, 0x06, 0xF6, 0x0D, 0xEC, 0x1B, 0xD8, 0x77, 0x98, 0xCF,
0x31, 0x9E, 0x63, 0x3C, 0xC6, 0x79, 0x98, 0xF1, 0xB1, 0xE3, 0x63, 0xC6,
0xC7, 0x8D, 0x8F, 0x0E, 0x1E, 0x1C, 0x3C, 0x38, 0x78, 0x70, 0xC0, 0xE0,
0x0F, 0xE0, 0x1F, 0xE0, 0x3F, 0xC0, 0x7D, 0xC0, 0xFB, 0x81, 0xF3, 0x83,
0xF7, 0x07, 0xE7, 0x0F, 0xCE, 0x1F, 0x8E, 0x3F, 0x1C, 0x7E, 0x1C, 0xFC,
0x39, 0xF8, 0x3B, 0xF0, 0x77, 0xE0, 0x77, 0xC0, 0xEF, 0x80, 0xFF, 0x00,
0xFE, 0x01, 0xFC, 0x01, 0xC0, 0x07, 0xF0, 0x0F, 0xFC, 0x0F, 0xDF, 0x87,
0x01, 0xC7, 0x00, 0x73, 0x80, 0x3B, 0xC0, 0x1D, 0xC0, 0x07, 0xE0, 0x03,
0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00, 0x1F, 0x80,
0x0F, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x8E, 0x03, 0x87, 0xEF, 0x81,
0xFF, 0x80, 0x3F, 0x80, 0xFF, 0xC3, 0xFF, 0xCE, 0x1F, 0xB8, 0x0E, 0xE0,
0x1F, 0x80, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0xEE, 0x07, 0xBF,
0xFC, 0xFF, 0xC3, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E,
0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x00, 0x07, 0xF0, 0x0F, 0xFC, 0x0F,
0xDF, 0x87, 0x01, 0xC7, 0x00, 0x73, 0x80, 0x3B, 0xC0, 0x1D, 0xC0, 0x07,
0xE0, 0x03, 0xF0, 0x01, 0xF8, 0x00, 0xFC, 0x00, 0x7E, 0x00, 0x3F, 0x00,
0x1F, 0x80, 0x0F, 0xE0, 0x0E, 0x70, 0x07, 0x38, 0x03, 0x8E, 0x03, 0x87,
0xEF, 0x81, 0xFF, 0x80, 0x3F, 0xC0, 0x00, 0xE0, 0x00, 0x38, 0x00, 0x1E,
0x00, 0x07, 0xC0, 0x01, 0xC0, 0x00, 0x60, 0xFF, 0x81, 0xFF, 0xC3, 0x8F,
0xC7, 0x03, 0x8E, 0x03, 0x9C, 0x07, 0x38, 0x0E, 0x70, 0x1C, 0xE0, 0x39,
0xC0, 0xE3, 0x83, 0xC7, 0xFF, 0x0F, 0xF8, 0x1C, 0x70, 0x38, 0x70, 0x70,
0x70, 0xE0, 0xE1, 0xC0, 0xE3, 0x80, 0xE7, 0x01, 0xEE, 0x01, 0xDC, 0x01,
0xC0, 0x0F, 0xF8, 0x7F, 0xFD, 0xFF, 0xF7, 0x80, 0x2E, 0x00, 0x1C, 0x00,
0x38, 0x00, 0x78, 0x00, 0x78, 0x00, 0x7C, 0x00, 0x7F, 0x00, 0x3F, 0x80,
0x0F, 0xC0, 0x03, 0x80, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1E, 0x00,
0x77, 0xE7, 0xEF, 0xFF, 0x87, 0xF8, 0x00, 0xFF, 0xFF, 0xFF, 0xFC, 0x0E,
0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80,
0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01,
0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70,
0x00, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01,
0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E,
0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xE0, 0x3D, 0xC0,
0x73, 0xF7, 0xC3, 0xFF, 0x01, 0xFC, 0x00, 0xE0, 0x01, 0xD8, 0x00, 0xE7,
0x00, 0x39, 0xC0, 0x0E, 0x30, 0x03, 0x0E, 0x01, 0xC3, 0x80, 0x70, 0x60,
0x18, 0x1C, 0x0E, 0x07, 0x03, 0x80, 0xC0, 0xC0, 0x38, 0x70, 0x0E, 0x1C,
0x01, 0x86, 0x00, 0x73, 0x80, 0x1C, 0xE0, 0x03, 0x30, 0x00, 0xFC, 0x00,
0x3F, 0x00, 0x07, 0x80, 0x01, 0xE0, 0x00, 0x78, 0x00, 0xE0, 0x00, 0xFC,
0x00, 0x1F, 0x80, 0x03, 0xB0, 0x00, 0x76, 0x00, 0x0C, 0xC0, 0x01, 0x9C,
0x00, 0x33, 0x87, 0x06, 0x70, 0xE0, 0xCE, 0x36, 0x38, 0xC6, 0xC7, 0x18,
0xD8, 0xE3, 0x1B, 0x98, 0x67, 0x33, 0x0E, 0xC6, 0x61, 0xD8, 0xEC, 0x3B,
0x0D, 0x83, 0xC1, 0xB0, 0x78, 0x36, 0x0F, 0x03, 0xC1, 0xE0, 0x70, 0x38,
0x0E, 0x00, 0xE0, 0x07, 0x38, 0x07, 0x0E, 0x03, 0x87, 0x03, 0x81, 0xC3,
0x80, 0xE1, 0xC0, 0x39, 0xC0, 0x0E, 0xE0, 0x07, 0xE0, 0x01, 0xE0, 0x00,
0x70, 0x00, 0x78, 0x00, 0x7E, 0x00, 0x3B, 0x80, 0x39, 0xC0, 0x1C, 0x70,
0x1C, 0x1C, 0x0C, 0x0E, 0x0E, 0x03, 0x8E, 0x01, 0xC7, 0x00, 0x77, 0x00,
0x1C, 0xE0, 0x03, 0xB8, 0x03, 0x9C, 0x01, 0xC7, 0x01, 0xC3, 0x80, 0xE0,
0xE0, 0xE0, 0x30, 0x60, 0x1C, 0x70, 0x06, 0x30, 0x03, 0xB8, 0x00, 0xF8,
0x00, 0x7C, 0x00, 0x1C, 0x00, 0x0E, 0x00, 0x07, 0x00, 0x03, 0x80, 0x01,
0xC0, 0x00, 0xE0, 0x00, 0x70, 0x00, 0x38, 0x00, 0x1C, 0x00, 0x0E, 0x00,
0xFF, 0xFF, 0xFF, 0xFC, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x07, 0x00,
0x1C, 0x00, 0x70, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x1C, 0x00, 0x70,
0x01, 0xC0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0x70, 0x01, 0xC0, 0x07,
0x00, 0x0F, 0xFF, 0xFF, 0xFF, 0xC0, 0xFF, 0xFF, 0xF8, 0x1C, 0x0E, 0x07,
0x03, 0x81, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0,
0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x7F, 0xFF,
0xE0, 0xE0, 0x03, 0x00, 0x1C, 0x00, 0x60, 0x03, 0x80, 0x0C, 0x00, 0x70,
0x01, 0x80, 0x0E, 0x00, 0x70, 0x01, 0xC0, 0x0E, 0x00, 0x38, 0x01, 0xC0,
0x06, 0x00, 0x38, 0x00, 0xC0, 0x07, 0x00, 0x18, 0x00, 0xE0, 0x03, 0x00,
0x1C, 0xFF, 0xFF, 0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81,
0xC0, 0xE0, 0x70, 0x38, 0x1C, 0x0E, 0x07, 0x03, 0x81, 0xC0, 0xE0, 0x70,
0x38, 0x1C, 0x0E, 0x07, 0x03, 0xFF, 0xFF, 0xE0, 0x03, 0x00, 0x07, 0x00,
0x1E, 0x00, 0x3E, 0x00, 0xCC, 0x01, 0x9C, 0x07, 0x18, 0x0C, 0x38, 0x38,
0x30, 0x60, 0x70, 0xC0, 0x63, 0x00, 0xE6, 0x00, 0xDC, 0x01, 0xC0, 0xFF,
0xFF, 0xFF, 0xFF, 0xFC, 0xF1, 0xC3, 0x86, 0x0C, 0x0F, 0xE1, 0xFF, 0xE3,
0xC7, 0x80, 0x07, 0x00, 0x1C, 0x00, 0x70, 0x01, 0xC1, 0xFF, 0x3F, 0xFD,
0xE0, 0x7E, 0x01, 0xF8, 0x07, 0xE0, 0x1F, 0x80, 0xFF, 0x0F, 0xDF, 0xF3,
0x1F, 0x8C, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C,
0x00, 0x38, 0x00, 0x73, 0xF0, 0xEF, 0xF1, 0xF8, 0xF3, 0xC0, 0x77, 0x00,
0xEE, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F,
0x80, 0x3F, 0x00, 0xEF, 0x01, 0xDF, 0x8F, 0x33, 0xFC, 0x63, 0xF0, 0x07,
0xF0, 0xFF, 0xCF, 0xDC, 0xF0, 0x07, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00,
0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x07, 0x00, 0x3C, 0x00, 0xFD, 0xE3,
0xFF, 0x07, 0xF0, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00,
0xE0, 0x01, 0xC0, 0x03, 0x87, 0xE7, 0x1F, 0xEE, 0x78, 0xFD, 0xC0, 0x7B,
0x80, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0,
0x1F, 0x80, 0x3B, 0x80, 0x77, 0x01, 0xE7, 0x8F, 0xC7, 0xF9, 0x87, 0xE3,
0x07, 0xE0, 0x3F, 0xE0, 0xF1, 0xE3, 0x80, 0xE7, 0x00, 0xFC, 0x01, 0xF8,
0x03, 0xFF, 0xFF, 0xFF, 0xFF, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x07, 0x00,
0x0F, 0x00, 0x0F, 0xDF, 0x0F, 0xFE, 0x07, 0xF0, 0x00, 0xFE, 0x07, 0xFC,
0x0E, 0x10, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0, 0x7F, 0xFE, 0xFF,
0xFC, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0xE0, 0x01, 0xC0,
0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00,
0xE0, 0x01, 0xC0, 0x03, 0x80, 0x0F, 0xFE, 0x3F, 0xFC, 0xE1, 0xC3, 0x81,
0xC7, 0x03, 0x8E, 0x07, 0x1C, 0x0E, 0x38, 0x1C, 0x38, 0x70, 0x7F, 0xC0,
0x3F, 0x00, 0xC0, 0x03, 0x00, 0x07, 0x00, 0x0F, 0xFE, 0x0F, 0xFE, 0x78,
0x7F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFE, 0x07, 0x9F, 0xFE,
0x0F, 0xF0, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C,
0x00, 0x38, 0x00, 0x71, 0xF8, 0xEF, 0xF9, 0xFC, 0x7B, 0xC0, 0x7F, 0x80,
0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F,
0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0x07,
0x00, 0x38, 0x01, 0xC0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0xE0,
0x7F, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00,
0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x83, 0xFF,
0xFF, 0xFF, 0x00, 0xE0, 0x1C, 0x03, 0x80, 0x00, 0x00, 0x00, 0x00, 0x01,
0xFF, 0x3F, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07,
0x00, 0xE0, 0x1C, 0x03, 0x80, 0x70, 0x0E, 0x01, 0xC0, 0x38, 0x07, 0x00,
0xE0, 0x1C, 0x03, 0x80, 0x7C, 0x3D, 0xFF, 0x3F, 0xC0, 0xE0, 0x01, 0xC0,
0x03, 0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x0E,
0xE0, 0x39, 0xC0, 0xE3, 0x83, 0x87, 0x0E, 0x0E, 0x38, 0x1D, 0xE0, 0x3F,
0x80, 0x7F, 0x80, 0xF7, 0x81, 0xC7, 0x03, 0x87, 0x07, 0x07, 0x0E, 0x07,
0x1C, 0x07, 0x38, 0x0F, 0x70, 0x0F, 0x7F, 0x03, 0xF8, 0x01, 0xC0, 0x0E,
0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0,
0x0E, 0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01,
0xC0, 0x0E, 0x00, 0x70, 0x03, 0x83, 0xFF, 0xFF, 0xFF, 0xCF, 0x1E, 0x6F,
0xDF, 0xBC, 0xED, 0xFC, 0x38, 0x7E, 0x1C, 0x3F, 0x0E, 0x1F, 0x87, 0x0F,
0xC3, 0x87, 0xE1, 0xC3, 0xF0, 0xE1, 0xF8, 0x70, 0xFC, 0x38, 0x7E, 0x1C,
0x3F, 0x0E, 0x1F, 0x87, 0x0F, 0xC3, 0x87, 0xE1, 0xC3, 0x80, 0xC3, 0xF1,
0x9F, 0xF3, 0xF8, 0xF7, 0x80, 0xFF, 0x00, 0xFC, 0x01, 0xF8, 0x03, 0xF0,
0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00, 0xFC, 0x01,
0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0E, 0x07, 0xC0, 0x3F, 0xE0, 0xF1, 0xE3,
0x80, 0xE7, 0x01, 0xDC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0,
0x1F, 0x80, 0x3F, 0x00, 0x77, 0x01, 0xCE, 0x03, 0x8F, 0x1E, 0x0F, 0xF8,
0x07, 0xC0, 0xC7, 0xE1, 0xDF, 0xE3, 0xF1, 0xE7, 0x80, 0xEE, 0x01, 0xDC,
0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00,
0x7E, 0x01, 0xDE, 0x03, 0xBF, 0x1E, 0x77, 0xF8, 0xE7, 0xE1, 0xC0, 0x03,
0x80, 0x07, 0x00, 0x0E, 0x00, 0x1C, 0x00, 0x38, 0x00, 0x70, 0x00, 0x0F,
0xC6, 0x3F, 0xCC, 0xF1, 0xFB, 0x80, 0xF7, 0x00, 0xFC, 0x01, 0xF8, 0x03,
0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x77, 0x00, 0xEE,
0x03, 0xCF, 0x1F, 0x8F, 0xF7, 0x0F, 0xCE, 0x00, 0x1C, 0x00, 0x38, 0x00,
0x70, 0x00, 0xE0, 0x01, 0xC0, 0x03, 0x80, 0x07, 0xC3, 0xEC, 0xFF, 0xDE,
0x6F, 0x00, 0xF0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0,
0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0xE0, 0x00, 0x1F, 0xE3,
0xFF, 0xFE, 0x1D, 0xC0, 0x0E, 0x00, 0x70, 0x01, 0xE0, 0x07, 0xE0, 0x0F,
0xC0, 0x1F, 0x80, 0x1E, 0x00, 0x70, 0x03, 0x80, 0x1F, 0xC3, 0xDF, 0xFC,
0x7F, 0x80, 0x06, 0x00, 0x18, 0x00, 0xE0, 0x03, 0x80, 0x7F, 0xFF, 0xFF,
0xF0, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E,
0x00, 0x38, 0x00, 0xE0, 0x03, 0x80, 0x0E, 0x00, 0x38, 0x00, 0x70, 0x41,
0xFF, 0x01, 0xFC, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F, 0x00, 0x7E, 0x00,
0xFC, 0x01, 0xF8, 0x03, 0xF0, 0x07, 0xE0, 0x0F, 0xC0, 0x1F, 0x80, 0x3F,
0x00, 0x7E, 0x00, 0xFE, 0x03, 0xDE, 0x3F, 0x9F, 0xF3, 0x1F, 0x86, 0xE0,
0x03, 0xB0, 0x01, 0x9C, 0x01, 0xCE, 0x00, 0xE3, 0x80, 0xE1, 0xC0, 0x70,
0x60, 0x30, 0x38, 0x38, 0x1C, 0x1C, 0x07, 0x1C, 0x03, 0x8E, 0x00, 0xC6,
0x00, 0x77, 0x00, 0x3B, 0x80, 0x0D, 0x80, 0x07, 0xC0, 0x01, 0xE0, 0x00,
0xE0, 0xE0, 0xFC, 0x1C, 0x1D, 0x83, 0xC3, 0x30, 0xD8, 0x66, 0x1B, 0x0C,
0xE3, 0x61, 0x9C, 0x6C, 0x71, 0x9D, 0xCC, 0x33, 0x19, 0x86, 0x63, 0x30,
0xCC, 0x66, 0x1D, 0x8D, 0xC1, 0xE0, 0xF0, 0x3C, 0x1E, 0x07, 0x83, 0xC0,
0xF0, 0x78, 0x1E, 0x0F, 0x00, 0x70, 0x07, 0x3C, 0x07, 0x8E, 0x03, 0x83,
0x83, 0x80, 0xE3, 0x80, 0x3B, 0x80, 0x1F, 0xC0, 0x07, 0xC0, 0x01, 0xC0,
0x01, 0xF0, 0x01, 0xDC, 0x01, 0xE7, 0x00, 0xE3, 0x80, 0xE0, 0xE0, 0xE0,
0x38, 0xE0, 0x0E, 0xF0, 0x07, 0x80, 0xE0, 0x03, 0xB0, 0x01, 0x9C, 0x01,
0xCE, 0x00, 0xE3, 0x80, 0xE1, 0xC0, 0x70, 0x70, 0x30, 0x38, 0x38, 0x0C,
0x1C, 0x07, 0x1C, 0x03, 0x8E, 0x00, 0xEE, 0x00, 0x77, 0x00, 0x1B, 0x00,
0x0F, 0x80, 0x03, 0xC0, 0x01, 0xC0, 0x00, 0xE0, 0x00, 0x60, 0x00, 0x70,
0x00, 0x70, 0x00, 0x78, 0x03, 0xF8, 0x01, 0xF0, 0x00, 0x7F, 0xFB, 0xFF,
0xC0, 0x0E, 0x00, 0xE0, 0x0E, 0x00, 0x60, 0x07, 0x00, 0x70, 0x07, 0x00,
0x70, 0x03, 0x00, 0x38, 0x03, 0x80, 0x38, 0x03, 0x80, 0x1F, 0xFF, 0xFF,
0xF8, 0x00, 0x78, 0x0F, 0xC0, 0xF8, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E,
0x00, 0x70, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x1E, 0x0F, 0xE0, 0x7E, 0x00,
0x7C, 0x00, 0xE0, 0x03, 0x80, 0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01,
0xC0, 0x0E, 0x00, 0x70, 0x03, 0xE0, 0x0F, 0xC0, 0x1E, 0xFF, 0xFF, 0xFF,
0xFF, 0xFF, 0xFF, 0xFF, 0xFC, 0xF0, 0x07, 0xE0, 0x0F, 0x80, 0x1C, 0x00,
0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x0E, 0x00, 0x70, 0x03, 0x80, 0x0F,
0x00, 0x3F, 0x80, 0xFC, 0x1F, 0x00, 0xE0, 0x0E, 0x00, 0x70, 0x03, 0x80,
0x1C, 0x00, 0xE0, 0x07, 0x00, 0x38, 0x01, 0xC0, 0x3C, 0x07, 0xE0, 0x3C,
0x00, 0x3E, 0x03, 0xFF, 0x9F, 0x9F, 0xFC, 0x07, 0xC0 };
const GFXglyph NotoMono16pt7bGlyphs[] PROGMEM = {
{ 0, 1, 1, 19, 0, 0 }, // 0x20 ' '
{ 1, 4, 22, 19, 8, -21 }, // 0x21 '!'
{ 12, 11, 8, 19, 4, -21 }, // 0x22 '"'
{ 23, 17, 22, 19, 1, -21 }, // 0x23 '#'
{ 70, 13, 25, 19, 3, -23 }, // 0x24 '$'
{ 111, 19, 22, 19, 0, -21 }, // 0x25 '%'
{ 164, 18, 22, 19, 1, -21 }, // 0x26 '&'
{ 214, 4, 8, 19, 8, -21 }, // 0x27 '''
{ 218, 11, 27, 19, 4, -21 }, // 0x28 '('
{ 256, 10, 27, 19, 5, -21 }, // 0x29 ')'
{ 290, 15, 14, 19, 2, -23 }, // 0x2A '*'
{ 317, 14, 14, 19, 2, -17 }, // 0x2B '+'
{ 342, 5, 8, 19, 7, -3 }, // 0x2C ','
{ 347, 11, 3, 19, 4, -9 }, // 0x2D '-'
{ 352, 5, 5, 19, 7, -4 }, // 0x2E '.'
{ 356, 13, 22, 19, 3, -21 }, // 0x2F '/'
{ 392, 15, 22, 19, 2, -21 }, // 0x30 '0'
{ 434, 8, 22, 19, 4, -21 }, // 0x31 '1'
{ 456, 15, 22, 19, 2, -21 }, // 0x32 '2'
{ 498, 14, 22, 19, 2, -21 }, // 0x33 '3'
{ 537, 16, 22, 19, 1, -21 }, // 0x34 '4'
{ 581, 13, 22, 19, 3, -21 }, // 0x35 '5'
{ 617, 15, 22, 19, 2, -21 }, // 0x36 '6'
{ 659, 15, 22, 19, 2, -21 }, // 0x37 '7'
{ 701, 15, 22, 19, 2, -21 }, // 0x38 '8'
{ 743, 15, 22, 19, 2, -21 }, // 0x39 '9'
{ 785, 4, 17, 19, 8, -16 }, // 0x3A ':'
{ 794, 5, 21, 19, 7, -16 }, // 0x3B ';'
{ 808, 15, 15, 19, 2, -18 }, // 0x3C '<'
{ 837, 15, 8, 19, 2, -14 }, // 0x3D '='
{ 852, 15, 15, 19, 2, -18 }, // 0x3E '>'
{ 881, 13, 22, 19, 3, -21 }, // 0x3F '?'
{ 917, 19, 25, 19, 0, -21 }, // 0x40 '@'
{ 977, 18, 22, 19, 1, -21 }, // 0x41 'A'
{ 1027, 16, 22, 19, 2, -21 }, // 0x42 'B'
{ 1071, 16, 22, 19, 2, -21 }, // 0x43 'C'
{ 1115, 16, 22, 19, 2, -21 }, // 0x44 'D'
{ 1159, 13, 22, 19, 3, -21 }, // 0x45 'E'
{ 1195, 13, 22, 19, 4, -21 }, // 0x46 'F'
{ 1231, 15, 22, 19, 2, -21 }, // 0x47 'G'
{ 1273, 15, 22, 19, 2, -21 }, // 0x48 'H'
{ 1315, 11, 22, 19, 4, -21 }, // 0x49 'I'
{ 1346, 13, 22, 19, 2, -21 }, // 0x4A 'J'
{ 1382, 15, 22, 19, 3, -21 }, // 0x4B 'K'
{ 1424, 12, 22, 19, 4, -21 }, // 0x4C 'L'
{ 1457, 15, 22, 19, 2, -21 }, // 0x4D 'M'
{ 1499, 15, 22, 19, 2, -21 }, // 0x4E 'N'
{ 1541, 17, 22, 19, 1, -21 }, // 0x4F 'O'
{ 1588, 14, 22, 19, 3, -21 }, // 0x50 'P'
{ 1627, 17, 28, 19, 1, -21 }, // 0x51 'Q'
{ 1687, 15, 22, 19, 3, -21 }, // 0x52 'R'
{ 1729, 15, 22, 19, 2, -21 }, // 0x53 'S'
{ 1771, 15, 22, 19, 2, -21 }, // 0x54 'T'
{ 1813, 15, 22, 19, 2, -21 }, // 0x55 'U'
{ 1855, 18, 22, 19, 1, -21 }, // 0x56 'V'
{ 1905, 19, 22, 19, 0, -21 }, // 0x57 'W'
{ 1958, 17, 22, 19, 1, -21 }, // 0x58 'X'
{ 2005, 17, 22, 19, 1, -21 }, // 0x59 'Y'
{ 2052, 15, 22, 19, 2, -21 }, // 0x5A 'Z'
{ 2094, 9, 27, 19, 6, -21 }, // 0x5B '['
{ 2125, 13, 22, 19, 3, -21 }, // 0x5C '\'
{ 2161, 9, 27, 19, 4, -21 }, // 0x5D ']'
{ 2192, 15, 14, 19, 2, -21 }, // 0x5E '^'
{ 2219, 19, 2, 19, 0, 4 }, // 0x5F '_'
{ 2224, 6, 5, 19, 7, -23 }, // 0x60 '`'
{ 2228, 14, 17, 19, 2, -16 }, // 0x61 'a'
{ 2258, 15, 24, 19, 2, -23 }, // 0x62 'b'
{ 2303, 13, 17, 19, 3, -16 }, // 0x63 'c'
{ 2331, 15, 24, 19, 2, -23 }, // 0x64 'd'
{ 2376, 15, 17, 19, 2, -16 }, // 0x65 'e'
{ 2408, 15, 24, 19, 2, -23 }, // 0x66 'f'
{ 2453, 15, 24, 19, 2, -16 }, // 0x67 'g'
{ 2498, 15, 24, 19, 2, -23 }, // 0x68 'h'
{ 2543, 13, 24, 19, 3, -23 }, // 0x69 'i'
{ 2582, 11, 31, 19, 2, -23 }, // 0x6A 'j'
{ 2625, 15, 24, 19, 3, -23 }, // 0x6B 'k'
{ 2670, 13, 24, 19, 3, -23 }, // 0x6C 'l'
{ 2709, 17, 17, 19, 1, -16 }, // 0x6D 'm'
{ 2746, 15, 17, 19, 2, -16 }, // 0x6E 'n'
{ 2778, 15, 17, 19, 2, -16 }, // 0x6F 'o'
{ 2810, 15, 24, 19, 2, -16 }, // 0x70 'p'
{ 2855, 15, 24, 19, 2, -16 }, // 0x71 'q'
{ 2900, 12, 17, 19, 4, -16 }, // 0x72 'r'
{ 2926, 13, 17, 19, 3, -16 }, // 0x73 's'
{ 2954, 14, 21, 19, 2, -20 }, // 0x74 't'
{ 2991, 15, 17, 19, 2, -16 }, // 0x75 'u'
{ 3023, 17, 17, 19, 1, -16 }, // 0x76 'v'
{ 3060, 19, 17, 19, 0, -16 }, // 0x77 'w'
{ 3101, 17, 17, 19, 1, -16 }, // 0x78 'x'
{ 3138, 17, 24, 19, 1, -16 }, // 0x79 'y'
{ 3189, 13, 17, 19, 3, -16 }, // 0x7A 'z'
{ 3217, 13, 27, 19, 3, -21 }, // 0x7B '{'
{ 3261, 2, 31, 19, 8, -23 }, // 0x7C '|'
{ 3269, 13, 27, 19, 3, -21 }, // 0x7D '}'
{ 3313, 15, 4, 19, 2, -12 } }; // 0x7E '~'
const GFXfont NotoMono16pt7b PROGMEM = {
(uint8_t *)NotoMono16pt7bBitmaps,
(GFXglyph *)NotoMono16pt7bGlyphs,
0x20, 0x7E, 37 };
// Approx. 3993 bytes

View file

@ -0,0 +1,185 @@
const uint8_t NotoMono8pt7bBitmaps[] PROGMEM = {
0x00, 0xFF, 0xFD, 0x0F, 0xCF, 0x3C, 0xF3, 0x08, 0x86, 0x61, 0x11, 0xFF,
0x11, 0x0C, 0xC2, 0x23, 0xFE, 0x22, 0x08, 0x84, 0x41, 0x10, 0x10, 0x21,
0xFE, 0x89, 0x1A, 0x1C, 0x0E, 0x16, 0x26, 0x5F, 0xE1, 0x02, 0x00, 0x71,
0xA2, 0x48, 0xB2, 0x28, 0x74, 0x01, 0x00, 0x80, 0x2E, 0x14, 0x4D, 0x12,
0x45, 0x8E, 0x38, 0x36, 0x11, 0x08, 0x82, 0x81, 0x89, 0xE5, 0x96, 0x86,
0x63, 0x33, 0xCF, 0x30, 0xFF, 0x11, 0x98, 0x8C, 0x63, 0x10, 0xC6, 0x30,
0x86, 0x18, 0x40, 0x43, 0x0C, 0x21, 0x8C, 0x61, 0x18, 0xC6, 0x23, 0x31,
0x00, 0x10, 0x22, 0x4F, 0xF2, 0x8D, 0x99, 0x00, 0x10, 0x20, 0x47, 0xF1,
0x02, 0x04, 0x00, 0x6F, 0x60, 0xFC, 0xF0, 0x0C, 0x20, 0x86, 0x10, 0xC3,
0x08, 0x61, 0x04, 0x30, 0x3C, 0x66, 0x42, 0xC3, 0xC3, 0x81, 0x81, 0xC3,
0xC3, 0x42, 0x66, 0x3C, 0x37, 0xD1, 0x11, 0x11, 0x11, 0x11, 0x3C, 0xE3,
0x03, 0x01, 0x03, 0x02, 0x04, 0x08, 0x10, 0x20, 0xC0, 0xFF, 0x7E, 0xC3,
0x03, 0x03, 0x06, 0x38, 0x06, 0x03, 0x01, 0x03, 0x86, 0xFC, 0x06, 0x07,
0x02, 0x83, 0x43, 0x21, 0x11, 0x09, 0x84, 0xFF, 0x81, 0x00, 0x80, 0x40,
0xFE, 0xC0, 0xC0, 0x80, 0x80, 0xFC, 0x06, 0x03, 0x01, 0x03, 0x86, 0xFC,
0x1E, 0x30, 0x40, 0xC0, 0xFC, 0xE2, 0xC3, 0x81, 0xC1, 0xC3, 0x66, 0x3C,
0xFF, 0x03, 0x02, 0x02, 0x06, 0x04, 0x0C, 0x0C, 0x18, 0x18, 0x10, 0x30,
0x3C, 0xC3, 0x81, 0xC3, 0x46, 0x3C, 0x66, 0xC3, 0x81, 0xC3, 0xC2, 0x3C,
0x3C, 0x66, 0xC3, 0x83, 0x81, 0xC3, 0x47, 0x3F, 0x03, 0x02, 0x04, 0x78,
0xF0, 0x03, 0xC0, 0x6C, 0x00, 0x03, 0x7B, 0x00, 0x01, 0x06, 0x38, 0xE0,
0xE0, 0x38, 0x06, 0x01, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x80, 0x60, 0x1C,
0x07, 0x07, 0x1C, 0x60, 0x80, 0x7C, 0xC3, 0x03, 0x01, 0x03, 0x06, 0x18,
0x10, 0x30, 0x00, 0x30, 0x30, 0x1E, 0x08, 0x64, 0x09, 0x79, 0x92, 0x68,
0x9A, 0x26, 0x89, 0xA6, 0xF7, 0x64, 0x00, 0x80, 0x1F, 0x00, 0x0C, 0x03,
0x01, 0xE0, 0x48, 0x12, 0x0C, 0xC2, 0x10, 0xFC, 0x61, 0x90, 0x24, 0x0B,
0x03, 0xFE, 0x87, 0x83, 0x83, 0x83, 0xFC, 0x86, 0x83, 0x83, 0x83, 0x86,
0xFC, 0x1F, 0x73, 0x60, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0xC0, 0x60, 0x71,
0x1F, 0xF8, 0x8E, 0x82, 0x83, 0x83, 0x83, 0x83, 0x83, 0x83, 0x86, 0x8C,
0xF8, 0xFF, 0x02, 0x04, 0x08, 0x1F, 0xE0, 0x40, 0x81, 0x02, 0x07, 0xF0,
0xFF, 0x02, 0x04, 0x08, 0x1F, 0xE0, 0x40, 0x81, 0x02, 0x04, 0x00, 0x1E,
0x72, 0x40, 0xC0, 0xC0, 0xC7, 0xC1, 0xC1, 0xC1, 0x41, 0x73, 0x3F, 0x81,
0x81, 0x81, 0x81, 0x81, 0xFF, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xFC,
0x82, 0x08, 0x20, 0x82, 0x08, 0x20, 0x82, 0x3F, 0x02, 0x04, 0x08, 0x10,
0x20, 0x40, 0x81, 0x02, 0x0E, 0x37, 0xC0, 0x81, 0xC1, 0xA1, 0x91, 0x89,
0x85, 0x83, 0x61, 0x18, 0x84, 0x43, 0x20, 0xD0, 0x30, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0xFF, 0xC3, 0xC3, 0xC3,
0xC3, 0xA5, 0xA5, 0xA5, 0xA5, 0x99, 0x99, 0x99, 0x91, 0xC1, 0xC1, 0xA1,
0xA1, 0x91, 0x91, 0x89, 0x89, 0x85, 0x85, 0x83, 0x83, 0x3C, 0x66, 0x42,
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, 0xFC, 0x86, 0x83,
0x83, 0x83, 0x82, 0xFC, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3C, 0x66, 0x42,
0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0xC3, 0x42, 0x66, 0x3C, 0x04, 0x02, 0x01,
0xFC, 0x43, 0x20, 0xD0, 0x68, 0x34, 0x13, 0xF1, 0x18, 0x86, 0x41, 0x20,
0xD0, 0x30, 0x3F, 0xE3, 0xC0, 0xC0, 0xC0, 0x78, 0x0E, 0x03, 0x01, 0x03,
0x86, 0xFC, 0xFF, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10, 0x10,
0x10, 0x10, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0xC3, 0xC3,
0x66, 0x3C, 0xC0, 0xD0, 0x24, 0x09, 0x86, 0x21, 0x08, 0x43, 0x30, 0x48,
0x12, 0x07, 0x80, 0xC0, 0x30, 0x80, 0x70, 0x1C, 0x0F, 0x03, 0x4C, 0x93,
0x24, 0xC9, 0x4A, 0x52, 0x94, 0xA6, 0x18, 0x84, 0xC0, 0xD8, 0x62, 0x10,
0xCC, 0x1E, 0x03, 0x00, 0xC0, 0x78, 0x33, 0x08, 0x44, 0x1B, 0x03, 0xC0,
0x90, 0x66, 0x10, 0x88, 0x12, 0x05, 0x00, 0xC0, 0x20, 0x08, 0x02, 0x00,
0x80, 0x20, 0xFF, 0x03, 0x02, 0x04, 0x0C, 0x08, 0x10, 0x30, 0x20, 0x40,
0xC0, 0xFF, 0xF8, 0x88, 0x88, 0x88, 0x88, 0x88, 0x88, 0xF0, 0xC1, 0x04,
0x18, 0x20, 0xC3, 0x04, 0x18, 0x20, 0x83, 0xF1, 0x11, 0x11, 0x11, 0x11,
0x11, 0x11, 0xF0, 0x18, 0x18, 0x24, 0x24, 0x46, 0x42, 0x83, 0xFF, 0xC0,
0xC8, 0x80, 0x7E, 0x43, 0x03, 0x01, 0x3F, 0xC1, 0x83, 0xC7, 0x7D, 0x80,
0x80, 0x80, 0x80, 0xBC, 0xE6, 0xC3, 0x83, 0x81, 0x83, 0xC3, 0xE6, 0xBC,
0x3F, 0x61, 0xC0, 0xC0, 0x80, 0xC0, 0xC0, 0x61, 0x3F, 0x01, 0x01, 0x01,
0x01, 0x3D, 0x67, 0xC3, 0xC1, 0x81, 0xC1, 0xC3, 0x67, 0x3D, 0x3C, 0x66,
0xC3, 0xC1, 0xFF, 0x80, 0xC0, 0x61, 0x3E, 0x1E, 0x60, 0x81, 0x0F, 0xC4,
0x08, 0x10, 0x20, 0x40, 0x81, 0x02, 0x00, 0x3F, 0xB1, 0x90, 0x48, 0x26,
0x31, 0xF1, 0x80, 0x80, 0x7F, 0x60, 0xE0, 0x38, 0x37, 0xE0, 0x80, 0x80,
0x80, 0x80, 0xBE, 0xE3, 0xC3, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x10,
0x20, 0x00, 0x07, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x8F, 0xE0, 0x0C,
0x30, 0x00, 0x7C, 0x10, 0x41, 0x04, 0x10, 0x41, 0x04, 0x10, 0x43, 0xF8,
0x80, 0x80, 0x80, 0x80, 0x84, 0x88, 0x90, 0xA0, 0xE0, 0x90, 0x88, 0x84,
0x86, 0x70, 0x20, 0x40, 0x81, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x8F,
0xE0, 0xB6, 0xDB, 0xD9, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0xBE, 0xE3,
0xC3, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x3C, 0x66, 0xC3, 0xC3, 0x81,
0xC3, 0xC3, 0x66, 0x3C, 0xBC, 0xE6, 0xC3, 0x83, 0x81, 0x83, 0xC3, 0xE6,
0xBC, 0x80, 0x80, 0x80, 0x80, 0x3D, 0x67, 0xC3, 0xC1, 0x81, 0xC1, 0xC3,
0x67, 0x3D, 0x01, 0x01, 0x01, 0x01, 0x9F, 0x47, 0x04, 0x08, 0x10, 0x20,
0x40, 0x80, 0x7F, 0x18, 0x38, 0x38, 0x30, 0x63, 0xF8, 0x20, 0x43, 0xF9,
0x02, 0x04, 0x08, 0x10, 0x20, 0x60, 0x78, 0x81, 0x81, 0x81, 0x81, 0x81,
0x81, 0xC3, 0xC7, 0x7D, 0xC3, 0x42, 0x42, 0x66, 0x24, 0x24, 0x3C, 0x18,
0x18, 0x8C, 0x73, 0x34, 0xC9, 0x7A, 0x52, 0x94, 0xA5, 0x28, 0x8C, 0x21,
0x00, 0x43, 0x66, 0x24, 0x18, 0x18, 0x3C, 0x24, 0x66, 0xC3, 0xC3, 0x42,
0x42, 0x66, 0x24, 0x24, 0x3C, 0x18, 0x18, 0x18, 0x10, 0x30, 0xE0, 0xFC,
0x30, 0x84, 0x30, 0x84, 0x30, 0xFC, 0x1C, 0xC2, 0x08, 0x20, 0x82, 0x30,
0x60, 0x82, 0x08, 0x20, 0xC1, 0xC0, 0xFF, 0xFF, 0x80, 0xE0, 0xC1, 0x04,
0x10, 0x41, 0x03, 0x18, 0x41, 0x04, 0x10, 0xCE, 0x00, 0x70, 0x99, 0x0E };
const GFXglyph NotoMono8pt7bGlyphs[] PROGMEM = {
{ 0, 1, 1, 10, 0, 0 }, // 0x20 ' '
{ 1, 2, 12, 10, 4, -11 }, // 0x21 '!'
{ 4, 6, 4, 10, 2, -11 }, // 0x22 '"'
{ 7, 10, 12, 10, 0, -11 }, // 0x23 '#'
{ 22, 7, 14, 10, 2, -12 }, // 0x24 '$'
{ 35, 10, 12, 10, 0, -11 }, // 0x25 '%'
{ 50, 9, 12, 10, 1, -11 }, // 0x26 '&'
{ 64, 2, 4, 10, 4, -11 }, // 0x27 '''
{ 65, 5, 15, 10, 3, -11 }, // 0x28 '('
{ 75, 5, 15, 10, 2, -11 }, // 0x29 ')'
{ 85, 7, 7, 10, 1, -12 }, // 0x2A '*'
{ 92, 7, 7, 10, 1, -8 }, // 0x2B '+'
{ 99, 3, 4, 10, 3, -1 }, // 0x2C ','
{ 101, 6, 1, 10, 2, -4 }, // 0x2D '-'
{ 102, 2, 2, 10, 4, -1 }, // 0x2E '.'
{ 103, 6, 12, 10, 2, -11 }, // 0x2F '/'
{ 112, 8, 12, 10, 1, -11 }, // 0x30 '0'
{ 124, 4, 12, 10, 2, -11 }, // 0x31 '1'
{ 130, 8, 12, 10, 1, -11 }, // 0x32 '2'
{ 142, 8, 12, 10, 1, -11 }, // 0x33 '3'
{ 154, 9, 12, 10, 1, -11 }, // 0x34 '4'
{ 168, 8, 12, 10, 1, -11 }, // 0x35 '5'
{ 180, 8, 12, 10, 1, -11 }, // 0x36 '6'
{ 192, 8, 12, 10, 1, -11 }, // 0x37 '7'
{ 204, 8, 12, 10, 1, -11 }, // 0x38 '8'
{ 216, 8, 12, 10, 1, -11 }, // 0x39 '9'
{ 228, 2, 9, 10, 4, -8 }, // 0x3A ':'
{ 231, 3, 11, 10, 3, -8 }, // 0x3B ';'
{ 236, 8, 8, 10, 1, -9 }, // 0x3C '<'
{ 244, 8, 5, 10, 1, -7 }, // 0x3D '='
{ 249, 8, 8, 10, 1, -9 }, // 0x3E '>'
{ 257, 8, 12, 10, 1, -11 }, // 0x3F '?'
{ 269, 10, 13, 10, 0, -11 }, // 0x40 '@'
{ 286, 10, 12, 10, 0, -11 }, // 0x41 'A'
{ 301, 8, 12, 10, 1, -11 }, // 0x42 'B'
{ 313, 8, 12, 10, 1, -11 }, // 0x43 'C'
{ 325, 8, 12, 10, 1, -11 }, // 0x44 'D'
{ 337, 7, 12, 10, 2, -11 }, // 0x45 'E'
{ 348, 7, 12, 10, 2, -11 }, // 0x46 'F'
{ 359, 8, 12, 10, 1, -11 }, // 0x47 'G'
{ 371, 8, 12, 10, 1, -11 }, // 0x48 'H'
{ 383, 6, 12, 10, 2, -11 }, // 0x49 'I'
{ 392, 7, 12, 10, 1, -11 }, // 0x4A 'J'
{ 403, 9, 12, 10, 1, -11 }, // 0x4B 'K'
{ 417, 8, 12, 10, 1, -11 }, // 0x4C 'L'
{ 429, 8, 12, 10, 1, -11 }, // 0x4D 'M'
{ 441, 8, 12, 10, 1, -11 }, // 0x4E 'N'
{ 453, 8, 12, 10, 1, -11 }, // 0x4F 'O'
{ 465, 8, 12, 10, 1, -11 }, // 0x50 'P'
{ 477, 8, 15, 10, 1, -11 }, // 0x51 'Q'
{ 492, 9, 12, 10, 1, -11 }, // 0x52 'R'
{ 506, 8, 12, 10, 1, -11 }, // 0x53 'S'
{ 518, 8, 12, 10, 1, -11 }, // 0x54 'T'
{ 530, 8, 12, 10, 1, -11 }, // 0x55 'U'
{ 542, 10, 12, 10, 0, -11 }, // 0x56 'V'
{ 557, 10, 12, 10, 0, -11 }, // 0x57 'W'
{ 572, 10, 12, 10, 0, -11 }, // 0x58 'X'
{ 587, 10, 12, 10, 0, -11 }, // 0x59 'Y'
{ 602, 8, 12, 10, 1, -11 }, // 0x5A 'Z'
{ 614, 4, 15, 10, 4, -11 }, // 0x5B '['
{ 622, 6, 12, 10, 2, -11 }, // 0x5C '\'
{ 631, 4, 15, 10, 2, -11 }, // 0x5D ']'
{ 639, 8, 7, 10, 1, -11 }, // 0x5E '^'
{ 646, 10, 1, 10, 0, 2 }, // 0x5F '_'
{ 648, 3, 3, 10, 4, -12 }, // 0x60 '`'
{ 650, 8, 9, 10, 1, -8 }, // 0x61 'a'
{ 659, 8, 13, 10, 1, -12 }, // 0x62 'b'
{ 672, 8, 9, 10, 1, -8 }, // 0x63 'c'
{ 681, 8, 13, 10, 1, -12 }, // 0x64 'd'
{ 694, 8, 9, 10, 1, -8 }, // 0x65 'e'
{ 703, 7, 13, 10, 2, -12 }, // 0x66 'f'
{ 715, 9, 13, 10, 0, -8 }, // 0x67 'g'
{ 730, 8, 13, 10, 1, -12 }, // 0x68 'h'
{ 743, 7, 13, 10, 1, -12 }, // 0x69 'i'
{ 755, 6, 17, 10, 1, -12 }, // 0x6A 'j'
{ 768, 8, 13, 10, 2, -12 }, // 0x6B 'k'
{ 781, 7, 13, 10, 1, -12 }, // 0x6C 'l'
{ 793, 8, 9, 10, 1, -8 }, // 0x6D 'm'
{ 802, 8, 9, 10, 1, -8 }, // 0x6E 'n'
{ 811, 8, 9, 10, 1, -8 }, // 0x6F 'o'
{ 820, 8, 13, 10, 1, -8 }, // 0x70 'p'
{ 833, 8, 13, 10, 1, -8 }, // 0x71 'q'
{ 846, 7, 9, 10, 2, -8 }, // 0x72 'r'
{ 854, 6, 9, 10, 2, -8 }, // 0x73 's'
{ 861, 7, 11, 10, 2, -10 }, // 0x74 't'
{ 871, 8, 9, 10, 1, -8 }, // 0x75 'u'
{ 880, 8, 9, 10, 1, -8 }, // 0x76 'v'
{ 889, 10, 9, 10, 0, -8 }, // 0x77 'w'
{ 901, 8, 9, 10, 1, -8 }, // 0x78 'x'
{ 910, 8, 13, 10, 1, -8 }, // 0x79 'y'
{ 923, 6, 9, 10, 2, -8 }, // 0x7A 'z'
{ 930, 6, 15, 10, 2, -11 }, // 0x7B '{'
{ 942, 1, 17, 10, 4, -12 }, // 0x7C '|'
{ 945, 6, 15, 10, 2, -11 }, // 0x7D '}'
{ 957, 8, 3, 10, 1, -6 } }; // 0x7E '~'
const GFXfont NotoMono8pt7b PROGMEM = {
(uint8_t *)NotoMono8pt7bBitmaps,
(GFXglyph *)NotoMono8pt7bGlyphs,
0x20, 0x7E, 18 };
// Approx. 1632 bytes

View file

@ -0,0 +1,517 @@
// =======================================================================
// GUIslice library (extensions)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file XCheckbox.c
// GUIslice library
#include "GUIslice.h"
#include "GUIslice_drv.h"
#include "XCheckbox.h"
#include <stdio.h>
#if (GSLC_USE_PROGMEM)
#include <avr/pgmspace.h>
#endif
// ----------------------------------------------------------------------------
// Error Messages
// ----------------------------------------------------------------------------
extern const char GSLC_PMEM ERRSTR_NULL[];
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
// ----------------------------------------------------------------------------
// Extended element definitions
// ----------------------------------------------------------------------------
//
// - This file extends the core GUIslice functionality with
// additional widget types
//
// ----------------------------------------------------------------------------
// ============================================================================
// Extended Element: Checkbox
// - Checkbox with custom handler for touch tracking which
// enables glow to be defined whenever touch is tracked over
// the element.
// ============================================================================
// Create a checkbox element and add it to the GUI element list
// - Defines default styling for the element
// - Defines callback for redraw but does not track touch/click
gslc_tsElemRef* gslc_ElemXCheckboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
gslc_tsXCheckbox* pXData,gslc_tsRect rElem,bool bRadio,gslc_teXCheckboxStyle nStyle,
gslc_tsColor colCheck,bool bChecked)
{
if ((pGui == NULL) || (pXData == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXCheckboxCreate";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return NULL;
}
gslc_tsElem sElem;
gslc_tsElemRef* pElemRef = NULL;
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_CHECKBOX,rElem,NULL,0,GSLC_FONT_NONE);
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
// Default group assignment. Can override later with ElemSetGroup()
sElem.nGroup = GSLC_GROUP_ID_NONE;
// Define other extended data
pXData->bRadio = bRadio;
pXData->bChecked = bChecked;
pXData->colCheck = colCheck;
pXData->nStyle = nStyle;
pXData->pfuncXToggle = NULL;
sElem.pXData = (void*)(pXData);
// Specify the custom drawing callback
sElem.pfuncXDraw = &gslc_ElemXCheckboxDraw;
// Specify the custom touch tracking callback
// - NOTE: This is optional (and can be set to NULL).
// See the discussion under gslc_ElemXCheckboxTouch()
sElem.pfuncXTouch = &gslc_ElemXCheckboxTouch;
sElem.colElemFill = GSLC_COL_BLACK;
sElem.colElemFillGlow = GSLC_COL_BLACK;
sElem.colElemFrame = GSLC_COL_GRAY;
sElem.colElemFrameGlow = GSLC_COL_WHITE;
if (nPage != GSLC_PAGE_NONE) {
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
return pElemRef;
#if (GSLC_FEATURE_COMPOUND)
} else {
// Save as temporary element
pGui->sElemTmp = sElem;
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
return &(pGui->sElemRefTmp);
#endif
}
return NULL;
}
bool gslc_ElemXCheckboxGetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
{
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
if (!pCheckbox) return false;
return pCheckbox->bChecked;
}
// Determine which checkbox in the group has been "checked"
gslc_tsElemRef* gslc_ElemXCheckboxFindChecked(gslc_tsGui* pGui,int16_t nGroupId)
{
int16_t nCurInd;
gslc_tsElemRef* pCurElemRef = NULL;
gslc_tsElem* pCurElem = NULL;
int16_t nCurType;
int16_t nCurGroup;
bool bCurChecked;
gslc_tsElemRef* pFoundElemRef = NULL;
// Operate on current page
// TODO: Support other page layers
gslc_tsPage* pPage = pGui->apPageStack[GSLC_STACK_CUR];
if (pPage == NULL) {
return NULL; // No page added yet
}
if (pGui == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXCheckboxFindChecked";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return NULL;
}
gslc_tsCollect* pCollect = &pPage->sCollect;
for (nCurInd=0;nCurInd<pCollect->nElemCnt;nCurInd++) {
// Fetch extended data
pCurElemRef = &(pCollect->asElemRef[nCurInd]);
pCurElem = gslc_GetElemFromRef(pGui,pCurElemRef);
nCurType = pCurElem->nType;
// Only want to proceed if it is a checkbox
if (nCurType != GSLC_TYPEX_CHECKBOX) {
continue;
}
nCurGroup = pCurElem->nGroup;
bCurChecked = gslc_ElemXCheckboxGetState(pGui,pCurElemRef);
// If this is in a different group, ignore it
if (nCurGroup != nGroupId) {
continue;
}
// Did we find an element in the group that was checked?
if (bCurChecked) {
pFoundElemRef = pCurElemRef;
break;
}
} // nCurInd
return pFoundElemRef;
}
// Assign the callback function for checkbox/radio state change events
void gslc_ElemXCheckboxSetStateFunc(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, GSLC_CB_XCHECKBOX pfuncCb)
{
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
if (!pCheckbox) return;
pCheckbox->pfuncXToggle = pfuncCb;
}
// Helper routine for gslc_ElemXCheckboxSetState()
// - Updates the checkbox/radio control's state but does
// not touch any other controls in the group
void gslc_ElemXCheckboxSetStateHelp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bChecked,bool bDoCb)
{
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
if (!pCheckbox) return;
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
// Update our data element
bool const bCheckedOld = pCheckbox->bChecked;
pCheckbox->bChecked = bChecked;
// Element needs redraw
if (bChecked != bCheckedOld) {
// Only need an incremental redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
} else {
// Same state as before
// - No need to do anything further since we don't need to
// trigger any callbacks or redraw
return;
}
// If no callbacks requested, exit now
if (!bDoCb) {
return;
}
// If any state callback is defined, call it now
// - In all cases, return the ElementRef of the element that issued the callback
//
// For checkbox:
// - If not selected: return current ID and state=false
// - If selected: return current ID and state=true
// For radio button:
// - If none selected: return ID_NONE and state=false
// - If one selected: return selected ID and state=true
if (pCheckbox->pfuncXToggle != NULL) {
gslc_tsElemRef* pRetRef = NULL;
int16_t nGroup = GSLC_GROUP_ID_NONE;
int16_t nSelId = GSLC_ID_NONE;
if (!pCheckbox->bRadio) {
// Checkbox
nSelId = pElem->nId;
} else {
// Radio button
// - Determine the group that the radio button belongs to
nGroup = pElem->nGroup;
// Determine if any radio button in the group has been selected
pRetRef = gslc_ElemXCheckboxFindChecked(pGui, nGroup);
if (pRetRef != NULL) {
// One has been selected, return its ID
bChecked = true;
nSelId = pRetRef->pElem->nId;
} else {
// No radio button selected, return ID NONE
bChecked = false;
nSelId = GSLC_ID_NONE;
}
}
// Now send the callback notification
(*pCheckbox->pfuncXToggle)((void*)(pGui), (void*)(pElemRef), nSelId, bChecked);
} // pfuncXToggle
}
// Update the checkbox/radio control's state. If it is a radio button
// then also update the state of all other buttons in the group.
void gslc_ElemXCheckboxSetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bChecked)
{
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
if (!pCheckbox) return;
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsPage* pPage = NULL;
bool bRadio = pCheckbox->bRadio;
int16_t nGroup = pElem->nGroup;
int16_t nElemId = pElem->nId;
// Special handling when we select a radio button
if (bRadio && bChecked) {
// If we are selecting a radio button that is already
// selected, then skip further update events.
// NOTE: This check is not very efficient, but it avoids
// the creation of extra events.
gslc_tsElemRef* pTmpRef = gslc_ElemXCheckboxFindChecked(pGui, nGroup);
if (pTmpRef == pElemRef) {
// Same element, so skip
return;
}
// Proceed to deselect any other selected items in the group.
// Note that SetState calls itself to deselect other items so it
// is important to qualify this logic with bChecked=true
int16_t nCurInd;
int16_t nCurId;
gslc_tsElem* pCurElem = NULL;
gslc_tsElemRef* pCurElemRef = NULL;
int16_t nCurType;
int16_t nCurGroup;
// We use the GUI pointer for access to other elements
// Check all pages in case we are affecting radio buttons on other pages
for (int8_t nPageInd=0;nPageInd<pGui->nPageCnt;nPageInd++) {
pPage = &pGui->asPage[nPageInd];
if (!pPage) {
// If this stack page is not enabled, skip to next stack page
continue;
}
gslc_tsCollect* pCollect = &pPage->sCollect;
for (nCurInd=0;nCurInd<pCollect->nElemRefCnt;nCurInd++) {
// Fetch extended data
pCurElemRef = &pCollect->asElemRef[nCurInd];
pCurElem = gslc_GetElemFromRef(pGui,pCurElemRef);
// FIXME: Handle pCurElemRef->eElemFlags
nCurId = pCurElem->nId;
nCurType = pCurElem->nType;
// Only want to proceed if it is a checkbox
if (nCurType != GSLC_TYPEX_CHECKBOX) {
continue;
}
nCurGroup = pCurElem->nGroup;
// If this is in a different group, ignore it
if (nCurGroup != nGroup) {
continue;
}
// Is this our element? If so, ignore the deselect operation
if (nCurId == nElemId) {
continue;
}
// Deselect all other elements
// - But don't trigger any callbacks
gslc_ElemXCheckboxSetStateHelp(pGui,pCurElemRef,false,false);
} // nInd
} // nStackPage
} // bRadio
// Set the state of the current element
// - Trigger callback if enabled
gslc_ElemXCheckboxSetStateHelp(pGui,pElemRef,bChecked,true);
}
// Toggle the checkbox control's state
void gslc_ElemXCheckboxToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef)
{
if (pElemRef == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXCheckboxToggleState";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
// Update the data element
bool bCheckNew = (gslc_ElemXCheckboxGetState(pGui,pElemRef))? false : true;
gslc_ElemXCheckboxSetState(pGui,pElemRef,bCheckNew);
// Element needs redraw
// - Only incremental is needed
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
}
// Redraw the checkbox
// - Note that this redraw is for the entire element rect region
// - The Draw function parameters use void pointers to allow for
// simpler callback function definition & scalability.
bool gslc_ElemXCheckboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
{
// Typecast the parameters to match the GUI and element types
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
if (!pCheckbox) return false;
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsRect rInner;
bool bChecked = pCheckbox->bChecked;
gslc_teXCheckboxStyle nStyle = pCheckbox->nStyle;
bool bGlow = (pElem->nFeatures & GSLC_ELEM_FEA_GLOW_EN) && gslc_ElemGetGlow(pGui,pElemRef);
// Draw the background
gslc_DrawFillRect(pGui,pElem->rElem,pElem->colElemFill);
// Generic coordinate calcs
int16_t nX0,nY0,nX1,nY1,nMidX,nMidY;
nX0 = pElem->rElem.x;
nY0 = pElem->rElem.y;
nX1 = pElem->rElem.x + pElem->rElem.w - 1;
nY1 = pElem->rElem.y + pElem->rElem.h - 1;
nMidX = (nX0+nX1)/2;
nMidY = (nY0+nY1)/2;
if (nStyle == GSLCX_CHECKBOX_STYLE_BOX) {
// Draw the center indicator if checked
rInner = gslc_ExpandRect(pElem->rElem,-5,-5);
if (bChecked) {
// If checked, fill in the inner region
gslc_DrawFillRect(pGui,rInner,pCheckbox->colCheck);
} else {
// Assume the background fill has already been done so
// we don't need to do anything more in the unchecked case
}
// Draw a frame around the checkbox
gslc_DrawFrameRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
} else if (nStyle == GSLCX_CHECKBOX_STYLE_X) {
// Draw an X through center if checked
if (bChecked) {
gslc_DrawLine(pGui,nX0,nY0,nX1,nY1,pCheckbox->colCheck);
gslc_DrawLine(pGui,nX0,nY1,nX1,nY0,pCheckbox->colCheck);
}
// Draw a frame around the checkbox
gslc_DrawFrameRect(pGui,pElem->rElem,(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
} else if (nStyle == GSLCX_CHECKBOX_STYLE_ROUND) {
// Draw inner circle if checked
if (bChecked) {
gslc_DrawFillCircle(pGui,nMidX,nMidY,5,pCheckbox->colCheck);
}
// Draw a frame around the checkbox
gslc_DrawFrameCircle(pGui,nMidX,nMidY,(pElem->rElem.w/2),(bGlow)?pElem->colElemFrameGlow:pElem->colElemFrame);
}
// Clear the redraw flag
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
// Mark page as needing flip
gslc_PageFlipSet(pGui,true);
return true;
}
// This callback function is called by gslc_ElemSendEventTouch()
// after any touch event
// - NOTE: Adding this touch callback is optional. Without it, we
// can still have a functional checkbox, but doing the touch
// tracking allows us to change the glow state of the element
// dynamically, as well as updating the checkbox state if the
// user releases over it (ie. a click event).
//
bool gslc_ElemXCheckboxTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY)
{
#if defined(DRV_TOUCH_NONE)
return false;
#else
// Typecast the parameters to match the GUI and element types
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsXCheckbox* pCheckbox = (gslc_tsXCheckbox*)gslc_GetXDataFromRef(pGui, pElemRef, GSLC_TYPEX_CHECKBOX, __LINE__);
if (!pCheckbox) return false;
//gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
bool bRadio = pCheckbox->bRadio;
bool bCheckedOld = pCheckbox->bChecked;
bool bGlowingOld = gslc_ElemGetGlow(pGui,pElemRef);
switch(eTouch) {
case GSLC_TOUCH_DOWN_IN:
gslc_ElemSetGlow(pGui,pElemRef,true);
break;
case GSLC_TOUCH_MOVE_IN:
gslc_ElemSetGlow(pGui,pElemRef,true);
break;
case GSLC_TOUCH_MOVE_OUT:
gslc_ElemSetGlow(pGui,pElemRef,false);
break;
case GSLC_TOUCH_UP_IN:
gslc_ElemSetGlow(pGui,pElemRef,false);
// Now that we released on element, update the state
bool bCheckNew;
if (bRadio) {
// Radio button action: set
bCheckNew = true;
} else {
// Checkbox button action: toggle
bCheckNew = (pCheckbox->bChecked)?false:true;
}
gslc_ElemXCheckboxSetState(pGui,pElemRef,bCheckNew);
break;
case GSLC_TOUCH_UP_OUT:
gslc_ElemSetGlow(pGui,pElemRef,false);
break;
default:
return false;
break;
}
// If the checkbox changed state, redraw
bool bChanged = false;
if (gslc_ElemGetGlow(pGui,pElemRef) != bGlowingOld) { bChanged = true; }
if (pCheckbox->bChecked != bCheckedOld) { bChanged = true; }
if (bChanged) {
// Incremental redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
}
return true;
#endif // !DRV_TOUCH_NONE
}
// ============================================================================

View file

@ -0,0 +1,290 @@
#ifndef _GUISLICE_EX_XCHECKBOX_H_
#define _GUISLICE_EX_XCHECKBOX_H_
#include "GUIslice.h"
// =======================================================================
// GUIslice library extension: Checkbox/Radio button control
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file XCheckbox.h
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// ============================================================================
// Extended Element: Checkbox
// ============================================================================
// Define unique identifier for extended element type
// - Select any number above GSLC_TYPE_BASE_EXTEND
#define GSLC_TYPEX_CHECKBOX GSLC_TYPE_BASE_EXTEND + 1
/// Checkbox drawing style
typedef enum {
GSLCX_CHECKBOX_STYLE_BOX, ///< Inner box
GSLCX_CHECKBOX_STYLE_X, ///< Crossed
GSLCX_CHECKBOX_STYLE_ROUND, ///< Circular
} gslc_teXCheckboxStyle;
/// Callback function for checkbox/radio element state change
/// - nSelId: Selected element's ID or GSLC_ID_NONE
/// - bChecked: Element was selected if true, false otherwise
typedef bool (*GSLC_CB_XCHECKBOX)(void* pvGui,void* pvElemRef,int16_t nSelId, bool bChecked);
// Extended element data structures
// - These data structures are maintained in the gslc_tsElem
// structure via the pXData pointer
/// Extended data for Checkbox element
typedef struct {
bool bRadio; ///< Radio-button operation if true
gslc_teXCheckboxStyle nStyle; ///< Drawing style for element
bool bChecked; ///< Indicates if it is selected (checked)
gslc_tsColor colCheck; ///< Color of checked inner fill
GSLC_CB_XCHECKBOX pfuncXToggle; ///< Callback event to say element has changed
} gslc_tsXCheckbox;
///
/// Create a Checkbox or Radio button Element
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
/// \param[in] nPage: Page ID to attach element to
/// \param[in] pXData: Ptr to extended element data structure
/// \param[in] rElem: Rectangle coordinates defining checkbox size
/// \param[in] bRadio: Radio-button functionality if true
/// \param[in] nStyle: Drawing style for checkbox / radio button
/// \param[in] colCheck: Color for inner fill when checked
/// \param[in] bChecked: Default state
///
/// \return Pointer to Element reference or NULL if failure
///
gslc_tsElemRef* gslc_ElemXCheckboxCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
gslc_tsXCheckbox* pXData,gslc_tsRect rElem,bool bRadio,
gslc_teXCheckboxStyle nStyle,gslc_tsColor colCheck,bool bChecked);
///
/// Get a Checkbox element's current state
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
///
/// \return Current state
///
bool gslc_ElemXCheckboxGetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
///
/// Set a Checkbox element's current state
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] bChecked: New state
///
/// \return none
///
void gslc_ElemXCheckboxSetState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bChecked);
///
/// Find the checkbox within a group that has been checked
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nGroupId: Group ID to search
///
/// \return Element Ptr or NULL if none checked
///
gslc_tsElemRef* gslc_ElemXCheckboxFindChecked(gslc_tsGui* pGui,int16_t nGroupId);
///
/// Toggle a Checkbox element's current state
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
///
/// \return none
///
void gslc_ElemXCheckboxToggleState(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef);
///
/// Assign the state callback function for a checkbox/radio button
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] pfuncCb: Function pointer to callback routine (or NULL for none)
///
/// \return none
///
void gslc_ElemXCheckboxSetStateFunc(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, GSLC_CB_XCHECKBOX pfuncCb);
///
/// Draw a Checkbox element on the screen
/// - Called from gslc_ElemDraw()
///
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
/// \param[in] eRedraw: Redraw mode
///
/// \return true if success, false otherwise
///
bool gslc_ElemXCheckboxDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
///
/// Handle touch events to Checkbox element
/// - Called from gslc_ElemSendEventTouch()
///
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
/// \param[in] eTouch: Touch event type
/// \param[in] nRelX: Touch X coord relative to element
/// \param[in] nRelY: Touch Y coord relative to element
///
/// \return true if success, false otherwise
///
bool gslc_ElemXCheckboxTouch(void* pvGui,void* pvElemRef,gslc_teTouch eTouch,int16_t nRelX,int16_t nRelY);
// ============================================================================
// ------------------------------------------------------------------------
// Read-only element macros
// ------------------------------------------------------------------------
// Macro initializers for Read-Only Elements in Flash/PROGMEM
//
/// \def gslc_ElemXCheckboxCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,nGroup,bRadio_,nStyle_,colCheck_,bChecked_)
///
/// Create a Checkbox or Radio button Element in Flash
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nElemId: Unique element ID to assign
/// \param[in] nPage: Page ID to attach element to
/// \param[in] nX: X coordinate of element
/// \param[in] nY: Y coordinate of element
/// \param[in] nW: Width of element
/// \param[in] nH: Height of element
/// \param[in] colFill: Color for the control background fill
/// \param[in] bFillEn: True if background filled, false otherwise (recommend True)
/// \param[in] nGroup: Group ID that radio buttons belong to (else GSLC_GROUP_NONE)
/// \param[in] bRadio_: Radio-button functionality if true
/// \param[in] nStyle_: Drawing style for checkbox / radio button
/// \param[in] colCheck_: Color for inner fill when checked
/// \param[in] bChecked_: Default state
///
/// \return none
///
#if (GSLC_USE_PROGMEM)
#define gslc_ElemXCheckboxCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,colFill,bFillEn,nGroup,bRadio_,nStyle_,colCheck_,bChecked_) \
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | (bFillEn?GSLC_ELEM_FEA_FILL_EN:0); \
static gslc_tsXCheckbox sCheckbox##nElemId; \
sCheckbox##nElemId.bRadio = bRadio_; \
sCheckbox##nElemId.bChecked = bChecked_; \
sCheckbox##nElemId.colCheck = colCheck_; \
sCheckbox##nElemId.nStyle = nStyle_; \
static const gslc_tsElem sElem##nElemId PROGMEM = { \
nElemId, \
nFeatures##nElemId, \
GSLC_TYPEX_CHECKBOX, \
(gslc_tsRect){nX,nY,nW,nH}, \
nGroup, \
GSLC_COL_GRAY,colFill,GSLC_COL_WHITE,GSLC_COL_BLACK, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
NULL, \
NULL, \
0, \
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
GSLC_COL_WHITE, \
GSLC_COL_WHITE, \
GSLC_ALIGN_MID_MID, \
0, \
0, \
NULL, \
(void*)(&sCheckbox##nElemId), \
NULL, \
&gslc_ElemXCheckboxDraw, \
&gslc_ElemXCheckboxTouch, \
NULL, \
}; \
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
#else
#define gslc_ElemXCheckboxCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,colFill,bFillEn,nGroup,bRadio_,nStyle_,colCheck_,bChecked_) \
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_CLICK_EN | (bFillEn?GSLC_ELEM_FEA_FILL_EN:0); \
static gslc_tsXCheckbox sCheckbox##nElemId; \
sCheckbox##nElemId.bRadio = bRadio_; \
sCheckbox##nElemId.bChecked = bChecked_; \
sCheckbox##nElemId.colCheck = colCheck_; \
sCheckbox##nElemId.nStyle = nStyle_; \
static const gslc_tsElem sElem##nElemId = { \
nElemId, \
nFeatures##nElemId, \
GSLC_TYPEX_CHECKBOX, \
(gslc_tsRect){nX,nY,nW,nH}, \
nGroup, \
GSLC_COL_GRAY,colFill,GSLC_COL_WHITE,GSLC_COL_BLACK, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
NULL, \
NULL, \
0, \
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
GSLC_COL_WHITE, \
GSLC_COL_WHITE, \
GSLC_ALIGN_MID_MID, \
0, \
0, \
NULL, \
(void*)(&sCheckbox##nElemId), \
NULL, \
&gslc_ElemXCheckboxDraw, \
&gslc_ElemXCheckboxTouch, \
NULL, \
}; \
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
#endif
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_EX_XCHECKBOX_H_

View file

@ -0,0 +1,699 @@
// =======================================================================
// GUIslice library (extensions)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file XGauge.c
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
// WARNING: The XGauge element has been replaced by XProgress / XRadial / XRamp
// Please update your code according to the migration notes in:
// https://github.com/ImpulseAdventure/GUIslice/pull/157
// XGauge may be removed in a future release.
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
// GUIslice library
#include "GUIslice.h"
#include "GUIslice_drv.h"
#include "XGauge.h"
#include <stdio.h>
#include <math.h> // For sin/cos in XGauge(RADIAL)
#if (GSLC_USE_PROGMEM)
#include <avr/pgmspace.h>
#endif
// ----------------------------------------------------------------------------
// Error Messages
// ----------------------------------------------------------------------------
extern const char GSLC_PMEM ERRSTR_NULL[];
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
// ----------------------------------------------------------------------------
// Extended element definitions
// ----------------------------------------------------------------------------
//
// - This file extends the core GUIslice functionality with
// additional widget types
//
// ----------------------------------------------------------------------------
// ============================================================================
// Extended Element: Gauge
// - Basic progress bar with support for positive/negative state
// and vertical / horizontal orientation.
// ============================================================================
// Create a gauge element and add it to the GUI element list
// - Defines default styling for the element
// - Defines callback for redraw but does not track touch/click
gslc_tsElemRef* gslc_ElemXGaugeCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
gslc_tsXGauge* pXData,gslc_tsRect rElem,
int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert)
{
if ((pGui == NULL) || (pXData == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeCreate";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return NULL;
}
gslc_tsElem sElem;
gslc_tsElemRef* pElemRef = NULL;
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_GAUGE,rElem,NULL,0,GSLC_FONT_NONE);
sElem.nFeatures |= GSLC_ELEM_FEA_FRAME_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
sElem.nFeatures &= ~GSLC_ELEM_FEA_CLICK_EN; // Element is not "clickable"
sElem.nFeatures &= ~GSLC_ELEM_FEA_GLOW_EN;
sElem.nGroup = GSLC_GROUP_ID_NONE;
pXData->nMin = nMin;
pXData->nMax = nMax;
pXData->nVal = nVal;
pXData->nStyle = GSLCX_GAUGE_STYLE_PROG_BAR; // Default to progress bar
pXData->bVert = bVert;
pXData->bFlip = false;
pXData->colGauge = colGauge;
pXData->colTick = GSLC_COL_GRAY;
pXData->nTickCnt = 8;
pXData->nTickLen = 5;
pXData->nIndicLen = 10; // Dummy default to be overridden
pXData->nIndicTip = 3; // Dummy default to be overridden
pXData->bIndicFill = false;
sElem.pXData = (void*)(pXData);
sElem.pfuncXDraw = &gslc_ElemXGaugeDraw;
sElem.pfuncXTouch = NULL; // No need to track touches
sElem.colElemFill = GSLC_COL_BLACK;
sElem.colElemFillGlow = GSLC_COL_BLACK;
sElem.colElemFrame = GSLC_COL_GRAY;
sElem.colElemFrameGlow = GSLC_COL_GRAY;
GSLC_DEBUG_PRINT("NOTE: XGauge has been replaced by XProgress/XRadial/XRamp\n","");
if (nPage != GSLC_PAGE_NONE) {
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
return pElemRef;
#if (GSLC_FEATURE_COMPOUND)
} else {
// Save as temporary element
pGui->sElemTmp = sElem;
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
return &(pGui->sElemRefTmp);
#endif
}
return NULL;
}
void gslc_ElemXGaugeSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teXGaugeStyle nStyle)
{
if (pElemRef == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetStyle";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
// Update the type element
pGauge->nStyle = nStyle;
// Just in case we were called at runtime, mark as needing redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
void gslc_ElemXGaugeSetIndicator(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colGauge,
uint16_t nIndicLen,uint16_t nIndicTip,bool bIndicFill)
{
if (pElemRef == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetIndicator";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
// Update the config
pGauge->colGauge = colGauge;
pGauge->nIndicLen = nIndicLen;
pGauge->nIndicTip = nIndicTip;
pGauge->bIndicFill = bIndicFill;
// Just in case we were called at runtime, mark as needing redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
void gslc_ElemXGaugeSetTicks(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colTick,uint16_t nTickCnt,uint16_t nTickLen)
{
if (pElemRef == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetTicks";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
// Update the config
pGauge->colTick = colTick;
pGauge->nTickCnt = nTickCnt;
pGauge->nTickLen = nTickLen;
// Just in case we were called at runtime, mark as needing redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
// Update the gauge control's current position
void gslc_ElemXGaugeUpdate(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal)
{
if (pElemRef == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeUpdate";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
// Update the data element
int16_t nValOld = pGauge->nVal;
pGauge->nVal = nVal;
// Element needs redraw
if (nVal != nValOld) {
// We only need an incremental redraw
// NOTE: If the user configures the indicator to be
// long enough that it overlaps some of the gauge indicators
// then a full redraw should be done instead.
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
}
}
// Update the gauge's fill direction
// - Setting bFlip causes the gauge to be filled in the reverse direction
// to the default
// - Default fill direction for horizontal gauges: left-to-right
// - Default fill direction for vertical gauges: bottom-to-top
void gslc_ElemXGaugeSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip)
{
if (pElemRef == NULL) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeSetFlip";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
// Fetch the element's extended data structure
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
if (pGauge == NULL) {
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXGaugeSetFlip(%s) pXData is NULL\n","");
return;
}
pGauge->bFlip = bFlip;
// Mark for redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
// Redraw the gauge
// - Note that this redraw is for the entire element rect region
// - The Draw function parameters use void pointers to allow for
// simpler callback function definition & scalability.
bool gslc_ElemXGaugeDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
{
if ((pvGui == NULL) || (pvElemRef == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGaugeDraw";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return false;
}
// Typecast the parameters to match the GUI and element types
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
// Fetch the element's extended data structure
gslc_tsXGauge* pGauge;
pGauge = (gslc_tsXGauge*)(pElem->pXData);
if (pGauge == NULL) {
GSLC_DEBUG2_PRINT("ERROR: ElemXGaugeDraw(%s) pXData is NULL\n","");
return false;
}
switch (pGauge->nStyle) {
case GSLCX_GAUGE_STYLE_PROG_BAR:
gslc_ElemXGaugeDrawProgressBar(pGui,pElemRef,eRedraw);
break;
case GSLCX_GAUGE_STYLE_RADIAL:
#if (GSLC_FEATURE_XGAUGE_RADIAL)
gslc_ElemXGaugeDrawRadial(pGui,pElemRef,eRedraw);
#endif
break;
case GSLCX_GAUGE_STYLE_RAMP:
#if (GSLC_FEATURE_XGAUGE_RAMP)
gslc_ElemXGaugeDrawRamp(pGui,pElemRef,eRedraw);
#endif
break;
default:
// ERROR
break;
}
// Save as "last state" to support incremental erase/redraw
pGauge->nValLast = pGauge->nVal;
pGauge->bValLastValid = true;
// Clear the redraw flag
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
return true;
}
bool gslc_ElemXGaugeDrawProgressBar(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
{
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
gslc_tsRect rTmp; // Temporary rect for drawing
gslc_tsRect rGauge; // Filled portion of gauge
gslc_tsRect rEmpty; // Empty portion of gauge
uint16_t nElemW,nElemH;
int16_t nElemX0,nElemY0,nElemX1,nElemY1;
int16_t nGaugeX0,nGaugeY0,nGaugeX1,nGaugeY1;
nElemX0 = pElem->rElem.x;
nElemY0 = pElem->rElem.y;
nElemX1 = pElem->rElem.x + pElem->rElem.w - 1;
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
nElemW = pElem->rElem.w;
nElemH = pElem->rElem.h;
bool bVert = pGauge->bVert;
bool bFlip = pGauge->bFlip;
int16_t nMax = pGauge->nMax;
int16_t nMin = pGauge->nMin;
int16_t nRng = pGauge->nMax - pGauge->nMin;
uint32_t nScl = 1;
int16_t nGaugeMid = 0;
int16_t nLen = 0;
int16_t nTmp = 0;
int32_t nTmpL = 0;
if (nRng == 0) {
GSLC_DEBUG2_PRINT("ERROR: ElemXGaugeDraw() Zero gauge range [%d,%d]\n",nMin,nMax);
return false;
}
if (bVert) {
nScl = nElemH*32768/nRng;
} else {
nScl = nElemW*32768/nRng;
}
// Calculate the control midpoint/zeropoint (for display purposes)
nTmpL = -((int32_t)nMin * (int32_t)nScl / 32768);
nGaugeMid = (int16_t)nTmpL;
// Calculate the length of the bar
// - Use long mult/divide to avoid need for floating point
nTmpL = (int32_t)(pGauge->nVal) * (int32_t)(nScl) / 32768;
nLen = (int16_t)(nTmpL);
// Define the gauge's fill rectangle region
// depending on the orientation (bVert) and whether
// the current position is negative or positive.
if (nLen >= 0) {
if (bVert) {
nGaugeY0 = nElemY0 + nGaugeMid;
nGaugeY1 = nElemY0 + nGaugeMid + nLen;
} else {
nGaugeX0 = nElemX0 + nGaugeMid;
nGaugeX1 = nElemX0 + nGaugeMid + nLen;
}
} else {
if (bVert) {
nGaugeY0 = nElemY0 + nGaugeMid + nLen;
nGaugeY1 = nElemY0 + nGaugeMid;
} else {
nGaugeX0 = nElemX0 + nGaugeMid + nLen;
nGaugeX1 = nElemX0 + nGaugeMid;
}
}
if (bVert) {
nGaugeX0 = nElemX0;
nGaugeX1 = nElemX1;
} else {
nGaugeY0 = nElemY0;
nGaugeY1 = nElemY1;
}
// Clip the region
nGaugeX0 = (nGaugeX0 < nElemX0)? nElemX0 : nGaugeX0;
nGaugeY0 = (nGaugeY0 < nElemY0)? nElemY0 : nGaugeY0;
nGaugeX1 = (nGaugeX1 > nElemX1)? nElemX1 : nGaugeX1;
nGaugeY1 = (nGaugeY1 > nElemY1)? nElemY1 : nGaugeY1;
// Support flipping of gauge directionality
// - The bFlip flag reverses the fill direction
// - Vertical gauges are flipped by default
if (bVert && !bFlip) {
nTmp = nElemY0+(nElemY1-nGaugeY1); // nTmp will be swapped into nGaugeY0
nGaugeY1 = nElemY1-(nGaugeY0-nElemY0);
nGaugeY0 = nTmp;
nGaugeMid = nElemH-nGaugeMid-1;
} else if (!bVert && bFlip) {
nTmp = nElemX0+(nElemX1-nGaugeX1); // nTmp will be swapped into nGaugeX0
nGaugeX1 = nElemX1-(nGaugeX0-nElemX0);
nGaugeX0 = nTmp;
nGaugeMid = nElemW-nGaugeMid-1;
}
#ifdef DBG_LOG
//printf("Gauge: nMin=%4d nMax=%4d nRng=%d nVal=%4d fScl=%6.3f nGaugeMid=%4d RectX=%4d RectW=%4d\n",
// nMin,nMax,nRng,pGauge->nGaugeVal,fScl,nGaugeMid,rGauge.x,rGauge.w);
#endif
// Draw a frame around the gauge
// - Only draw this during full redraw
if (eRedraw == GSLC_REDRAW_FULL) {
gslc_DrawFrameRect(pGui, pElem->rElem, pElem->colElemFrame);
}
// To avoid flicker, we only erase the portion of the gauge
// that isn't "filled". Determine the gauge empty region and erase it
// There are two empty regions (one in negative and one in positive)
int16_t nEmptyPos;
if (bVert) {
// Empty Region #1 (negative)
nEmptyPos = (nGaugeY0 > nElemY1) ? nElemY1 : nGaugeY0;
rEmpty = (gslc_tsRect){nElemX0,nElemY0,nElemX1-nElemX0+1,nEmptyPos-nElemY0+1};
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
gslc_DrawFillRect(pGui,rTmp,pElem->colElemFill);
// Empty Region #2 (positive)
nEmptyPos = (nGaugeY1 < nElemY0) ? nElemY0 : nGaugeY1;
rEmpty = (gslc_tsRect){nElemX0,nEmptyPos,nElemX1-nElemX0+1,nElemY1-nEmptyPos+1};
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
gslc_DrawFillRect(pGui,rTmp,pElem->colElemFill);
} else {
// Empty Region #1 (negative)
nEmptyPos = (nGaugeX0 > nElemX1) ? nElemX1 : nGaugeX0;
rEmpty = (gslc_tsRect){nElemX0,nElemY0,nEmptyPos-nElemX0+1,nElemY1-nElemY0+1};
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
gslc_DrawFillRect(pGui, rTmp, pElem->colElemFill);
// Empty Region #2 (positive)
nEmptyPos = (nGaugeX1 < nElemX0) ? nElemX0 : nGaugeX1;
rEmpty = (gslc_tsRect){nEmptyPos,nElemY0,nElemX1-nEmptyPos+1,nElemY1-nElemY0+1};
rTmp = gslc_ExpandRect(rEmpty,-1,-1);
gslc_DrawFillRect(pGui, rTmp, pElem->colElemFill);
}
// Draw the gauge fill region
rGauge = (gslc_tsRect){nGaugeX0,nGaugeY0,nGaugeX1-nGaugeX0+1,nGaugeY1-nGaugeY0+1};
rTmp = gslc_ExpandRect(rGauge,-1,-1);
gslc_DrawFillRect(pGui,rTmp,pGauge->colGauge);
// Draw the midpoint line
if (bVert) {
if (nElemY0 + nGaugeMid < nElemY1) {
gslc_DrawLine(pGui, nElemX0, nElemY0 + nGaugeMid, nElemX1, nElemY0 + nGaugeMid, pElem->colElemFrame);
}
} else {
if (nElemX0 + nGaugeMid < nElemX1) {
gslc_DrawLine(pGui, nElemX0 + nGaugeMid, nElemY0, nElemX0 + nGaugeMid, nElemY1, pElem->colElemFrame);
}
}
return true;
}
#if (GSLC_FEATURE_XGAUGE_RADIAL)
void gslc_ElemXGaugeDrawRadialHelp(gslc_tsGui* pGui,int16_t nX,int16_t nY,uint16_t nArrowLen,uint16_t nArrowSz,int16_t n64Ang,bool bFill,gslc_tsColor colFrame)
{
int16_t nTipX,nTipY;
int16_t nBaseX1,nBaseY1,nBaseX2,nBaseY2;
int16_t nTipBaseX,nTipBaseY;
gslc_PolarToXY(nArrowLen,n64Ang,&nTipX,&nTipY);
gslc_PolarToXY(nArrowLen-nArrowSz,n64Ang,&nTipBaseX,&nTipBaseY);
gslc_PolarToXY(nArrowSz,n64Ang-90*64,&nBaseX1,&nBaseY1);
gslc_PolarToXY(nArrowSz,n64Ang+90*64,&nBaseX2,&nBaseY2);
if (!bFill) {
// Framed
gslc_DrawLine(pGui,nX+nBaseX1,nY+nBaseY1,nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY,colFrame);
gslc_DrawLine(pGui,nX+nBaseX2,nY+nBaseY2,nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY,colFrame);
gslc_DrawLine(pGui,nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY,nX+nTipX,nY+nTipY,colFrame);
gslc_DrawLine(pGui,nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY,nX+nTipX,nY+nTipY,colFrame);
gslc_DrawLine(pGui,nX+nBaseX1,nY+nBaseY1,nX+nBaseX2,nY+nBaseY2,colFrame);
} else {
// Filled
gslc_tsPt asPt[4];
// Main body of pointer
asPt[0] = (gslc_tsPt){nX+nBaseX1,nY+nBaseY1};
asPt[1] = (gslc_tsPt){nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY};
asPt[2] = (gslc_tsPt){nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY};
asPt[3] = (gslc_tsPt){nX+nBaseX2,nY+nBaseY2};
gslc_DrawFillQuad(pGui,asPt,colFrame);
// Tip of pointer
asPt[0] = (gslc_tsPt){nX+nBaseX1+nTipBaseX,nY+nBaseY1+nTipBaseY};
asPt[1] = (gslc_tsPt){nX+nTipX,nY+nTipY};
asPt[2] = (gslc_tsPt){nX+nBaseX2+nTipBaseX,nY+nBaseY2+nTipBaseY};
gslc_DrawFillTriangle(pGui,asPt[0].x,asPt[0].y,asPt[1].x,asPt[1].y,asPt[2].x,asPt[2].y,colFrame);
}
}
bool gslc_ElemXGaugeDrawRadial(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
{
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
uint16_t nElemW,nElemH,nElemRad;
int16_t nElemX0,nElemY0,nElemX1,nElemY1;
int16_t nElemMidX,nElemMidY;
nElemX0 = pElem->rElem.x;
nElemY0 = pElem->rElem.y;
nElemX1 = pElem->rElem.x + pElem->rElem.w - 1;
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
nElemMidX = (nElemX0+nElemX1)/2;
nElemMidY = (nElemY0+nElemY1)/2;
nElemW = pElem->rElem.w;
nElemH = pElem->rElem.h;
nElemRad = (nElemW>=nElemH)? nElemH/2 : nElemW/2;
int16_t nMax = pGauge->nMax;
int16_t nMin = pGauge->nMin;
int16_t nRng = pGauge->nMax - pGauge->nMin;
int16_t nVal = pGauge->nVal;
int16_t nValLast = pGauge->nValLast;
bool bValLastValid = pGauge->bValLastValid;
uint16_t nTickLen = pGauge->nTickLen;
uint16_t nTickAng = 360 / pGauge->nTickCnt;
uint16_t nArrowLen = pGauge->nIndicLen;
uint16_t nArrowSize = pGauge->nIndicTip;
bool bFill = pGauge->bIndicFill;
int16_t n64Ang,n64AngLast;
int16_t nInd;
if (nRng == 0) {
GSLC_DEBUG2_PRINT("ERROR: ElemXRadialDraw() Zero range [%d,%d]\n",nMin,nMax);
return false;
}
// Support reversing of direction
// TODO: Clean up excess integer typecasting
if (pGauge->bFlip) {
n64Ang = (int32_t)(nMax - nVal )* 360*64 /nRng;
n64AngLast = (int32_t)(nMax - nValLast)* 360*64 /nRng;
} else {
n64Ang = (int32_t)(nVal - nMin)* 360*64 /nRng;
n64AngLast = (int32_t)(nValLast - nMin)* 360*64 /nRng;
}
// Clear old
if (bValLastValid) {
gslc_ElemXGaugeDrawRadialHelp(pGui,nElemMidX,nElemMidY,nArrowLen,nArrowSize,n64AngLast,bFill,pElem->colElemFill);
}
// Draw frame
if (eRedraw == GSLC_REDRAW_FULL) {
gslc_DrawFillCircle(pGui,nElemMidX,nElemMidY,nElemRad,pElem->colElemFill); // Erase first
gslc_DrawFrameCircle(pGui,nElemMidX,nElemMidY,nElemRad,pElem->colElemFrame);
for (nInd=0;nInd<360;nInd+=nTickAng) {
gslc_DrawLinePolar(pGui,nElemMidX,nElemMidY,nElemRad-nTickLen,nElemRad,nInd*64,pGauge->colTick);
}
}
// Draw pointer
gslc_ElemXGaugeDrawRadialHelp(pGui,nElemMidX,nElemMidY,nArrowLen,nArrowSize,n64Ang,bFill,pGauge->colGauge);
return true;
}
#endif // GSLC_FEATURE_XGAUGE_RADIAL
#ifdef GSLC_FEATURE_XGAUGE_RAMP
bool gslc_ElemXGaugeDrawRamp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw)
{
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGauge* pGauge = (gslc_tsXGauge*)(pElem->pXData);
uint16_t nElemW,nElemH;
int16_t nElemX0,nElemY1;
nElemX0 = pElem->rElem.x;
nElemY1 = pElem->rElem.y + pElem->rElem.h - 1;
nElemW = pElem->rElem.w;
nElemH = pElem->rElem.h;
int16_t nMax = pGauge->nMax;
int16_t nMin = pGauge->nMin;
int16_t nRng = pGauge->nMax - pGauge->nMin;
int16_t nVal = pGauge->nVal;
int16_t nValLast = pGauge->nValLast;
bool bValLastValid = pGauge->bValLastValid;
int16_t nInd;
if (nRng == 0) {
GSLC_DEBUG2_PRINT("ERROR: gslc_ElemXGaugeDrawRamp() Zero range [%d,%d]\n",nMin,nMax);
return false;
}
uint32_t nSclFX;
uint16_t nHeight;
int32_t nHeightTmp;
uint16_t nHeightBot;
uint16_t nX;
uint16_t nColInd;
// Calculate region to draw or clear
bool bModeErase;
int16_t nValStart;
int16_t nValEnd;
if ((eRedraw == GSLC_REDRAW_INC) && (!bValLastValid)) {
// - If the request was incremental (GSLC_REDRAW_INC) but
// the last value wasn't marked as valid (!bValLastValid)
// then we want to force a full redraw.
// - We don't expect to enter here since bValLastValid
// should always be set after we perform our first
// redraw.
eRedraw = GSLC_REDRAW_FULL;
}
if (eRedraw == GSLC_REDRAW_FULL) {
// If we haven't drawn anything before, draw full range from zero
bModeErase = false;
nValStart = 0;
nValEnd = nVal;
} else {
if (nVal >= nValLast) {
// As we are advancing the control, we just draw the new range
bModeErase = false;
nValStart = nValLast;
nValEnd = nVal;
} else {
// Since we are retracting the control, we erase the new range
bModeErase = true;
nValStart = nVal;
nValEnd = nValLast;
}
}
// Calculate the scaled gauge position
// - TODO: Also support reversing of direction
int16_t nPosXStart,nPosXEnd;
nPosXStart = (nValStart - nMin)*nElemW/nRng;
nPosXEnd = (nValEnd - nMin)*nElemW/nRng;
nSclFX = (uint32_t)nElemH*32767/(nElemW*nElemW);
for (nX=nPosXStart;nX<nPosXEnd;nX++) {
nInd = nElemW-nX;
nHeightTmp = nSclFX * nInd*nInd /32767;
nHeight = nElemH-nHeightTmp;
if (nHeight >= 20) {
nHeightBot = nHeight-20;
} else {
nHeightBot = 0;
}
gslc_tsColor nCol;
uint16_t nSteps = 10;
uint16_t nGap = 3;
if (nSteps == 0) {
nColInd = nX*1000/nElemW;
nCol = gslc_ColorBlend3(GSLC_COL_GREEN,GSLC_COL_YELLOW,GSLC_COL_RED,500,nColInd);
} else {
uint16_t nBlockLen,nSegLen,nSegInd,nSegOffset,nSegStart;
nBlockLen = (nElemW-(nSteps-1)*nGap)/nSteps;
nSegLen = nBlockLen + nGap;
nSegInd = nX/nSegLen;
nSegOffset = nX % nSegLen;
nSegStart = nSegInd * nSegLen;
if (nSegOffset <= nBlockLen) {
// Inside block
nColInd = (uint32_t)nSegStart*1000/nElemW;
nCol = gslc_ColorBlend3(GSLC_COL_GREEN,GSLC_COL_YELLOW,GSLC_COL_RED,500,nColInd);
} else {
// Inside gap
// - No draw
nCol = pElem->colElemFill;
}
}
if (bModeErase) {
nCol = pElem->colElemFill;
}
gslc_DrawLine(pGui,nElemX0+nX,nElemY1-nHeightBot,nElemX0+nX,nElemY1-nHeight,nCol);
}
return true;
}
#endif // GLSC_FEATURE_XGAUGE_RAMP
// ============================================================================

View file

@ -0,0 +1,394 @@
#ifndef _GUISLICE_EX_XGAUGE_H_
#define _GUISLICE_EX_XGAUGE_H_
#include "GUIslice.h"
// =======================================================================
// GUIslice library extension: Gauge control (See replacement warning below)
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file XGauge.h
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
// WARNING: The XGauge element has been replaced by XProgress / XRadial / XRamp
// Please update your code according to the migration notes in:
// https://github.com/ImpulseAdventure/GUIslice/pull/157
// XGauge may be removed in a future release.
// *-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-*-
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// ============================================================================
// Extended Element: Gauge
// ============================================================================
// Define unique identifier for extended element type
// - Select any number above GSLC_TYPE_BASE_EXTEND
#define GSLC_TYPEX_GAUGE GSLC_TYPE_BASE_EXTEND + 0
/// Gauge drawing style
typedef enum {
GSLCX_GAUGE_STYLE_PROG_BAR, ///< Progress bar
GSLCX_GAUGE_STYLE_RADIAL, ///< Radial indicator
GSLCX_GAUGE_STYLE_RAMP, ///< Ramp indicator
} gslc_teXGaugeStyle;
// Extended element data structures
// - These data structures are maintained in the gslc_tsElem
// structure via the pXData pointer
/// Extended data for Gauge element
typedef struct {
// Range config
int16_t nMin; ///< Minimum control value
int16_t nMax; ///< Maximum control value
// Current value
int16_t nVal; ///< Current control value
// Previous value
int16_t nValLast; ///< Last value
bool bValLastValid; ///< Last value valid?
// Appearance config
gslc_teXGaugeStyle nStyle; ///< Gauge sub-type
gslc_tsColor colGauge; ///< Color of gauge fill bar
gslc_tsColor colTick; ///< Color of gauge tick marks
uint16_t nTickCnt; ///< Number of gauge tick marks
uint16_t nTickLen; ///< Length of gauge tick marks
bool bVert; ///< Vertical if true, else Horizontal
bool bFlip; ///< Reverse direction of gauge
uint16_t nIndicLen; ///< Indicator length
uint16_t nIndicTip; ///< Size of tip at end of indicator
bool bIndicFill; ///< Fill the indicator if true
} gslc_tsXGauge;
///
/// Create a Gauge Element
/// - Draws a gauge element that represents a proportion (nVal)
/// between nMin and nMax.
/// - Support gauge sub-types:
/// - GSLC_TYPEX_GAUGE_PROG_BAR: Horizontal or vertical box with filled region
/// - GSLC_TYPEX_GAUGE_RADIAL: Radial / compass indicator
/// - Default appearance is a horizontal progress bar, but can be changed
/// with gslc_ElemXGaugeSetStyle())
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
/// \param[in] nPage: Page ID to attach element to
/// \param[in] pXData: Ptr to extended element data structure
/// \param[in] rElem: Rectangle coordinates defining gauge size
/// \param[in] nMin: Minimum value of gauge for nVal comparison
/// \param[in] nMax: Maximum value of gauge for nVal comparison
/// \param[in] nVal: Starting value of gauge
/// \param[in] colGauge: Color for the gauge indicator
/// \param[in] bVert: Flag to indicate vertical vs horizontal action
/// (true = vertical, false = horizontal)
///
/// \return Pointer to Element reference or NULL if failure
///
gslc_tsElemRef* gslc_ElemXGaugeCreate(gslc_tsGui* pGui,int16_t nElemId,int16_t nPage,
gslc_tsXGauge* pXData,gslc_tsRect rElem,int16_t nMin,int16_t nMax,int16_t nVal,gslc_tsColor colGauge,bool bVert);
///
/// Configure the style of a Gauge element
/// - This function is used to select between one of several gauge types
/// (eg. progress bar, radial dial, etc.)
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] nType: Gauge style enumeration
///
/// \return none
///
void gslc_ElemXGaugeSetStyle(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teXGaugeStyle nType);
///
/// Configure the appearance of the Gauge indicator
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] colGauge: Color of the indicator
/// \param[in] nIndicLen: Length of the indicator
/// \param[in] nIndicTip: Size of the indicator tip
/// \param[in] bIndicFill: Fill in the indicator if true
///
/// \return none
///
void gslc_ElemXGaugeSetIndicator(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colGauge,
uint16_t nIndicLen,uint16_t nIndicTip,bool bIndicFill);
///
/// Configure the appearance of the Gauge ticks
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] colTick: Color of the gauge ticks
/// \param[in] nTickCnt: Number of ticks to draw around / along gauge
/// \param[in] nTickLen: Length of the tick marks to draw
///
/// \return none
///
void gslc_ElemXGaugeSetTicks(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_tsColor colTick,uint16_t nTickCnt,uint16_t nTickLen);
///
/// Update a Gauge element's current value
/// - Note that min & max values are assigned in create()
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] nVal: New value to show in gauge
///
/// \return none
///
void gslc_ElemXGaugeUpdate(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,int16_t nVal);
///
/// Set a Gauge element's fill direction
/// - Setting bFlip reverses the default fill direction
/// - Default fill direction for horizontal gauges: left-to-right
/// - Default fill direction for vertical gauges: bottom-to-top
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] pElemRef: Pointer to Element reference
/// \param[in] bFlip: If set, reverse direction of fill from default
///
/// \return none
///
void gslc_ElemXGaugeSetFlip(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,bool bFlip);
///
/// Draw a gauge element on the screen
/// - Called from gslc_ElemDraw()
///
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
/// \param[in] pvElemRef: Void ptr to Element reference (typecast to gslc_tsElemRef*)
/// \param[in] eRedraw: Redraw mode
///
/// \return true if success, false otherwise
///
bool gslc_ElemXGaugeDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
///
/// Helper function to draw a gauge with style: progress bar
/// - Called from gslc_ElemXGaugeDraw()
///
/// \param[in] pGui: Ptr to GUI
/// \param[in] pElemRef: Ptr to Element reference
/// \param[in] eRedraw: Redraw status
///
/// \return true if success, false otherwise
///
bool gslc_ElemXGaugeDrawProgressBar(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
#if (GSLC_FEATURE_XGAUGE_RADIAL)
///
/// Helper function to draw a gauge with style: radial
/// - Called from gslc_ElemXGaugeDraw()
///
/// \param[in] pGui: Ptr to GUI
/// \param[in] pElemRef: Ptr to Element reference
/// \param[in] eRedraw: Redraw status
///
/// \return true if success, false otherwise
///
bool gslc_ElemXGaugeDrawRadial(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
#endif
#if (GSLC_FEATURE_XGAUGE_RAMP)
///
/// Helper function to draw a gauge with style: ramp
/// - Called from gslc_ElemXGaugeDraw()
///
/// \param[in] pGui: Ptr to GUI
/// \param[in] pElemRef: Ptr to Element reference
/// \param[in] eRedraw: Redraw status
///
/// \return true if success, false otherwise
///
bool gslc_ElemXGaugeDrawRamp(gslc_tsGui* pGui,gslc_tsElemRef* pElemRef,gslc_teRedrawType eRedraw);
#endif
// ============================================================================
// ------------------------------------------------------------------------
// Read-only element macros
// ------------------------------------------------------------------------
// Macro initializers for Read-Only Elements in Flash/PROGMEM
//
/// \def gslc_ElemXGaugeCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,
/// nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_)
///
/// Create a Gauge Element in Flash
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nElemId: Unique element ID to assign
/// \param[in] nPage: Page ID to attach element to
/// \param[in] nX: X coordinate of element
/// \param[in] nY: Y coordinate of element
/// \param[in] nW: Width of element
/// \param[in] nH: Height of element
/// \param[in] nMin_: Minimum value of gauge for nVal comparison
/// \param[in] nMax_: Maximum value of gauge for nVal comparison
/// \param[in] nVal_: Starting value of gauge
/// \param[in] colFrame_: Color for the gauge frame
/// \param[in] colFill_: Color for the gauge background fill
/// \param[in] colGauge_: Color for the gauge indicator
/// \param[in] bVert_: Flag to indicate vertical vs horizontal action
/// (true = vertical, false = horizontal)
///
/// \return none
///
#if (GSLC_USE_PROGMEM)
#define gslc_ElemXGaugeCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_) \
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
static gslc_tsXGauge sGauge##nElemId; \
sGauge##nElemId.nMin = nMin_; \
sGauge##nElemId.nMax = nMax_; \
sGauge##nElemId.nVal = nVal_; \
sGauge##nElemId.nValLast = nVal_; \
sGauge##nElemId.bValLastValid = false; \
sGauge##nElemId.nStyle = GSLCX_GAUGE_STYLE_PROG_BAR; \
sGauge##nElemId.colGauge = colGauge_; \
sGauge##nElemId.colTick = GSLC_COL_GRAY; \
sGauge##nElemId.nTickCnt = 8; \
sGauge##nElemId.nTickLen = 5; \
sGauge##nElemId.bVert = bVert_; \
sGauge##nElemId.bFlip = false; \
sGauge##nElemId.nIndicLen = 10; \
sGauge##nElemId.nIndicTip = 3; \
sGauge##nElemId.bIndicFill = false; \
static const gslc_tsElem sElem##nElemId PROGMEM = { \
nElemId, \
nFeatures##nElemId, \
GSLC_TYPEX_GAUGE, \
(gslc_tsRect){nX,nY,nW,nH}, \
GSLC_GROUP_ID_NONE, \
colFrame_,colFill_,colFrame_,colFill_, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
NULL, \
NULL, \
0, \
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
GSLC_COL_WHITE, \
GSLC_COL_WHITE, \
GSLC_ALIGN_MID_MID, \
0, \
0, \
NULL, \
(void*)(&sGauge##nElemId), \
NULL, \
&gslc_ElemXGaugeDraw, \
NULL, \
NULL, \
}; \
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_PROG | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
#else
#define gslc_ElemXGaugeCreate_P(pGui,nElemId,nPage,nX,nY,nW,nH,\
nMin_,nMax_,nVal_,colFrame_,colFill_,colGauge_,bVert_) \
static const uint8_t nFeatures##nElemId = GSLC_ELEM_FEA_VALID | \
GSLC_ELEM_FEA_GLOW_EN | GSLC_ELEM_FEA_FILL_EN; \
static gslc_tsXGauge sGauge##nElemId; \
sGauge##nElemId.nMin = nMin_; \
sGauge##nElemId.nMax = nMax_; \
sGauge##nElemId.nVal = nVal_; \
sGauge##nElemId.nValLast = nVal_; \
sGauge##nElemId.bValLastValid = false; \
sGauge##nElemId.nStyle = GSLCX_GAUGE_STYLE_PROG_BAR; \
sGauge##nElemId.colGauge = colGauge_; \
sGauge##nElemId.colTick = GSLC_COL_GRAY; \
sGauge##nElemId.nTickCnt = 8; \
sGauge##nElemId.nTickLen = 5; \
sGauge##nElemId.bVert = bVert_; \
sGauge##nElemId.bFlip = false; \
sGauge##nElemId.nIndicLen = 10; \
sGauge##nElemId.nIndicTip = 3; \
sGauge##nElemId.bIndicFill = false; \
static const gslc_tsElem sElem##nElemId = { \
nElemId, \
nFeatures##nElemId, \
GSLC_TYPEX_GAUGE, \
(gslc_tsRect){nX,nY,nW,nH}, \
GSLC_GROUP_ID_NONE, \
colFrame_,colFill_,colFrame_,colFill_, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
(gslc_tsImgRef){NULL,NULL,GSLC_IMGREF_NONE,NULL}, \
NULL, \
NULL, \
0, \
(gslc_teTxtFlags)(GSLC_TXT_DEFAULT), \
GSLC_COL_WHITE, \
GSLC_COL_WHITE, \
GSLC_ALIGN_MID_MID, \
0, \
0, \
NULL, \
(void*)(&sGauge##nElemId), \
NULL, \
&gslc_ElemXGaugeDraw, \
NULL, \
NULL, \
}; \
gslc_ElemAdd(pGui,nPage,(gslc_tsElem*)&sElem##nElemId, \
(gslc_teElemRefFlags)(GSLC_ELEMREF_SRC_CONST | GSLC_ELEMREF_VISIBLE | GSLC_ELEMREF_REDRAW_FULL));
#endif
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_EX_XGAUGE_H_

View file

@ -0,0 +1,348 @@
// =======================================================================
// GUIslice library extension: XGlowball
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file XGlowball.c
// GUIslice library
#include "GUIslice.h"
#include "GUIslice_drv.h"
#include "XGlowball.h"
#include <stdio.h>
#if (GSLC_USE_PROGMEM)
#include <avr/pgmspace.h>
#endif
// ----------------------------------------------------------------------------
// Error Messages
// ----------------------------------------------------------------------------
extern const char GSLC_PMEM ERRSTR_NULL[];
extern const char GSLC_PMEM ERRSTR_PXD_NULL[];
// ----------------------------------------------------------------------------
// Extended element definitions
// ----------------------------------------------------------------------------
//
// - This file extends the core GUIslice functionality with
// additional widget types
//
// ----------------------------------------------------------------------------
// ============================================================================
// Extended Element: XGlowball
// ============================================================================
// Create a XGlowball element and add it to the GUI element list
// - Defines default styling for the element
// - Defines callback for redraw and touch
gslc_tsElemRef* gslc_ElemXGlowballCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
gslc_tsXGlowball* pXData, int16_t nMidX, int16_t nMidY, gslc_tsXGlowballRing* pRings, uint8_t nNumRings)
{
if ((pGui == NULL) || (pXData == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballCreate";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return NULL;
}
gslc_tsElem sElem;
gslc_tsElemRef* pElemRef = NULL;
// Calculate the actual element dimensions based on the ring defintion
// - Note that we use the outer radius of the last ring
int16_t nRadMax;
gslc_tsRect rElem;
nRadMax = pRings[nNumRings - 1].nRad2;
rElem.w = 2 * nRadMax;
rElem.h = 2 * nRadMax;
rElem.x = nMidX - nRadMax;
rElem.y = nMidY - nRadMax;
sElem = gslc_ElemCreate(pGui,nElemId,nPage,GSLC_TYPEX_GLOW,rElem,NULL,0,GSLC_FONT_NONE);
sElem.colElemFill = GSLC_COL_BLACK;
sElem.colElemFillGlow = GSLC_COL_BLACK;
sElem.colElemFrame = GSLC_COL_GRAY;
sElem.colElemFrameGlow = GSLC_COL_GRAY;
sElem.colElemText = GSLC_COL_WHITE;
sElem.colElemTextGlow = GSLC_COL_WHITE;
sElem.nFeatures |= GSLC_ELEM_FEA_FILL_EN;
sElem.nFeatures &= ~GSLC_ELEM_FEA_FRAME_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_CLICK_EN;
sElem.nFeatures |= GSLC_ELEM_FEA_GLOW_EN;
sElem.eTxtAlign = GSLC_ALIGN_MID_LEFT;
sElem.nGroup = GSLC_GROUP_ID_NONE;
// Initialize any pxData members with default parameters
pXData->nVal = 0;
pXData->nQuality = 72;
pXData->nAngStart = 0;
pXData->nAngEnd = 360;
pXData->pRings = pRings;
pXData->nNumRings = nNumRings;
pXData->nMidX = nMidX;
pXData->nMidY = nMidY;
pXData->colBg = GSLC_COL_BLACK;
pXData->nValLast = 0;
sElem.pXData = (void*)(pXData);
// Specify the custom drawing callback
sElem.pfuncXDraw = &gslc_ElemXGlowballDraw;
// Specify the custom touch tracking callback
sElem.pfuncXTouch = NULL;
if (nPage != GSLC_PAGE_NONE) {
pElemRef = gslc_ElemAdd(pGui,nPage,&sElem,GSLC_ELEMREF_DEFAULT);
return pElemRef;
#if (GSLC_FEATURE_COMPOUND)
} else {
// Save as temporary element
pGui->sElemTmp = sElem;
pGui->sElemRefTmp.pElem = &(pGui->sElemTmp);
pGui->sElemRefTmp.eElemFlags = GSLC_ELEMREF_DEFAULT | GSLC_ELEMREF_REDRAW_FULL;
return &(pGui->sElemRefTmp);
#endif
}
return NULL;
}
void drawXGlowballArc(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nRad1, int16_t nRad2, gslc_tsColor cArc, uint16_t nAngStart, uint16_t nAngEnd)
{
gslc_tsPt anPts[4];
// TODO: Cleanup
int16_t nStep64 = 64*360 / pGlowball->nQuality;
int16_t nAng64;
int16_t nX, nY;
int16_t nSegStart, nSegEnd;
nSegStart = nAngStart * pGlowball->nQuality / 360;
nSegEnd = nAngEnd * pGlowball->nQuality / 360;
for (uint16_t nSegInd = nSegStart; nSegInd < nSegEnd; nSegInd++) {
nAng64 = nSegInd * nStep64;
nAng64 = nAng64 % (360 * 64);
gslc_PolarToXY(nRad1, nAng64, &nX, &nY);
anPts[0] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
gslc_PolarToXY(nRad2, nAng64, &nX, &nY);
anPts[1] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
gslc_PolarToXY(nRad2, nAng64 + nStep64, &nX, &nY);
anPts[2] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
gslc_PolarToXY(nRad1, nAng64 + nStep64, &nX, &nY);
anPts[3] = (gslc_tsPt) { nMidX + nX, nMidY + nY };
gslc_DrawFillQuad(pGui, anPts, cArc);
}
}
void drawXGlowballRing(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd, bool bErase)
{
int16_t nRad1, nRad2;
gslc_tsColor cCol;
if ((nVal <= 0) || (nVal > pGlowball->nNumRings)) {
return;
}
nRad1 = pGlowball->pRings[nVal - 1].nRad1;
nRad2 = pGlowball->pRings[nVal - 1].nRad2;
cCol = (bErase) ? pGlowball->colBg : pGlowball->pRings[nVal - 1].cCol;
drawXGlowballArc(pGui, pGlowball, nMidX, nMidY, nRad1, nRad2, cCol, nAngStart, nAngEnd);
}
// nAngStart & nAngEnd define the range (in degrees) for the XGlowball arcs
// - Angles are measured with 0 degrees at the top, incrementing clockwise
// - Note that the supported range is 0..510 degrees
// nVal represents the value to set (0.. NUM_RINGS)
// nMidX,nMidY define the center of the XGlowball
void drawXGlowball(gslc_tsGui* pGui,gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd)
{
int16_t nValLast = pGlowball->nValLast;
int8_t nRingInd;
if (nVal > nValLast) {
for (nRingInd = nValLast + 1; nRingInd <= nVal; nRingInd++) {
drawXGlowballRing(pGui, pGlowball, nMidX, nMidY, nRingInd, nAngStart, nAngEnd, false);
}
} else {
for (nRingInd = nValLast; nRingInd > nVal; nRingInd--) {
drawXGlowballRing(pGui, pGlowball, nMidX, nMidY, nRingInd, nAngStart, nAngEnd, true);
}
}
pGlowball->nValLast = nVal;
}
void gslc_ElemXGlowballSetVal(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nVal)
{
if ((pGui == NULL) || (pElemRef == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetVal";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
// Update the value
pGlowball->nVal = nVal;
// Mark for redraw
// - Only need incremental redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_INC);
}
void gslc_ElemXGlowballSetAngles(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nAngStart, int16_t nAngEnd)
{
if ((pGui == NULL) || (pElemRef == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetAngles";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
// Update the angular ranges
pGlowball->nAngStart = nAngStart;
pGlowball->nAngEnd = nAngEnd;
// Mark for redraw
// - Force full redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
void gslc_ElemXGlowballSetQuality(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nQuality)
{
if ((pGui == NULL) || (pElemRef == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetQuality";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
// Update the rendering quality setting
pGlowball->nQuality = nQuality;
// Mark for redraw
// - Force full redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
void gslc_ElemXGlowballSetColorBack(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colBg)
{
if ((pGui == NULL) || (pElemRef == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballSetColorBack";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return;
}
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
gslc_tsXGlowball* pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
// Update the background color
pGlowball->colBg = colBg;
// Mark for redraw
// - Force full redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_FULL);
}
// Redraw the element
// - Note that this redraw is for the entire element rect region
// - The Draw function parameters use void pointers to allow for
// simpler callback function definition & scalability.
bool gslc_ElemXGlowballDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw)
{
if ((pvGui == NULL) || (pvElemRef == NULL)) {
static const char GSLC_PMEM FUNCSTR[] = "ElemXGlowballDraw";
GSLC_DEBUG2_PRINT_CONST(ERRSTR_NULL,FUNCSTR);
return false;
}
// Typecast the parameters to match the GUI and element types
gslc_tsGui* pGui = (gslc_tsGui*)(pvGui);
gslc_tsElemRef* pElemRef = (gslc_tsElemRef*)(pvElemRef);
gslc_tsElem* pElem = gslc_GetElemFromRef(pGui,pElemRef);
// Fetch the element's extended data structure
gslc_tsXGlowball* pGlowball;
pGlowball = (gslc_tsXGlowball*)(pElem->pXData);
if (pGlowball == NULL) {
GSLC_DEBUG2_PRINT("ERROR: ElemXGlowballDraw(%s) pXData is NULL\n","");
return false;
}
// --------------------------------------------------------------------------
// Init for default drawing
// --------------------------------------------------------------------------
int16_t nElemX,nElemY;
uint16_t nElemW,nElemH;
nElemX = pElem->rElem.x;
nElemY = pElem->rElem.y;
nElemW = pElem->rElem.w;
nElemH = pElem->rElem.h;
// Calculate center of XGlowball
int16_t nMidX, nMidY;
nMidX = nElemX + (nElemW / 2);
nMidY = nElemY + (nElemH / 2);
// Fetch the current value
int16_t nVal = pGlowball->nVal;
int16_t nAngStart = pGlowball->nAngStart;
int16_t nAngEnd = pGlowball->nAngEnd;
// Check to see if we need full redraw
if (eRedraw == GSLC_REDRAW_FULL) {
// Erase the region
gslc_DrawFillRect(pGui, pElem->rElem, pGlowball->colBg);
// Now force redraw from zero level to current value
pGlowball->nValLast = 0;
}
// Draw the glowball
drawXGlowball(pGui, pGlowball, nMidX, nMidY, nVal, nAngStart, nAngEnd);
// --------------------------------------------------------------------------
// Mark the element as no longer requiring redraw
gslc_ElemSetRedraw(pGui,pElemRef,GSLC_REDRAW_NONE);
return true;
}
// ============================================================================

View file

@ -0,0 +1,136 @@
#ifndef _GUISLICE_EX_XGLOWBALL_H_
#define _GUISLICE_EX_XGLOWBALL_H_
#include "GUIslice.h"
// =======================================================================
// GUIslice library extension: XGlowball
// - Calvin Hass
// - https://www.impulseadventure.com/elec/guislice-gui.html
// - https://github.com/ImpulseAdventure/GUIslice
// =======================================================================
//
// The MIT License
//
// Copyright 2016-2020 Calvin Hass
//
// 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.
//
// =======================================================================
/// \file XGlowball.h
#ifdef __cplusplus
extern "C" {
#endif // __cplusplus
// ============================================================================
// Extended Element: Example template
// ============================================================================
// Define unique identifier for extended element type
// - Select any number above GSLC_TYPE_BASE_EXTEND
#define GSLC_TYPEX_GLOW GSLC_TYPE_BASE_EXTEND + 24
// Defines the attributes of each ring in the XGlowball gauge
typedef struct {
uint8_t nRad1; // Inner radius
uint8_t nRad2; // Outer radius
gslc_tsColor cCol; // Fill color
} gslc_tsXGlowballRing;
// Extended element data structures
// - These data structures are maintained in the gslc_tsElem
// structure via the pXData pointer
/// Extended data for Slider element
typedef struct {
// Config
int16_t nMidX; ///< Gauge midpoint X coord
int16_t nMidY; ///< Gauge midpoint Y coord
gslc_tsXGlowballRing* pRings; ///< Ring definition array
uint8_t nNumRings; ///< Number of rings in definition
// Style config
uint16_t nQuality; ///< Rendering quality (number of segments / rotation)
int16_t nAngStart; ///< Starting angle (0..510 degrees)
int16_t nAngEnd; ///< Ending angle (0..510 degrees)
gslc_tsColor colBg; ///< Background color (for redraw)
// State
int16_t nVal; ///< Current value
int16_t nValLast; ///< Previous value
// Callbacks
} gslc_tsXGlowball;
///
/// Create a XGlowball element
///
/// \param[in] pGui: Pointer to GUI
/// \param[in] nElemId: Element ID to assign (0..16383 or GSLC_ID_AUTO to autogen)
/// \param[in] nPage: Page ID to attach element to
/// \param[in] pXData: Ptr to extended element data structure
/// \param[in] nMidX: Center X coordinate
/// \param[in] nMidY: Center Y coordinate
/// \param[in] pRings: Pointer to tsXGlowballRing structure array defining appearance
/// \param[in] nNumRings: Number of rings in pRings array
///
/// \return Pointer to Element reference or NULL if failure
///
gslc_tsElemRef* gslc_ElemXGlowballCreate(gslc_tsGui* pGui, int16_t nElemId, int16_t nPage,
gslc_tsXGlowball* pXData, int16_t nMidX, int16_t nMidY, gslc_tsXGlowballRing* pRings, uint8_t nNumRings);
///
/// Draw the XGlowball element on the screen
/// - Called from gslc_ElemDraw()
///
/// \param[in] pvGui: Void ptr to GUI (typecast to gslc_tsGui*)
/// \param[in] pvElemRef: Void ptr to Element (typecast to gslc_tsElemRef*)
/// \param[in] eRedraw: Redraw mode
///
/// \return true if success, false otherwise
///
bool gslc_ElemXGlowballDraw(void* pvGui,void* pvElemRef,gslc_teRedrawType eRedraw);
// XGlowball draw helper routines
void drawXGlowballArc(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nRad1, int16_t nRad2, gslc_tsColor cArc, uint16_t nAngStart, uint16_t nAngEnd);
void drawXGlowballRing(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd, bool bErase);
void drawXGlowball(gslc_tsGui* pGui, gslc_tsXGlowball* pGlowball, int16_t nMidX, int16_t nMidY, int16_t nVal, uint16_t nAngStart, uint16_t nAngEnd);
void gslc_ElemXGlowballSetAngles(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nAngStart, int16_t nAngEnd);
void gslc_ElemXGlowballSetVal(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, int16_t nVal);
void gslc_ElemXGlowballSetQuality(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, uint16_t nQuality);
void gslc_ElemXGlowballSetColorBack(gslc_tsGui* pGui, gslc_tsElemRef* pElemRef, gslc_tsColor colBg);
// ============================================================================
// ------------------------------------------------------------------------
// Read-only element macros
// ------------------------------------------------------------------------
// Macro initializers for Read-Only Elements in Flash/PROGMEM
//
#ifdef __cplusplus
}
#endif // __cplusplus
#endif // _GUISLICE_EX_XGLOWBALL_H_

Some files were not shown because too many files have changed in this diff Show more