Compare commits

...

1 commit

Author SHA1 Message Date
Doxygen CI
9ae75ada25 Deploy docs to GitHub Pages from commit 2dd4b85c43
Commit: 2dd4b85c43
GitHub Actions run: 4613482004
2023-04-05 00:26:57 +00:00
9 changed files with 12 additions and 449 deletions

1
.nojekyll Normal file
View file

@ -0,0 +1 @@

View file

@ -1,210 +0,0 @@
// SPDX-FileCopyrightText: 2023 P Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*!
* @file Adafruit_CPFS.cpp
*
* This is a barebones library to:
*
* - Make a CircuitPython-capable board's flash filesystem accessible to
* Arduino code.
* - Make this same drive accessible to a host computer over USB.
*
* This is an "80/20" library to cover the most common use case, with least
* code and documentation, for non-technical users: if a board supports
* CircuitPython, then Arduino code and a host computer can both access that
* drive. Flash formatting is done by installing CircuitPython once
* (pre-built for just about everything), no special steps. That's it.
* NOT for SD cards, special flash partitioning, etc. Those can always be
* implemented manually using the Adafruit_TinyUSB library, but this is
* not the code for it. Keeping it really simple.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Phil "Paint Your Dragon" Burgess for Adafruit Industries.
*
* MIT license, all text here must be included in any redistribution.
*
*/
#if defined(USE_TINYUSB) || defined(ESP32)
#include "Adafruit_CPFS.h"
#include <Adafruit_SPIFlash.h>
#include <Adafruit_TinyUSB.h>
#if defined(_SAMD21_)
#include <Adafruit_InternalFlash.h>
// These apply to M0 boards only, ignored elsewhere:
#define INTERNAL_FLASH_FS_SIZE (64 * 1024)
#define INTERNAL_FLASH_FS_START (0x00040000 - 256 - 0 - INTERNAL_FLASH_FS_SIZE)
#endif
// Library state is maintained in a few global variables (rather than in the
// Adafruit_CPFS class) as there's only one filesystem instance anyway, and
// also that the mass storage callbacks are C and require access to this info.
// For several major board types, the correct flash transport to use
// is known at compile-time:
#if defined(ARDUINO_ARCH_ESP32)
static Adafruit_FlashTransport_ESP32 _transport;
#elif defined(ARDUINO_ARCH_RP2040)
static Adafruit_FlashTransport_RP2040_CPY _transport;
#elif defined(EXTERNAL_FLASH_USE_QSPI)
static Adafruit_FlashTransport_QSPI _transport;
#elif defined(EXTERNAL_FLASH_USE_CS) && defined(EXTERNAL_FLASH_USE_SPI)
static Adafruit_FlashTransport_SPI _transport(EXTERNAL_FLASH_USE_CS,
EXTERNAL_FLASH_USE_SPI);
#else
// If not one of the above board types, nor EXTERNAL_FLASH_USE_* defined,
// it's probably a SAMD21. Some can be "Haxpress" modified to add external
// SPI flash & run a special CircuitPython build, but Arduino IDE lacks a
// distinct special board select...at compile-time, indistinguishable from
// a stock M0 board, could go either way. Thus, the transport and flash
// members are pointers, initialized at run-time depending on arguments
// passed (or not) to the begin() function.
#define HAXPRESS
static Adafruit_FlashTransport_SPI *_transport;
static void *_flash;
#endif
#if !defined HAXPRESS
static Adafruit_SPIFlash _flash(&_transport);
#endif
static Adafruit_USBD_MSC _usb_msc;
static FatVolume _fatfs;
static bool _started = 0;
static bool _changed = 0;
#if defined(HAXPRESS)
// On Haxpress-capable boards, flash type (internal vs SPI) isn't known
// at compile time, so callbacks are provided for both, and one set or
// other is installed in begin().
static int32_t msc_read_cb_internal(uint32_t lba, void *buffer,
uint32_t bufsize) {
return ((Adafruit_InternalFlash *)_flash)
->readBlocks(lba, (uint8_t *)buffer, bufsize / 512)
? bufsize
: -1;
}
static int32_t msc_write_cb_internal(uint32_t lba, uint8_t *buffer,
uint32_t bufsize) {
_changed = 1;
return ((Adafruit_InternalFlash *)_flash)
->writeBlocks(lba, buffer, bufsize / 512)
? bufsize
: -1;
}
static void msc_flush_cb_internal(void) {
((Adafruit_InternalFlash *)_flash)->syncBlocks();
_fatfs.cacheClear();
}
static int32_t msc_read_cb_spi(uint32_t lba, void *buffer, uint32_t bufsize) {
return ((Adafruit_SPIFlash *)_flash)
->readBlocks(lba, (uint8_t *)buffer, bufsize / 512)
? bufsize
: -1;
}
static int32_t msc_write_cb_spi(uint32_t lba, uint8_t *buffer,
uint32_t bufsize) {
_changed = 1;
return ((Adafruit_SPIFlash *)_flash)->writeBlocks(lba, buffer, bufsize / 512)
? bufsize
: -1;
}
static void msc_flush_cb_spi(void) {
((Adafruit_SPIFlash *)_flash)->syncBlocks();
_fatfs.cacheClear();
}
#else
// Flash type is known at compile time. Simple callbacks.
static int32_t msc_read_cb(uint32_t lba, void *buffer, uint32_t bufsize) {
return _flash.readBlocks(lba, (uint8_t *)buffer, bufsize / 512) ? bufsize
: -1;
}
static int32_t msc_write_cb(uint32_t lba, uint8_t *buffer, uint32_t bufsize) {
_changed = 1;
return _flash.writeBlocks(lba, buffer, bufsize / 512) ? bufsize : -1;
}
static void msc_flush_cb(void) {
_flash.syncBlocks();
_fatfs.cacheClear();
}
#endif // end !HAXPRESS
FatVolume *Adafruit_CPFS::begin(int cs, void *spi) {
if (_started)
return &_fatfs; // Don't re-init if already running
_started = 1;
#if defined(HAXPRESS)
if ((cs >= 0) && (spi != NULL)) { // External flash
if ((_transport = new Adafruit_FlashTransport_SPI(cs, (SPIClass *)spi))) {
if ((_flash = (void *)new Adafruit_SPIFlash(_transport))) {
((Adafruit_SPIFlash *)_flash)->begin();
_usb_msc.setID("Adafruit", "External Flash", "1.0");
_usb_msc.setReadWriteCallback(msc_read_cb_spi, msc_write_cb_spi,
msc_flush_cb_spi);
_usb_msc.setCapacity(((Adafruit_SPIFlash *)_flash)->size() / 512, 512);
_usb_msc.setUnitReady(true);
_usb_msc.begin();
if (_fatfs.begin((Adafruit_SPIFlash *)_flash))
return &_fatfs;
} // end if new flash
} // end if new transport
} else { // Internal flash
if ((_flash = (void *)new Adafruit_InternalFlash(INTERNAL_FLASH_FS_START,
INTERNAL_FLASH_FS_SIZE))) {
((Adafruit_InternalFlash *)_flash)->begin();
_usb_msc.setID("Adafruit", "Internal Flash", "1.0");
_usb_msc.setReadWriteCallback(msc_read_cb_internal, msc_write_cb_internal,
msc_flush_cb_internal);
_usb_msc.setCapacity(((Adafruit_InternalFlash *)_flash)->size() / 512,
512);
_usb_msc.setUnitReady(true);
_usb_msc.begin();
if (_fatfs.begin((Adafruit_InternalFlash *)_flash))
return &_fatfs;
} // end if new flash
}
#else
_flash.begin();
_usb_msc.setID("Adafruit", "Onboard Flash", "1.0");
_usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb);
_usb_msc.setCapacity(_flash.size() / 512, 512);
_usb_msc.setUnitReady(true);
_usb_msc.begin();
if (_fatfs.begin(&_flash))
return &_fatfs;
#endif // end HAXPRESS
_started = 0;
return NULL;
}
bool Adafruit_CPFS::changed(void) { return _changed; }
void Adafruit_CPFS::change_ack(void) { _changed = 0; }
#endif // end USE_TINYUSB || ESP32

View file

@ -1,107 +0,0 @@
// SPDX-FileCopyrightText: 2023 P Burgess for Adafruit Industries
//
// SPDX-License-Identifier: MIT
/*!
* @file Adafruit_CPFS.h
*
* This is a barebones library to:
*
* - Make a CircuitPython-capable board's flash filesystem accessible to
* Arduino code.
* - Make this same drive accessible to a host computer over USB.
*
* This is an "80/20" library to cover the most common use case, with least
* code and documentation, for non-technical users: if a board supports
* CircuitPython, then Arduino code and a host computer can both access that
* drive. Flash formatting is done by installing CircuitPython once
* (pre-built for just about everything), no special steps. That's it.
* NOT for SD cards, special flash partitioning, etc. Those can always be
* implemented manually using the Adafruit_TinyUSB library, but this is
* not the code for it. Keeping it really simple.
*
* Adafruit invests time and resources providing this open source code,
* please support Adafruit and open-source hardware by purchasing
* products from Adafruit!
*
* Written by Phil "Paint Your Dragon" Burgess for Adafruit Industries.
*
* MIT license, all text here must be included in any redistribution.
*
*/
#pragma once
#if defined(USE_TINYUSB) || defined(ESP32)
#include <SdFat.h>
/*!
@brief Adafruit_CPFS is a minimal class to assist in using a board's
CIRCUITPY flash filesystem with Arduino code, and making it
available to a host computer over USB.
All functions here are currently static -- you do not need to
declare an object (unless you want to). Since there's only one
CIRCUITPY filesystem, library state is maintained internally
and any of these functions can be called directly,
e.g. Adafruit_CPFS::begin(). Putting the functions inside a
class simply avoids namespace issues.
*/
class Adafruit_CPFS {
public:
/*!
@brief Adafruit_CPFS constructor. No arguments. User code is not
required to declare an object (all functions are static and can
be invoked directly without an object), but it's still an option
if the resulting code reads easier for you (e.g. using
object.func() rather than class::func() syntax), all good.
*/
Adafruit_CPFS(void){};
/*!
@brief Adafruit_CPFS destructor.
*/
~Adafruit_CPFS(void){};
/*!
@brief Access a board's CIRCUITPY flash filesystem, making it
available to code and to a host computer over USB.
IMPORTANT: this function should always be called BEFORE
Serial.begin().
@param cs OPTIONAL SPI flash chip-select pin. This should ONLY be
used on "Haxpress" boards (QT Py or Trinket M0
with flash chip retrofitted). For most boards,
including unmodified QT Py or Trinket M0, do not
pass any arguments.
@param spi OPTIONAL Pointer to SPI peripheral interfaced with flash
chip. Again, only for a couple of Haxpress M0
boards.
@return FatVolume* On success, a non-NULL pointer to a FatVolume
object, where files can then be opened and accessed.
NULL on error (uninitialized CIRCUITPY drive, or
invalid cs/spi combo)..
*/
static FatVolume *begin(int cs = -1, void *spi = NULL);
/*!
@brief Checks if USB-connected host computer has made any changes
(new or altered files) to the drive. Code can use this if it
needs to auto-restart on change.
@return 1/true if host computer has written to drive, 0/false otherwise.
*/
static bool changed(void);
/*!
@brief Acknowledge and reset status of changed() polling. Change-
sensitive code can call this to distinguish subsequent
changed() calls.
*/
static void change_ack(void);
};
#else
#error "Requires TinyUSB stack. From the Arduino IDE 'Tools' menu,"
#error "select 'USB Stack -> Adafruit TinyUSB' and recompile."
#endif // end USE_TINYUSB || ESP32

