-
-
Save joric/d04f43a42ad788fde368b36181be3977 to your computer and use it in GitHub Desktop.
msc.ino
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// see https://github.com/joric/nrfmicro/wiki/Bluemicro | |
// use ramdisk.h from msc arduino sample | |
#define GPIO(port, pin) ((port << 5) | pin) | |
#define RGB_ENABLED 0 | |
#define MSC_ENABLED 1 | |
#define ADAFRUIT_GFX_ENABLED 1 | |
#include "Adafruit_TinyUSB.h" | |
#include <Adafruit_LittleFS.h> | |
#include <InternalFileSystem.h> | |
using namespace Adafruit_LittleFS_Namespace; | |
#define FILENAME "/image.img" | |
#define CONTENTS "Adafruit Little File System test file contents" | |
File file(InternalFS); | |
#define LED_PIN GPIO(1,10) | |
#define RGB_PIN GPIO(0,6) | |
#define POWER_PIN GPIO(1,9) | |
#define PROG_PIN GPIO(0,5) | |
#define STAT_PIN GPIO(0,7) | |
#if (ADAFRUIT_GFX_ENABLED) | |
#include <Wire.h> | |
TwoWire nRFWire(NRF_TWIM0, NRF_TWIS0, SPIM0_SPIS0_TWIM0_TWIS0_SPI0_TWI0_IRQn, 15, 17); | |
#include <Adafruit_GFX.h> | |
#include <Adafruit_SSD1306.h> | |
#define OLED_I2C_ADDR 0x3C | |
#define OLED_WIDTH 128 | |
#define OLED_HEIGHT 32 | |
#define OLED_RESET -1 | |
Adafruit_SSD1306 display(OLED_WIDTH, OLED_HEIGHT, &Wire, OLED_RESET); | |
#endif | |
// 8KB is the smallest size that windows allow to mount | |
#define DISK_BLOCK_NUM 16 | |
#define DISK_BLOCK_SIZE 512 | |
#include "ramdisk.h" | |
bool dirty = false; | |
// HID report descriptor using TinyUSB's template | |
// Generic In Out with 64 bytes report (max) | |
uint8_t const desc_hid_report[] = | |
{ | |
TUD_HID_REPORT_DESC_GENERIC_INOUT(64) | |
}; | |
Adafruit_USBD_HID usb_hid; | |
Adafruit_USBD_MSC usb_msc; | |
#if (RGB_ENABLED) | |
#include <Adafruit_NeoPixel.h> | |
#define NUMPIXELS 6 | |
#define DELAYVAL 50 | |
Adafruit_NeoPixel pixels(NUMPIXELS, RGB_PIN, NEO_GRB + NEO_KHZ800); | |
#endif | |
const int LINES = 4; | |
int lnum = 0; | |
String lbuf[LINES]; | |
void update(char * s) { | |
String line = String(lnum) + String(".") + String(s); | |
Serial.println(line); | |
#if (ADAFRUIT_GFX_ENABLED) | |
display.clearDisplay(); | |
lbuf[lnum%LINES] = line; | |
int ofs = lnum<LINES ? 0 : (lnum + 1) % LINES; | |
for (int i=0; i<LINES; i++) { | |
display.setCursor(0, i*8); | |
display.print(lbuf[ (ofs+i) % LINES ].substring(0,21)); | |
} | |
display.display(); | |
#endif | |
lnum++; | |
} | |
// the setup function runs once when you press reset or power the board | |
void setup() | |
{ | |
#if (ADAFRUIT_GFX_ENABLED) | |
Wire = nRFWire; | |
display.begin(SSD1306_SWITCHCAPVCC, 0x3C); | |
display.setTextSize(0); | |
display.setTextColor(WHITE); | |
update("USB Mass Class"); | |
#endif | |
// Initialize Internal File System | |
InternalFS.begin(); | |
bool exists = false; | |
file.open(FILENAME, FILE_O_READ); | |
if ( file ) { | |
exists = true; | |
for (int i = 0; i < DISK_BLOCK_NUM; i++) { | |
file.read(&msc_disk[i], DISK_BLOCK_SIZE); | |
} | |
file.close(); | |
} | |
if (!exists) | |
InternalFS.format(); | |
#if (MSC_ENABLED) | |
usb_msc.setID("Adafruit", "Mass Storage", "1.0"); | |
// Set disk size | |
usb_msc.setCapacity(DISK_BLOCK_NUM, DISK_BLOCK_SIZE); | |
// Set callback | |
usb_msc.setReadWriteCallback(msc_read_cb, msc_write_cb, msc_flush_cb); | |
// Set Lun ready (RAM disk is always ready) | |
usb_msc.setUnitReady(true); | |
usb_msc.begin(); | |
usb_hid.enableOutEndpoint(true); | |
usb_hid.setPollInterval(2); | |
usb_hid.setReportDescriptor(desc_hid_report, sizeof(desc_hid_report)); | |
usb_hid.setReportCallback(get_report_callback, set_report_callback); | |
usb_hid.begin(); | |
#endif | |
Serial.begin(115200); | |
Serial.println("Waiting for USBDevice mount"); | |
// wait until device mounted | |
while ( !USBDevice.mounted() ) delay(1); | |
delay(1000); | |
Serial.println("Adafruit TinyUSB HID Generic In Out example"); | |
if (exists) { | |
update("FILE EXISTS!"); | |
} | |
char buf[128]; | |
sprintf(buf, "%s", msc_disk[3]); | |
update(buf); | |
// this somehow messes msc up, should be run after msc | |
pinMode(LED_PIN, OUTPUT); for (int i = 0; i < 4; i++) { | |
digitalWrite(LED_PIN, i % 2 ? LOW : HIGH ); | |
delay(200); | |
} | |
// enable charger | |
//pinMode(STAT_PIN, OUTPUT); digitalWrite(STAT_PIN, 0); pinMode(PROG_PIN, OUTPUT); digitalWrite(PROG_PIN, 0); | |
pinMode(POWER_PIN, OUTPUT); | |
digitalWrite(POWER_PIN, 0); | |
#if (RGB_ENABLED) | |
pixels.begin(); | |
pixels.clear(); | |
for (int j = 0; j < 4; j++) | |
for (int i = 0; i < NUMPIXELS; i++) { // For each pixel... | |
pixels.setPixelColor(i, pixels.Color(0, 0, ((j + 1) % 2) * 32)); | |
pixels.show(); // Send the updated pixel colors to the hardware. | |
delay(DELAYVAL); // Pause before next pass through loop | |
} | |
#endif | |
} | |
// only flush in 1-sec cycles | |
int counter = 0; | |
void loop() | |
{ | |
delay(1); | |
if (counter>=1000 && dirty) { | |
counter = 0; | |
if ( file.open(FILENAME, FILE_O_WRITE) ) | |
{ | |
file.seek(0); | |
for (int i = 0; i < DISK_BLOCK_NUM; i++) { | |
file.write(msc_disk[i], DISK_BLOCK_SIZE); | |
} | |
file.close(); | |
update("updated file"); | |
} else | |
{ | |
update("can't update"); | |
} | |
char buf[128]; | |
sprintf(buf, "%s", msc_disk[3]); | |
update(buf); | |
dirty = false; | |
} | |
counter++; | |
} | |
// Invoked when received GET_REPORT control request | |
// Application must fill buffer report's content and return its length. | |
// Return zero will cause the stack to STALL request | |
uint16_t get_report_callback (uint8_t report_id, hid_report_type_t report_type, uint8_t* buffer, uint16_t reqlen) | |
{ | |
// not used in this example | |
return 0; | |
} | |
// Invoked when received SET_REPORT control request or | |
// received data on OUT endpoint ( Report ID = 0, Type = 0 ) | |
void set_report_callback(uint8_t report_id, hid_report_type_t report_type, uint8_t const* buffer, uint16_t bufsize) | |
{ | |
// This example doesn't use multiple report and report ID | |
(void) report_id; | |
(void) report_type; | |
//char buf[128]; | |
//sprintf(buf, "id: %d type: %d", report_id, report_type); | |
//update(buf); | |
// echo back anything we received from host | |
usb_hid.sendReport(0, buffer, bufsize); | |
} | |
// Callback invoked when received READ10 command. | |
// Copy disk's data to buffer (up to bufsize) and | |
// return number of copied bytes (must be multiple of block size) | |
int32_t msc_read_cb (uint32_t lba, void* buffer, uint32_t bufsize) | |
{ | |
uint8_t const* addr = msc_disk[lba]; | |
memcpy(buffer, addr, bufsize); | |
//update("msc_read_cb"); | |
return bufsize; | |
} | |
// Callback invoked when received WRITE10 command. | |
// Process data in buffer to disk's storage and | |
// return number of written bytes (must be multiple of block size) | |
int32_t msc_write_cb (uint32_t lba, uint8_t* buffer, uint32_t bufsize) | |
{ | |
uint8_t* addr = msc_disk[lba]; | |
memcpy(addr, buffer, bufsize); | |
//update("msc_write_cb"); | |
dirty = true; | |
return bufsize; | |
} | |
// Callback invoked when WRITE10 command is completed (status received and accepted by host). | |
// used to flush any pending cache. | |
void msc_flush_cb (void) | |
{ | |
//update("msc_flush_cb"); | |
// nothing to do | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment