Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4cc8e6d6db | ||
|
|
fecbac2e25 | ||
|
|
e2e65fd53b | ||
|
|
f22ed52b75 | ||
|
|
03dbd6af65 | ||
|
|
fca7fb5e0f | ||
|
|
80d6e2f0ec | ||
|
|
d35e938c36 | ||
|
|
4e16a700c6 | ||
|
|
d717b58001 | ||
|
|
861da4c361 |
+6
-7
@@ -192,13 +192,12 @@ File File::openNextFile() {
|
||||
String File::readString() {
|
||||
String ret;
|
||||
ret.reserve(size() - position());
|
||||
char temp[256 + 1];
|
||||
int countRead = readBytes(temp, sizeof(temp) - 1);
|
||||
while (countRead > 0) {
|
||||
temp[countRead] = 0;
|
||||
ret += temp;
|
||||
countRead = readBytes(temp, sizeof(temp) - 1);
|
||||
}
|
||||
uint8_t temp[256];
|
||||
int countRead;
|
||||
do {
|
||||
countRead = read(temp, sizeof(temp));
|
||||
ret.concat(temp, countRead);
|
||||
} while (countRead > 0);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
@@ -68,9 +68,11 @@ static int __usb_task_irq;
|
||||
#define USBD_STR_SERIAL (0x03)
|
||||
#define USBD_STR_CDC (0x04)
|
||||
|
||||
|
||||
#define EPNUM_HID 0x83
|
||||
|
||||
#define USBD_MSC_EPOUT 0x03
|
||||
#define USBD_MSC_EPIN 0x84
|
||||
#define USBD_MSC_EPSIZE 64
|
||||
|
||||
const uint8_t *tud_descriptor_device_cb(void) {
|
||||
static tusb_desc_device_t usbd_desc_device = {
|
||||
@@ -89,7 +91,7 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||
.iSerialNumber = USBD_STR_SERIAL,
|
||||
.bNumConfigurations = 1
|
||||
};
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick) {
|
||||
if (__USBInstallSerial && !__USBInstallKeyboard && !__USBInstallMouse && !__USBInstallJoystick && !__USBInstallMassStorage) {
|
||||
// Can use as-is, this is the default USB case
|
||||
return (const uint8_t *)&usbd_desc_device;
|
||||
}
|
||||
@@ -103,6 +105,9 @@ const uint8_t *tud_descriptor_device_cb(void) {
|
||||
if (__USBInstallJoystick) {
|
||||
usbd_desc_device.idProduct |= 0x0100;
|
||||
}
|
||||
if (__USBInstallMassStorage) {
|
||||
usbd_desc_device.idProduct ^= 0x2000;
|
||||
}
|
||||
// Set the device class to 0 to indicate multiple device classes
|
||||
usbd_desc_device.bDeviceClass = 0;
|
||||
usbd_desc_device.bDeviceSubClass = 0;
|
||||
@@ -223,7 +228,7 @@ void __SetupUSBDescriptor() {
|
||||
if (!usbd_desc_cfg) {
|
||||
bool hasHID = __USBInstallKeyboard || __USBInstallMouse || __USBInstallJoystick;
|
||||
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0);
|
||||
uint8_t interface_count = (__USBInstallSerial ? 2 : 0) + (hasHID ? 1 : 0) + (__USBInstallMassStorage ? 1 : 0);
|
||||
|
||||
uint8_t cdc_desc[TUD_CDC_DESC_LEN] = {
|
||||
// Interface number, string index, protocol, report descriptor len, EP In & Out address, size & polling interval
|
||||
@@ -238,7 +243,12 @@ void __SetupUSBDescriptor() {
|
||||
TUD_HID_DESCRIPTOR(hid_itf, 0, HID_ITF_PROTOCOL_NONE, hid_report_len, EPNUM_HID, CFG_TUD_HID_EP_BUFSIZE, 10)
|
||||
};
|
||||
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0);
|
||||
uint8_t msd_itf = interface_count - 1;
|
||||
uint8_t msd_desc[TUD_MSC_DESC_LEN] = {
|
||||
TUD_MSC_DESCRIPTOR(msd_itf, 0, USBD_MSC_EPOUT, USBD_MSC_EPIN, USBD_MSC_EPSIZE)
|
||||
};
|
||||
|
||||
int usbd_desc_len = TUD_CONFIG_DESC_LEN + (__USBInstallSerial ? sizeof(cdc_desc) : 0) + (hasHID ? sizeof(hid_desc) : 0) + (__USBInstallMassStorage ? sizeof(msd_desc) : 0);
|
||||
|
||||
uint8_t tud_cfg_desc[TUD_CONFIG_DESC_LEN] = {
|
||||
// Config number, interface count, string index, total length, attribute, power in mA
|
||||
@@ -260,6 +270,10 @@ void __SetupUSBDescriptor() {
|
||||
memcpy(ptr, hid_desc, sizeof(hid_desc));
|
||||
ptr += sizeof(hid_desc);
|
||||
}
|
||||
if (__USBInstallMassStorage) {
|
||||
memcpy(ptr, msd_desc, sizeof(msd_desc));
|
||||
ptr += sizeof(msd_desc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -367,4 +381,55 @@ extern "C" void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_r
|
||||
(void) bufsize;
|
||||
}
|
||||
|
||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) __attribute__((weak));
|
||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
(void) lba;
|
||||
(void) offset;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) __attribute__((weak));
|
||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
return false;
|
||||
}
|
||||
|
||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) __attribute__((weak));
|
||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
(void) lba;
|
||||
(void) offset;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
return -1;
|
||||
}
|
||||
|
||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) __attribute__((weak));
|
||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
||||
(void) lun;
|
||||
(void) scsi_cmd;
|
||||
(void) buffer;
|
||||
(void) bufsize;
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) __attribute__((weak));
|
||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
|
||||
(void) lun;
|
||||
*block_count = 0;
|
||||
*block_size = 0;
|
||||
}
|
||||
|
||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) __attribute__((weak));
|
||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||
(void) lun;
|
||||
vendor_id[0] = 0;
|
||||
product_id[0] = 0;
|
||||
product_rev[0] = 0;
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -26,6 +26,7 @@ extern void __USBInstallSerial() __attribute__((weak));
|
||||
extern void __USBInstallKeyboard() __attribute__((weak));
|
||||
extern void __USBInstallJoystick() __attribute__((weak));
|
||||
extern void __USBInstallMouse() __attribute__((weak));
|
||||
extern void __USBInstallMassStorage() __attribute__((weak));
|
||||
|
||||
// Big, global USB mutex, shared with all USB devices to make sure we don't
|
||||
// have multiple cores updating the TUSB state in parallel
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#pragma once
|
||||
#define ARDUINO_PICO_MAJOR 2
|
||||
#define ARDUINO_PICO_MINOR 6
|
||||
#define ARDUINO_PICO_REVISION 4
|
||||
#define ARDUINO_PICO_VERSION_STR "2.6.4"
|
||||
#define ARDUINO_PICO_REVISION 5
|
||||
#define ARDUINO_PICO_VERSION_STR "2.6.5"
|
||||
|
||||
@@ -390,7 +390,12 @@ void __not_in_flash_func(SerialUART::_handleIRQ)(bool inIRQ) {
|
||||
// ICR is write-to-clear
|
||||
uart_get_hw(_uart)->icr = UART_UARTICR_RTIC_BITS | UART_UARTICR_RXIC_BITS;
|
||||
while (uart_is_readable(_uart)) {
|
||||
auto val = uart_getc(_uart);
|
||||
uint32_t raw = uart_get_hw(_uart)->dr;
|
||||
if (raw & 0x700) {
|
||||
// Framing, Parity, or Break. Ignore this bad char
|
||||
continue;
|
||||
}
|
||||
uint8_t val = raw & 0xff;
|
||||
auto next_writer = _writer + 1;
|
||||
if (next_writer == _fifoSize) {
|
||||
next_writer = 0;
|
||||
|
||||
+2
-2
@@ -54,9 +54,9 @@ author = u'Earle F. Philhower, III'
|
||||
# built documents.
|
||||
#
|
||||
# The short X.Y version.
|
||||
version = u'2.6.4'
|
||||
version = u'2.6.5'
|
||||
# The full version, including alpha/beta/rc tags.
|
||||
release = u'2.6.4'
|
||||
release = u'2.6.5'
|
||||
|
||||
# The language for content autogenerated by Sphinx. Refer to documentation
|
||||
# for a list of supported languages.
|
||||
|
||||
@@ -39,6 +39,8 @@ For the latest version, always check https://github.com/earlephilhower/arduino-p
|
||||
USB (Arduino and Adafruit_TinyUSB) <usb>
|
||||
Multicore Processing <multicore>
|
||||
|
||||
Single File USB Drive <singlefile>
|
||||
|
||||
FreeRTOS SMP (multicore) <freertos>
|
||||
|
||||
WiFi (Pico-W Support) <wifi>
|
||||
|
||||
@@ -0,0 +1,82 @@
|
||||
SingleFileDrive
|
||||
===============
|
||||
|
||||
USB drive mode is supported through the ``SingleFileDrive`` class which
|
||||
allows the Pico to emulate a FAT-formatted USB stick while preserving the
|
||||
onboard LittleFS filesystem. A single file can be exported this way without
|
||||
needing to use FAT as the onboard filesystem (FAT is not appropriate for
|
||||
flash-based devices without complicated wear leveling because of the update
|
||||
frequency of the FAT tables).
|
||||
|
||||
This emulation is very simple and only allows for the reading of the single
|
||||
file, and deleting it.
|
||||
|
||||
Callbacks, Interrupt Safety, and File Operations
|
||||
------------------------------------------------
|
||||
|
||||
The ``SingleFileDrive`` library allows your application to get a callback
|
||||
when a PC attempts to mount or unmount the Pico as a drive. Your app can
|
||||
also get a callback if the user attempts to delete the file (but your
|
||||
sketch does not actually need to delete the file, it's up to you).
|
||||
|
||||
Note that when the USB drive is mounted by a PC it is not safe for your
|
||||
main sketch to make changes to the LittleFS filesystem or the file being
|
||||
exported. So, normally, your ``onPlug`` callback will set a flag letting
|
||||
your application know not to touch the filesystem, with the ``onUnplug``
|
||||
callback clearing this flag.
|
||||
|
||||
Also, because the USB port can be connected at any time, it is important
|
||||
to disable interrupts using ``noInterrupts()`` before writing to a file
|
||||
you will be exporting (and restoring them with ``interrupts()`` afterwards).
|
||||
It is also important to ``close()`` the file after each update, or the
|
||||
on-flash version the ``SingleFileDrive`` will attempt to export may not be
|
||||
up to date causing issues later on.
|
||||
|
||||
See the included ``DataLoggerUSB`` sketch for an example of working with
|
||||
these limitations.
|
||||
|
||||
Using SingleFileDrive
|
||||
---------------------
|
||||
|
||||
Implementing the drive requires including the header file, starting LittleFS,
|
||||
defining your callbacks, and telling the library what file to export. No
|
||||
polling or other calls are required outside of your ``setup()``. (Note that
|
||||
the callback routines allow for a parameter to be passed to them, but in most
|
||||
cases this can be safely ignored.)
|
||||
|
||||
.. code:: cpp
|
||||
|
||||
#include <LittleFS.h>
|
||||
#include <SingleFileDrive.h>
|
||||
|
||||
void myPlugCB(uint32_t data) {
|
||||
// Tell my app not to write to flash, we're connected
|
||||
}
|
||||
|
||||
void myUnplugCB(uint32_t data) {
|
||||
// I can start writing to flash again
|
||||
}
|
||||
|
||||
void myDeleteDB(uint32_t data) {
|
||||
// Maybe LittleFS.remove("myfile.txt")? or do nothing
|
||||
}
|
||||
|
||||
void setup() {
|
||||
LittleFS.begin();
|
||||
singleFileDrive.onPlug(myPlugCB);
|
||||
singleFileDrive.onUnplug(myUnplugCB);
|
||||
singleFileDrive.onDelete(myDeleteCB);
|
||||
singleFileDrive.begin("littlefsfile.csv", "Data Recorder.csv");
|
||||
// ... rest of setup ...
|
||||
}
|
||||
|
||||
void loop() {
|
||||
// Take some measurements, delay, etc.
|
||||
if (okay-to-write) {
|
||||
noInterrupts();
|
||||
File f = LittleFS.open("littlefsfile.csv", "a");
|
||||
f.printf("%d,%d,%d\n", data1, data2, data3);
|
||||
f.close();
|
||||
interrupts();
|
||||
}
|
||||
}
|
||||
@@ -72,15 +72,14 @@
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID (2)
|
||||
#define CFG_TUD_CDC (1)
|
||||
#define CFG_TUD_MSC (0)
|
||||
#define CFG_TUD_MSC (1)
|
||||
#define CFG_TUD_MIDI (0)
|
||||
#define CFG_TUD_VENDOR (0)
|
||||
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (256)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (256)
|
||||
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE (64)
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE (64)
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -215,7 +215,10 @@ int AudioRingBuffer::available() {
|
||||
}
|
||||
int avail;
|
||||
avail = _wordsPerBuffer - _userOff;
|
||||
avail += ((_bufferCount + _curBuffer - _userBuffer) % _bufferCount) * _wordsPerBuffer;
|
||||
avail += ((_bufferCount + _curBuffer - _userBuffer) % _bufferCount) * _wordsPerBuffer /* total other buffers */ - _wordsPerBuffer /* minus the one currently being output */;
|
||||
if (avail < 0) {
|
||||
avail = 0; // Should never hit
|
||||
}
|
||||
return avail;
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,6 @@ maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Configures requests for OTA bootloader
|
||||
paragraph=Example repository for Ethernet drivers
|
||||
category=Device Control
|
||||
url=https://github.com/earlephilhower.arduino-pico
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
// Simple logger with USB upload to PC
|
||||
// Uses SingleFileDrive to export an onboard LittleFS file to the computer
|
||||
// The PC can open/copy the file, and then the user can delete it to restart
|
||||
|
||||
// Released to the public domain, 2022 - Earle F. Philhower, III
|
||||
|
||||
#include <SingleFileDrive.h>
|
||||
#include <LittleFS.h>
|
||||
|
||||
uint32_t cnt = 0;
|
||||
bool okayToWrite = true;
|
||||
|
||||
// Make the CSV file and give it a simple header
|
||||
void headerCSV() {
|
||||
File f = LittleFS.open("data.csv", "w");
|
||||
f.printf("sample,millis,temp,rand\n");
|
||||
f.close();
|
||||
cnt = 0;
|
||||
}
|
||||
|
||||
// Called when the USB stick connected to a PC and the drive opened
|
||||
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
|
||||
void plug(uint32_t i) {
|
||||
(void) i;
|
||||
okayToWrite = false;
|
||||
}
|
||||
|
||||
// Called when the USB is ejected or removed from a PC
|
||||
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
|
||||
void unplug(uint32_t i) {
|
||||
(void) i;
|
||||
okayToWrite = true;
|
||||
}
|
||||
|
||||
// Called when the PC tries to delete the single file
|
||||
// Note this is from a USB IRQ so no printing to SerialUSB/etc.
|
||||
void deleteCSV(uint32_t i) {
|
||||
(void) i;
|
||||
LittleFS.remove("data.csv");
|
||||
headerCSV();
|
||||
}
|
||||
|
||||
void setup() {
|
||||
Serial.begin();
|
||||
delay(5000);
|
||||
|
||||
LittleFS.begin();
|
||||
|
||||
// Set up the USB disk share
|
||||
singleFileDrive.onDelete(deleteCSV);
|
||||
singleFileDrive.onPlug(plug);
|
||||
singleFileDrive.onUnplug(unplug);
|
||||
singleFileDrive.begin("data.csv", "Recorded data from the Raspberry Pi Pico.csv");
|
||||
|
||||
// Find the last written data
|
||||
File f = LittleFS.open("data.csv", "r");
|
||||
if (!f || !f.size()) {
|
||||
cnt = 1;
|
||||
headerCSV();
|
||||
} else {
|
||||
if (f.size() > 2048) {
|
||||
f.seek(f.size() - 1024);
|
||||
}
|
||||
do {
|
||||
String s = f.readStringUntil('\n');
|
||||
sscanf(s.c_str(), "%lu,", &cnt);
|
||||
} while (f.available());
|
||||
f.close();
|
||||
cnt++;
|
||||
}
|
||||
|
||||
Serial.printf("Starting acquisition at %d\n", cnt);
|
||||
}
|
||||
|
||||
void loop() {
|
||||
float temp = analogReadTemp();
|
||||
uint32_t hwrand = rp2040.hwrand32();
|
||||
// Make sure the USB connect doesn't happen while we're writing!
|
||||
noInterrupts();
|
||||
if (okayToWrite) {
|
||||
Serial.printf("Sampling...%lu\n", cnt);
|
||||
// Don't want the USB to connect during an update!
|
||||
File f = LittleFS.open("data.csv", "a");
|
||||
if (f) {
|
||||
f.printf("%lu,%lu,%f,%lu\n", cnt++, millis(), temp, hwrand);
|
||||
f.close();
|
||||
}
|
||||
}
|
||||
interrupts();
|
||||
|
||||
delay(10000);
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#######################################
|
||||
# Syntax Coloring Map
|
||||
#######################################
|
||||
|
||||
#######################################
|
||||
# Datatypes (KEYWORD1)
|
||||
#######################################
|
||||
|
||||
SingleFileDrive KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Methods and Functions (KEYWORD2)
|
||||
#######################################
|
||||
|
||||
singleFileDrive KEYWORD1
|
||||
onDelete KEYWORD1
|
||||
onPlug KEYWORD1
|
||||
onUnplug KEYWORD1
|
||||
|
||||
#######################################
|
||||
# Constants (LITERAL1)
|
||||
#######################################
|
||||
@@ -0,0 +1,10 @@
|
||||
name=SingleFileDrive
|
||||
version=1.0.0
|
||||
author=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
maintainer=Earle F. Philhower, III <earlephilhower@yahoo.com>
|
||||
sentence=Allows using USB MSC (USB stick) to transfer an onboard flash file to a PC
|
||||
paragraph=Emulates a USB stick and presents a single file for users to copy over/erase
|
||||
category=Device Control
|
||||
url=https://github.com/earlephilhower/arduino-pico
|
||||
architectures=rp2040
|
||||
dot_a_linkage=true
|
||||
@@ -0,0 +1,396 @@
|
||||
/*
|
||||
SingleFileDrive - Emulates a USB stick for easy data transfer
|
||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include <SingleFileDrive.h>
|
||||
#include <LittleFS.h>
|
||||
#include <class/msc/msc.h>
|
||||
|
||||
SingleFileDrive singleFileDrive;
|
||||
|
||||
static const uint32_t _hddsize = (256 * 1024 * 1024); // 256MB
|
||||
static const uint32_t _hddsects = _hddsize / 512;
|
||||
|
||||
// Ensure we are logged in to the USB framework
|
||||
void __USBInstallMassStorage() {
|
||||
/* dummy */
|
||||
}
|
||||
|
||||
SingleFileDrive::SingleFileDrive() {
|
||||
}
|
||||
|
||||
SingleFileDrive::~SingleFileDrive() {
|
||||
end();
|
||||
}
|
||||
|
||||
void SingleFileDrive::onDelete(void (*cb)(uint32_t), uint32_t cbData) {
|
||||
_cbDelete = cb;
|
||||
_cbDeleteData = cbData;
|
||||
}
|
||||
|
||||
void SingleFileDrive::onPlug(void (*cb)(uint32_t), uint32_t cbData) {
|
||||
_cbPlug = cb;
|
||||
_cbPlugData = cbData;
|
||||
}
|
||||
|
||||
void SingleFileDrive::onUnplug(void (*cb)(uint32_t), uint32_t cbData) {
|
||||
_cbUnplug = cb;
|
||||
_cbUnplugData = cbData;
|
||||
}
|
||||
|
||||
bool SingleFileDrive::begin(const char *localFile, const char *dosFile) {
|
||||
if (_started) {
|
||||
return false;
|
||||
}
|
||||
_localFile = strdup(localFile);
|
||||
_dosFile = strdup(dosFile);
|
||||
_started = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void SingleFileDrive::end() {
|
||||
_started = false;
|
||||
free(_localFile);
|
||||
free(_dosFile);
|
||||
_localFile = nullptr;
|
||||
_dosFile = nullptr;
|
||||
}
|
||||
|
||||
void SingleFileDrive::bootSector(char buff[512]) {
|
||||
// 256MB FAT16 stolen from mkfs.fat
|
||||
// dd if=/dev/zero of=/tmp/fat.bin bs=1M seek=255 count=1
|
||||
// mkfs.fat -F 16 -r 16 -n PICODISK -i 12345678 -s 128 -m ':(' /tmp/fat.bin
|
||||
const uint8_t hdr[] = {
|
||||
0xeb, 0x3c, 0x90, 0x6d, 0x6b, 0x66, 0x73, 0x2e, 0x66, 0x61, 0x74, 0x00,
|
||||
0x02, 0x80, 0x80, 0x00, 0x02, 0x00, 0x08, 0x00, 0x00, 0xf8, 0x80, 0x00,
|
||||
0x20, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00,
|
||||
0x80, 0x00, 0x29, 0x78, 0x56, 0x34, 0x12, 0x50, 0x49, 0x43, 0x4f, 0x44,
|
||||
0x49, 0x53, 0x4b, 0x20, 0x20, 0x20, 0x46, 0x41, 0x54, 0x31, 0x36, 0x20,
|
||||
0x20, 0x20, 0x0e, 0x1f, 0xbe, 0x5b, 0x7c, 0xac, 0x22, 0xc0, 0x74, 0x0b,
|
||||
0x56, 0xb4, 0x0e, 0xbb, 0x07, 0x00, 0xcd, 0x10, 0x5e, 0xeb, 0xf0, 0x32,
|
||||
0xe4, 0xcd, 0x16, 0xcd, 0x19, 0xeb, 0xfe, 0x3a, 0x28, 0x0d, 0x0a, 0x00
|
||||
};
|
||||
memset(buff, 0, 512);
|
||||
memcpy(buff, hdr, sizeof(hdr));
|
||||
buff[0x1fe] = 0x55;
|
||||
buff[0x1ff] = 0xff;
|
||||
}
|
||||
|
||||
static char _toLegalFATChar(char c) {
|
||||
const char *odds = "!#$%&'()-@^_`{}~";
|
||||
c = toupper(c);
|
||||
if (((c >= '0') && (c <= '9')) || ((c >= 'A') && (c <= 'Z')) || strchr(odds, c)) {
|
||||
return c;
|
||||
} else {
|
||||
return '~';
|
||||
}
|
||||
}
|
||||
|
||||
void SingleFileDrive::directorySector(char buff[512]) {
|
||||
const uint8_t lbl[] = {
|
||||
0x50, 0x49, 0x43, 0x4f, 0x44, 0x49, 0x53, 0x4b, 0x20, 0x20, 0x20, 0x08, 0x00, 0x00, 0xac, 0x56,
|
||||
0x82, 0x55, 0x82, 0x55, 0x00, 0x00, 0xac, 0x56, 0x82, 0x55
|
||||
}; //, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
|
||||
memset(buff, 0, 512);
|
||||
memcpy(buff, lbl, sizeof(lbl));
|
||||
buff += 32; // Skip the just-set label
|
||||
|
||||
// Create a legal 11-char UPPERCASE FILENAME WITH 0x20 PAD
|
||||
char SFN[11];
|
||||
memset(SFN, ' ', 11);
|
||||
for (int i = 0; (i < 8) && _dosFile[i] && (_dosFile[i] != '.'); i++) {
|
||||
SFN[i] = _toLegalFATChar(_dosFile[i]);
|
||||
}
|
||||
char *dot = _dosFile + strlen(_dosFile) - 1;
|
||||
while ((dot >= _dosFile) && (*dot != '.')) {
|
||||
dot--;
|
||||
}
|
||||
if (*dot == '.') {
|
||||
dot++;
|
||||
for (int i = 0; (i < 3) && dot[i]; i++) {
|
||||
SFN[8 + i] = _toLegalFATChar(dot[i]);
|
||||
}
|
||||
}
|
||||
uint8_t chksum = 0; // for LFN
|
||||
for (int i = 0; i < 11; i++) {
|
||||
chksum = (chksum >> 1) + (chksum << 7) + SFN[i];
|
||||
}
|
||||
|
||||
// Create LFN structure
|
||||
int entries = (strlen(_dosFile) + 12) / 13; // round up
|
||||
for (int i = 0; i < entries; i++) {
|
||||
*buff++ = (entries - i) | (i == 0 ? 0x40 : 0);
|
||||
const char *partname = _dosFile + 13 * (entries - i - 1);
|
||||
for (int j = 0; j < 13; j++) {
|
||||
uint16_t u;
|
||||
if (j > (int)strlen(partname)) {
|
||||
u = 0xffff;
|
||||
} else {
|
||||
u = partname[j] & 0xff;
|
||||
}
|
||||
*buff++ = u & 0xff;
|
||||
*buff++ = (u >> 8) & 0xff;
|
||||
if (j == 4) {
|
||||
*buff++ = 0x0f; // LFN ATTR
|
||||
*buff++ = 0;
|
||||
*buff++ = chksum;
|
||||
} else if (j == 10) {
|
||||
*buff++ = 0;
|
||||
*buff++ = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Create SFN
|
||||
memset(buff, 0, 32);
|
||||
for (int i = 0; i < 11; i++) {
|
||||
buff[i] = SFN[i];
|
||||
}
|
||||
buff[0x0b] = 0x20; // ATTR = Archive
|
||||
// Ignore creation data/time, etc.
|
||||
buff[0x1a] = 0x03; // Starting cluster 3
|
||||
File f = LittleFS.open(_localFile, "r");
|
||||
int size = f.size();
|
||||
f.close();
|
||||
buff[0x1c] = size & 255;
|
||||
buff[0x1d] = (size >> 8) & 255;
|
||||
buff[0x1e] = (size >> 16) & 255; // 16MB or smaller
|
||||
}
|
||||
|
||||
void SingleFileDrive::fatSector(char fat[512]) {
|
||||
memset(fat, 0, 512);
|
||||
fat[0x00] = 0xff;
|
||||
fat[0x01] = 0xf8;
|
||||
fat[0x02] = 0xff;
|
||||
fat[0x03] = 0xff;
|
||||
int cluster = 3;
|
||||
File f = LittleFS.open(_localFile, "r");
|
||||
int size = f.size();
|
||||
f.close();
|
||||
while (size > 65536) {
|
||||
fat[cluster * 2] = (cluster + 1) & 0xff;
|
||||
fat[cluster * 2 + 1] = ((cluster + 1) >> 8) & 0xff;
|
||||
cluster++;
|
||||
size -= 65536;
|
||||
}
|
||||
fat[cluster * 2] = 0xff;
|
||||
fat[cluster * 2 + 1] = 0xff;
|
||||
}
|
||||
|
||||
// Invoked to determine max LUN
|
||||
extern "C" uint8_t tud_msc_get_maxlun_cb(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_INQUIRY
|
||||
// Application fill vendor id, product id and revision with string up to 8, 16, 4 characters respectively
|
||||
extern "C" void tud_msc_inquiry_cb(uint8_t lun, uint8_t vendor_id[8], uint8_t product_id[16], uint8_t product_rev[4]) {
|
||||
(void) lun;
|
||||
|
||||
const char vid[] = "PicoDisk";
|
||||
const char pid[] = "Mass Storage";
|
||||
const char rev[] = "1.0";
|
||||
|
||||
memcpy(vendor_id, vid, strlen(vid));
|
||||
memcpy(product_id, pid, strlen(pid));
|
||||
memcpy(product_rev, rev, strlen(rev));
|
||||
}
|
||||
|
||||
bool SingleFileDrive::testUnitReady() {
|
||||
return _started;
|
||||
}
|
||||
|
||||
// Invoked when received Test Unit Ready command.
|
||||
// return true allowing host to read/write this LUN e.g SD card inserted
|
||||
extern "C" bool tud_msc_test_unit_ready_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
|
||||
return singleFileDrive.testUnitReady();
|
||||
}
|
||||
|
||||
// Invoked when received SCSI_CMD_READ_CAPACITY_10 and SCSI_CMD_READ_FORMAT_CAPACITY to determine the disk size
|
||||
// Application update block count and block size
|
||||
extern "C" void tud_msc_capacity_cb(uint8_t lun, uint32_t* block_count, uint16_t* block_size) {
|
||||
(void) lun;
|
||||
*block_count = _hddsects;
|
||||
*block_size = 512;
|
||||
}
|
||||
|
||||
|
||||
// Callback invoked when received READ10 command.
|
||||
// Copy disk's data to buffer (up to bufsize) and return number of copied bytes.
|
||||
extern "C" int32_t tud_msc_read10_cb(uint8_t lun, uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
return singleFileDrive.read10(lba, offset, buffer, bufsize);
|
||||
}
|
||||
|
||||
int32_t SingleFileDrive::read10(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize) {
|
||||
if (!_started || (lba >= _hddsects)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t toread = bufsize;
|
||||
char buff[512];
|
||||
uint8_t *curbuff = (uint8_t *)buffer;
|
||||
|
||||
while (bufsize > 0) {
|
||||
if (lba == 0) {
|
||||
bootSector(buff);
|
||||
} else if ((lba == 128) || (lba == 256)) {
|
||||
fatSector(buff);
|
||||
} else if (lba == 384) {
|
||||
directorySector(buff);
|
||||
} else if (lba >= 640) {
|
||||
File f = LittleFS.open(_localFile, "r");
|
||||
f.seek((lba - 640) * 512);
|
||||
f.read((uint8_t*)buff, 512);
|
||||
f.close();
|
||||
} else {
|
||||
memset(buff, 0, sizeof(buff));
|
||||
}
|
||||
|
||||
uint32_t cplen = 512 - offset;
|
||||
if (bufsize < cplen) {
|
||||
cplen = bufsize;
|
||||
}
|
||||
memcpy(curbuff, buff + offset, cplen);
|
||||
curbuff += cplen;
|
||||
offset = 0;
|
||||
lba++;
|
||||
bufsize -= cplen;
|
||||
}
|
||||
|
||||
return toread;
|
||||
}
|
||||
|
||||
extern "C" bool tud_msc_is_writable_cb(uint8_t lun) {
|
||||
(void) lun;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
// Callback invoked when received WRITE10 command.
|
||||
// Process data in buffer to disk's storage and return number of written bytes
|
||||
extern "C" int32_t tud_msc_write10_cb(uint8_t lun, uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
(void) lun;
|
||||
return singleFileDrive.write10(lba, offset, buffer, bufsize);
|
||||
}
|
||||
|
||||
int32_t SingleFileDrive::write10(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize) {
|
||||
if (!_started || (lba >= _hddsects)) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint32_t addr = lba * 512 + offset;
|
||||
uint32_t hotspot = 384 * 512 + 0x20;
|
||||
if ((addr > hotspot) || (addr + bufsize < hotspot)) {
|
||||
// Did not try and erase the file entry, ignore
|
||||
return bufsize;
|
||||
}
|
||||
int off = hotspot - addr;
|
||||
uint8_t *ptr = (uint8_t *)buffer;
|
||||
ptr += off;
|
||||
if (*ptr == 0xe5) {
|
||||
if (_cbDelete) {
|
||||
_cbDelete(_cbDeleteData);
|
||||
}
|
||||
}
|
||||
|
||||
return bufsize;
|
||||
}
|
||||
|
||||
extern "C" bool tud_msc_set_sense(uint8_t lun, uint8_t sense_key, uint8_t add_sense_code, uint8_t add_sense_qualifier);
|
||||
|
||||
// Callback invoked when received an SCSI command not in built-in list below
|
||||
// - READ_CAPACITY10, READ_FORMAT_CAPACITY, INQUIRY, MODE_SENSE6, REQUEST_SENSE
|
||||
// - READ10 and WRITE10 has their own callbacks
|
||||
extern "C" int32_t tud_msc_scsi_cb(uint8_t lun, uint8_t const scsi_cmd[16], void* buffer, uint16_t bufsize) {
|
||||
const int SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL = 0x1E;
|
||||
const int SCSI_CMD_START_STOP_UNIT = 0x1B;
|
||||
const int SCSI_SENSE_ILLEGAL_REQUEST = 0x05;
|
||||
|
||||
void const* response = NULL;
|
||||
int32_t resplen = 0;
|
||||
|
||||
// most scsi handled is input
|
||||
bool in_xfer = true;
|
||||
scsi_start_stop_unit_t const * start_stop = (scsi_start_stop_unit_t const *) scsi_cmd;
|
||||
switch (scsi_cmd[0]) {
|
||||
case SCSI_CMD_PREVENT_ALLOW_MEDIUM_REMOVAL:
|
||||
// Host is about to read/write etc ... better not to disconnect disk
|
||||
if (scsi_cmd[4] & 1) {
|
||||
singleFileDrive.plug();
|
||||
}
|
||||
resplen = 0;
|
||||
break;
|
||||
case SCSI_CMD_START_STOP_UNIT:
|
||||
// Host try to eject/safe remove/poweroff us. We could safely disconnect with disk storage, or go into lower power
|
||||
if (!start_stop->start && start_stop->load_eject) {
|
||||
singleFileDrive.unplug();
|
||||
} else if (start_stop->start && start_stop->load_eject) {
|
||||
singleFileDrive.plug();
|
||||
}
|
||||
resplen = 0;
|
||||
break;
|
||||
default:
|
||||
// Set Sense = Invalid Command Operation
|
||||
tud_msc_set_sense(lun, SCSI_SENSE_ILLEGAL_REQUEST, 0x20, 0x00);
|
||||
// negative means error -> tinyusb could stall and/or response with failed status
|
||||
resplen = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
// return resplen must not larger than bufsize
|
||||
if (resplen > bufsize) {
|
||||
resplen = bufsize;
|
||||
}
|
||||
|
||||
if (response && (resplen > 0)) {
|
||||
if (in_xfer) {
|
||||
memcpy(buffer, response, resplen);
|
||||
} else {
|
||||
// SCSI output
|
||||
}
|
||||
}
|
||||
|
||||
return resplen;
|
||||
}
|
||||
|
||||
void SingleFileDrive::plug() {
|
||||
if (_started && _cbPlug) {
|
||||
_cbPlug(_cbPlugData);
|
||||
}
|
||||
}
|
||||
|
||||
void SingleFileDrive::unplug() {
|
||||
if (_started && _cbUnplug) {
|
||||
_cbUnplug(_cbUnplugData);
|
||||
}
|
||||
}
|
||||
|
||||
// Callback invoked on start/stop
|
||||
extern "C" bool tud_msc_start_stop_cb(uint8_t lun, uint8_t power_condition, bool start, bool load_eject) {
|
||||
(void) lun;
|
||||
(void) power_condition;
|
||||
if (start && load_eject) {
|
||||
singleFileDrive.plug();
|
||||
} else if (!start && load_eject) {
|
||||
singleFileDrive.unplug();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
SingleFileDrive - Emulates a USB stick for easy data transfer
|
||||
Copyright (c) 2022 Earle F. Philhower, III. All rights reserved.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Lesser General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2.1 of the License, or (at your option) any later version.
|
||||
|
||||
This library is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
Lesser General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Lesser General Public
|
||||
License along with this library; if not, write to the Free Software
|
||||
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <Arduino.h>
|
||||
|
||||
class SingleFileDrive {
|
||||
public:
|
||||
SingleFileDrive();
|
||||
~SingleFileDrive();
|
||||
|
||||
bool begin(const char *localFile, const char *dosFile);
|
||||
void end();
|
||||
|
||||
void onDelete(void (*cb)(uint32_t), uint32_t cbData = 0);
|
||||
void onPlug(void (*cb)(uint32_t), uint32_t cbData = 0);
|
||||
void onUnplug(void (*cb)(uint32_t), uint32_t cbData = 0);
|
||||
|
||||
// Only for internal TinyUSB callback use
|
||||
bool testUnitReady();
|
||||
int32_t read10(uint32_t lba, uint32_t offset, void* buffer, uint32_t bufsize);
|
||||
int32_t write10(uint32_t lba, uint32_t offset, uint8_t* buffer, uint32_t bufsize);
|
||||
void plug();;
|
||||
void unplug();
|
||||
|
||||
private:
|
||||
void bootSector(char buff[512]);
|
||||
void directorySector(char buff[512]);
|
||||
void fatSector(char buff[512]);
|
||||
|
||||
private:
|
||||
bool _started = false;
|
||||
char *_localFile = nullptr;
|
||||
char *_dosFile = nullptr;
|
||||
|
||||
void (*_cbDelete)(uint32_t) = nullptr;
|
||||
uint32_t _cbDeleteData = 0;
|
||||
|
||||
void (*_cbPlug)(uint32_t) = nullptr;
|
||||
uint32_t _cbPlugData = 0;
|
||||
|
||||
void (*_cbUnplug)(uint32_t) = nullptr;
|
||||
uint32_t _cbUnplugData = 0;
|
||||
};
|
||||
|
||||
extern SingleFileDrive singleFileDrive;
|
||||
@@ -57,7 +57,8 @@ beginEnterprise KEYWORD2
|
||||
setHostname KEYWORD2
|
||||
end KEYWORD2
|
||||
getTime KEYWORD2
|
||||
lowPowerMode KEYWORD2
|
||||
aggressiveLowPowerMode KEYWORD2
|
||||
defaultLowPowerMode KEYWORD2
|
||||
noLowPowerMode KEYWORD2
|
||||
ping KEYWORD2
|
||||
beginMulticast KEYWORD2
|
||||
|
||||
@@ -99,6 +99,7 @@ int WiFiClass::begin(const char* ssid, const char *passphrase) {
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
noLowPowerMode();
|
||||
// Enable CYW43 event debugging (make sure Debug Port is set)
|
||||
//cyw43_state.trace_flags = 0xffff;
|
||||
while (!_calledESP && ((millis() - start < (uint32_t)2 * _timeout)) && !connected()) {
|
||||
@@ -134,6 +135,7 @@ uint8_t WiFiClass::beginAP(const char *ssid, const char* passphrase) {
|
||||
if (!_wifi.begin()) {
|
||||
return WL_IDLE_STATUS;
|
||||
}
|
||||
noLowPowerMode();
|
||||
IPAddress gw = _wifi.gatewayIP();
|
||||
if (!gw.isSet()) {
|
||||
gw = IPAddress(192, 168, 42, 1);
|
||||
@@ -565,14 +567,19 @@ unsigned long WiFiClass::getTime() {
|
||||
return millis();
|
||||
}
|
||||
|
||||
void WiFiClass::lowPowerMode() {
|
||||
void WiFiClass::aggressiveLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, CYW43_AGGRESSIVE_PM);
|
||||
}
|
||||
|
||||
void WiFiClass::noLowPowerMode() {
|
||||
void WiFiClass::defaultLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, CYW43_DEFAULT_PM);
|
||||
}
|
||||
|
||||
// The difference between the default CYW43_DEFAULT_PM (0xA11142) and not low power (0xA11140) is that it changed from "Powersave mode on specified interface with High throughput" to "No Powersave mode". All other parameters stayed the same.
|
||||
void WiFiClass::noLowPowerMode() {
|
||||
cyw43_wifi_pm(&cyw43_state, 0xA11140);
|
||||
}
|
||||
|
||||
int WiFiClass::ping(const char* hostname, uint8_t ttl) {
|
||||
IPAddress ip;
|
||||
if (!hostByName(hostname, ip)) {
|
||||
|
||||
@@ -368,7 +368,8 @@ public:
|
||||
|
||||
unsigned long getTime();
|
||||
|
||||
void lowPowerMode();
|
||||
void aggressiveLowPowerMode();
|
||||
void defaultLowPowerMode();
|
||||
void noLowPowerMode();
|
||||
|
||||
int ping(const char* hostname, uint8_t ttl = 128);
|
||||
@@ -381,7 +382,7 @@ public:
|
||||
void feedWatchdog();
|
||||
|
||||
private:
|
||||
int _timeout = 10000;
|
||||
int _timeout = 15000;
|
||||
String _ssid;
|
||||
String _password;
|
||||
bool _wifiHWInitted = false;
|
||||
|
||||
@@ -374,12 +374,22 @@ public:
|
||||
return 0;
|
||||
}
|
||||
size_t sent = 0;
|
||||
uint8_t buff[256];
|
||||
while (stream.available()) {
|
||||
char b;
|
||||
b = stream.read();
|
||||
if (write(&b, 1)) {
|
||||
sent ++;
|
||||
// Stream only lets you read 1 byte at a time, so buffer in local copy
|
||||
size_t i;
|
||||
for (i = 0; (i < sizeof(buff)) && stream.available(); i++) {
|
||||
buff[i] = stream.read();
|
||||
}
|
||||
if (i) {
|
||||
// Send as a single packet
|
||||
int len = write((const char *)buff, i);
|
||||
sent += len;
|
||||
if (len != (int)i) {
|
||||
break; // Write error...
|
||||
}
|
||||
} else {
|
||||
// Out of data...
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "framework-arduinopico",
|
||||
"version": "1.20604.0",
|
||||
"version": "1.20605.0",
|
||||
"description": "Arduino Wiring-based Framework (RPi Pico RP2040)",
|
||||
"keywords": [
|
||||
"framework",
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@
|
||||
# https://github.com/arduino/Arduino/wiki/Arduino-IDE-1.5---3rd-party-Hardware-specification
|
||||
|
||||
name=Raspberry Pi RP2040 Boards
|
||||
version=2.6.4
|
||||
version=2.6.5
|
||||
|
||||
runtime.tools.pqt-gcc.path={runtime.platform.path}/system/arm-none-eabi
|
||||
runtime.tools.pqt-python3.path={runtime.platform.path}/system/python3
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
#!/bin/bash
|
||||
|
||||
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S \
|
||||
for dir in ./cores/rp2040 ./libraries/EEPROM ./libraries/I2S ./libraries/SingleFileDrive \
|
||||
./libraries/LittleFS/src ./libraries/LittleFS/examples \
|
||||
./libraries/rp2040 ./libraries/SD ./libraries/ESP8266SdFat \
|
||||
./libraries/Servo ./libraries/SPI ./libraries/Wire ./libraries/PDM \
|
||||
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1021"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_LCD_0_96 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1021"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "waveshare_rp2040_lcd_0_96"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RP2040 LCD 0.96",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1039"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_LCD_1_28 -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1039"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "waveshare_rp2040_lcd_1_28"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RP2040 LCD 1.28",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 2097152,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q16jvxq_4_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x103A"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_ONE -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x103A"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "waveshare_rp2040_one"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RP2040 One",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1020"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_PLUS -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1020"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "waveshare_rp2040_plus_16mb"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RP2040 Plus 16MB",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 16777216,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
{
|
||||
"build": {
|
||||
"arduino": {
|
||||
"earlephilhower": {
|
||||
"boot2_source": "boot2_w25q080_2_padded_checksum.S",
|
||||
"usb_vid": "0x2E8A",
|
||||
"usb_pid": "0x1020"
|
||||
}
|
||||
},
|
||||
"core": "earlephilhower",
|
||||
"cpu": "cortex-m0plus",
|
||||
"extra_flags": "-D ARDUINO_WAVESHARE_RP2040_PLUS -DARDUINO_ARCH_RP2040 -DUSBD_MAX_POWER_MA=500",
|
||||
"f_cpu": "133000000L",
|
||||
"hwids": [
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x00C0"
|
||||
],
|
||||
[
|
||||
"0x2E8A",
|
||||
"0x1020"
|
||||
]
|
||||
],
|
||||
"mcu": "rp2040",
|
||||
"variant": "waveshare_rp2040_plus_4mb"
|
||||
},
|
||||
"debug": {
|
||||
"jlink_device": "RP2040_M0_0",
|
||||
"openocd_target": "rp2040.cfg",
|
||||
"svd_path": "rp2040.svd"
|
||||
},
|
||||
"frameworks": [
|
||||
"arduino"
|
||||
],
|
||||
"name": "RP2040 Plus 4MB",
|
||||
"upload": {
|
||||
"maximum_ram_size": 270336,
|
||||
"maximum_size": 4194304,
|
||||
"require_upload_port": true,
|
||||
"native_usb": true,
|
||||
"use_1200bps_touch": true,
|
||||
"wait_for_upload_port": false,
|
||||
"protocol": "picotool",
|
||||
"protocols": [
|
||||
"cmsis-dap",
|
||||
"jlink",
|
||||
"raspberrypi-swd",
|
||||
"picotool",
|
||||
"picoprobe"
|
||||
]
|
||||
},
|
||||
"url": "https://www.raspberrypi.org/products/raspberry-pi-pico/",
|
||||
"vendor": "Waveshare"
|
||||
}
|
||||
@@ -72,15 +72,14 @@
|
||||
//------------- CLASS -------------//
|
||||
#define CFG_TUD_HID (2)
|
||||
#define CFG_TUD_CDC (1)
|
||||
#define CFG_TUD_MSC (0)
|
||||
#define CFG_TUD_MSC (1)
|
||||
#define CFG_TUD_MIDI (0)
|
||||
#define CFG_TUD_VENDOR (0)
|
||||
|
||||
#define CFG_TUD_CDC_RX_BUFSIZE (256)
|
||||
#define CFG_TUD_CDC_TX_BUFSIZE (256)
|
||||
|
||||
#define CFG_TUD_MIDI_RX_BUFSIZE (64)
|
||||
#define CFG_TUD_MIDI_TX_BUFSIZE (64)
|
||||
#define CFG_TUD_MSC_EP_BUFSIZE (64)
|
||||
|
||||
// HID buffer size Should be sufficient to hold ID (if any) + Data
|
||||
#define CFG_TUD_HID_EP_BUFSIZE (64)
|
||||
|
||||
@@ -54,6 +54,7 @@ def scanner():
|
||||
scannerGo = True
|
||||
|
||||
def main():
|
||||
global scannerGo
|
||||
while True:
|
||||
cmdline = input()
|
||||
cmd = cmdline.split()[0]
|
||||
|
||||
Reference in New Issue
Block a user