21
LICENSE
View file

@ -1,21 +0,0 @@
MIT License
Copyright (c) 2023 Adafruit Industries
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.

View file

@ -1,33 +0,0 @@
# Adafruit_CPFS
[C]ircuit[P]ython [F]ile[S]ystem library for Arduino.
This is a small library that does one...well okay, two...things:
* Makes a CircuitPython-capable board's flash filesystem accessible to
Arduino code.
* Make this same drive accessible to a host computer over USB.
Nothing new here, same can be done using Adafruit_TinyUSB and SdFat, this
simply wraps the code in a library out of sight, as it's normally quite a
tangle of #ifdefs. NOT for SD cards or unusual flash partitioning. Again,
those can be implemented with the aforementioned libraries. This is an
"80/20" library to cover the most common use case, with least code and
documentation, for non-technical users: if a board supports CircuitPython,
then Arduino code and a host computer can both access that drive. Flash
formatting is done by installing CircuitPython once (pre-built for just
about everything), no special steps. That's it.
When an Arduino sketch using this library is uploaded to the board,
CircuitPython will be overwritten, but the flash drive contents remain
intact and are available to our code. CircuitPython can be reinstalled
later via bootloader, drive again remains intact. Best of both worlds!
Must enable TinyUSB before compiling:
Tools -> USB Stack -> Adafruit_TinyUSB
IMPORTANT: keep a backup of the CIRCUITPY drive contents somewhere safe.
USB + mass storage + Serial is pretty demanding, and accidents do happen.
You may need to reinstall CircuitPython to initialize a botched drive.
See examples/simple for use.

View file

@ -1,68 +0,0 @@
/*
Barebones example for Adafruit_CPFS. Lists CIRCUITPY drive contents to
the Serial console. If anything on the drive changes, a new listing is
shown.
Board must have CircuitPython installed at least once to initialize
the flash filesystem. When this Arduino sketch is uploaded to board,
CircuitPython will be overwritten, but the flash drive contents remain
intact and are available to our code. CircuitPython can be reinstalled
later via bootloader, drive again remains intact. Best of both worlds!
Must enable TinyUSB before compiling:
Tools -> USB Stack -> Adafruit_TinyUSB
IMPORTANT: keep a backup of the CIRCUITPY drive contents somewhere safe.
USB + mass storage + Serial is pretty demanding, and accidents do happen.
*/
#include <Adafruit_CPFS.h>
FatVolume *fs = NULL; // CIRCUITPY flash filesystem, as a FAT pointer
void setup(void) {
// Start the CIRCUITPY flash filesystem FIRST. Very important!
fs = Adafruit_CPFS::begin();
// For "Haxpress" boards (small M0 boards retrofitted with SPI flash),
// a chip-select pin and/or SPI instance can be passed to begin():
// fs = Adafruit_CPFS::begin(SS1, &SPI1); // QT Py M0 Haxpress
// Start Serial AFTER Adafruit_CPFS, or CIRCUITPY won't show on computer.
Serial.begin(115200);
//while(!Serial);
pinMode(LED_BUILTIN, OUTPUT);
if (fs == NULL) { // If CIRCUITPY filesystem is missing or malformed...
// Show error message & blink LED to indicate problem. Full stop.
Serial.println("Can't access board's CIRCUITPY drive.");
Serial.println("Has CircuitPython been previously installed?");
for (;;) digitalWrite(LED_BUILTIN, (millis() / 500) & 1);
} // else valid CIRCUITPY drive, proceed...
// Most simple programs can jump right in at this point, such as reading
// settings or graphics files. Because this particular example monitors
// for changes in the filesystem, it's good to pause here -- a LOT happens
// in begin() when the filesystem is connected to USB, and many rapid-fire
// change events occur. Allow a couple seconds to settle...
delay(2500);
Adafruit_CPFS::change_ack(); // Clear any pent-up change notifications
// Then access files and directories using any SdFat calls (open(), etc.)
// Because fs is a pointer, we use "->" indirection rather than "." access.
fs->ls("/", LS_R | LS_SIZE); // List initial drive contents
}
void loop(void) {
if (Adafruit_CPFS::changed()) { // Anything changed on CIRCUITPY drive?
Adafruit_CPFS::change_ack(); // Got it, thanks.
Serial.println("CIRCUITPY drive contents changed.");
fs->ls("/", LS_R | LS_SIZE); // List updated drive contents
}
// Note that "changes" are often inconsequential -- updating the last-
// touch times when clicking a file from the host computer, for example.
// You might see the directory listing refresh multiple times even when
// nothing of much substance has occurred on the drive. This is normal.
// Most projects need not even concern themselves with change detection.
}

11
index.html Normal file
View file

@ -0,0 +1,11 @@
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<meta charset="UTF-8">
<meta http-equiv="refresh" content="1;url=html/index.html">
<title>Page Redirection</title>
</head>
<body>
If you are not redirected automatically, follow the <a href="html/index.html">link to the documentation</a>
</body>
</html>

View file

@ -1,10 +0,0 @@
name=Adafruit CPFS
version=1.0.0
author=Adafruit
maintainer=Adafruit <info@adafruit.com>
sentence=Arduino library for accessing a board's CircuitPython flash filesystem and presenting it over USB.
paragraph=Arduino library for accessing a board's CircuitPython flash filesystem and presenting it over USB.
category=Data Storage
url=https://github.com/adafruit/Adafruit_CPFS
architectures=samd, rp2040, esp32
depends=SdFat - Adafruit Fork, Adafruit SPIFlash, Adafruit TinyUSB Library, Adafruit InternalFlash, FlashStorage