Sound for model railroading scale 1/32

Status
Not open for further replies.
Thanks defragster for the reply......but I am still clutching at straws in the background....????
I normally I think ? keep my Tools, USB type set to USB HID......and this seems to always work....but for CopyFromSerial it needs to be USB Type Serial...and Copy From Serial works......but the to play the file I load the FlashRawPlayer and USB type was still set to Serial......so I put it to USB HID and the while(!Serial); bit works now and the files play without opening the monitor. I tried USB HID with CopyFromSerial and Python does not open COM5......So........I probably had USB HID when I used CopyfromSD and had no problems. The monitor still printed the file name to the monitor with either setting....

So USB Serial for CopyFromSerial and USB HID for the Player etc.......

Maybe defragster you would have a technical answer as to why.....thanks....
 
IWith the setting indicated in last post, it plays OK when Powered by USB port of the PC but does not play if plugged into a USB power bank that is fully charged and I have tried on several other Teensy devices to make sure the power pack is working and all work. If I set the USB type to "No USB" I can still upload the player sketch to teensy with the "No USB" setting and it reboots and plays normal and OK. And it plays when Powered by the USB Power bank. I have never come across this before and I have had lots of Teensys and programmed all sorts of sketches. So what has changed in the program or settings...???
What is the meaning of USB type in tools settings.....??
What does "No USB" mean if I can still program it with a USB port....??
all my other teensy devices work from a power bank and were definitely not setup as "No USB"...?
 
programmed as NO_USB should only work with a BUTTON push to program?

USB battery bank will work - with programmed delay using the provided && millis() cod.

My use is generally USB_Type Serial - - HID usage was rare - and connected at those times. And usually with the millis() timeout to prevent it hanging when not connected.
 
Yes, No USB means Press Button to upload sketch....Ok thats fine....I never gave all this much thought in the past as it never gave me a problem, the only time I think I ever changed these settings was when doing MIDI sketches OR making teensy work as a USBtoSerial port for talking serial to something.
So I went back to basics, closed down Arduino IDE, closed down computer, rebooted, run CCleaner, rebooted computer, no teensy plugged in, checked system devices, shows COM1 only and no HID devices......All OK and normal.

Got a brand new Teensy3.2 probably bought about 6 mths ago never used still in packet, plugged it into USB port on PC, PCsays Found new hardware etc etc, new HID device found, Device now ready, or words similar....all appears normal and OK.

Opened system devices, what now listed are...2x HID compliant device and 2x USB Human Interface Device and still COM1 only listed.......all Normal and OK.....and preinstalled Blink sketch is flashing the LEDs.

Opened the Arduino IDE, it opens at the last sketch used which was FlashRawPlayer, Did not do anything with it, clicked file new, opened the blank default that opens with new, closed the FlashRawPlayer sketch, all normal, now looking at the new blank sketch, clicked menu tools, list shows USB type HID and Port lists COM1 but not ticked.
And I think all this is normal and I would not have changed these settings so thats why I assumed I always used HID in the past......???

It is possible I have uploaded sketches with USB set to Serial but Serial not actually used or needed, OR maybe they have a Serial(begin) with a few Serial.print lines but wouldn't have any while(!Serial) waiting to make sure it was there......so all my devices work plugged into PC or on Power Bank or on just 2 wires.

some of these checks are ok when writing or debugging sketches but maybe not for the final running program....????

When I plug in my teensy with the player sketch set to Serial, system devices immediately shows Teensy COM5 listed and Tools says USB type Serial and Port COM5 ticked.

The sketch works OK without the while(!Serial) check and works with Defragster mod as well....but if I read it correctly it waits for Serial and if it doesn't happen go on anyway.??....the Serial.print lines are working so serial must be working OR is it that Serial only starts working when we open the monitor window....we need the monitor open anyway to see what it prints.....so if it Listfiles sketck...no problem we are expecting text so we open the monitor.....but if Flash Player we are expecting sound so don't bother to open the monitor.....????
 
It seems your post 79 dialog is normal and good. To support USB the Teensy needs to be running USB code, unlike UNO it doesn't have a USB hardware interface chip that survives reboot and is always present.

When any USB stack is loaded in Teensy sketch - and active without fault from BAD code - it can respond to the Computer request to upload Program and button press not required. The Button press is when USB NONE { as shipped } or if the loaded sketch takes USB stack offline.

When there is a while (!Serial){} that will wait forever for a USB monitor to connect, adding some timeout like &&millis() allows that to be conditional as desired.

Without some wait - early prints in setup() or loop() can be lost as Teensy may be online and ready to run before the computer software can be connected.

Using while (!Serial && millis()<500 ); would result in a 100 ms ( 150 ms on TD 1.42 ) wait at most and USB would generally be present when desired for immediate use, and minimal delay when not connected. Also there is typically some buffering in USB code if minimal prints are sent before a Monitor is connected.
 
OK, thanks for that, it has given me a better understanding as to what happens for the different settings.

I wonder what is happening when I try to copy a 1.6 MB or a 700 KB to spiflash using Copyfromserial.....My PC crashes and restarts.....I can copy them using CopyfromSD...no problems.......I can copy small files with CopyFromSerial OK and it works as discussed in the earlier posts.

What is the reaction between Python and the Teensy serial port and SPI......With Teensy setup as a Serial port is it acting like a terminal on COM5 and then Python opens COM5 and sends data to Teensy over the serial port and then Teensy sends the data to spiflash over SPI.....??
What bit of this is likely to be the problem....????
 
Not having read anything other than what led to what I posted ... speculation ...

Could be comingling the SPI writes and COM5 transfers? They likely don't run at the same speed - and the overhead of incoming USB may be interfering with the SPI writes?

Without handshaking on the USB to control Python output the incoming data may be faster than the data dumping to the SPI?

Quick test might be to have the Python send usable/manageable chunk - some number of flash pages that fit in Teensy RAM - then pause Python until the Teensy asks for more?

Not sure if that is already done in any fashion - or is easily done ...

<edit> just re-read p#81 - I've not used these 'copyfrom...' things - it is the PC that crashes when the Teensy spews OUT data? SPI read will run much faster than SD - the receiver code on the PC would have to be efficient to keep up with Teensy data rate. Take what is written above and reverse it ... have the Teensy send at a slower rate - like that from SD - send in usable blocks and pause ?
 
The CopyfromSerial sketch I am using is posted on post #71. Basically it is loaded and running on Teensy. The audio.raw files to be copied are on PC in same folder as the Python script....which is the "rawfile-uploader.py" found in extras folder in the SerialFlash teensy library.

PC is connected to teensy via the USB/Serial port and spiflash is connected to Teensy via SPI port.

Direction of Data transfer is from PC via Python to USB/Serial and on to Teensy and from Teensy sketch via SPI port to spiFlash. So from your last post SPI runs faster but would be fed by the slower Serial data..???? so would there be that type of problem...??

Python apparantly buffers the data on PC waiting on Teensy saying it is ready, The crash seems to happen as soon as transfer seems to start, I thought maybe a conflict when Teensy is trying to talk to the port when Python has it open as well...???.......Thanks for your consideration.....
 
Have you try on another PC?
Because, we call some Windows ressources and I am not sure of the compatibility with certain Python procedures.
I thought that the PC USB (seen from Windows) link protocols were differents when :
1) uploading with Python rawfile-uploader.py
2) uploading SPI Flash with CopyFromSerial
That's why it was necessary to unplug /plug in order to re-initialize the protocol parameters.
 
Okay so that the <edit> was the wrong read ... indeed SPI write should be fast - though at 12 Mbit USB won't be slow - and that incoming data won't be stopped unless speed is controlled by sender? The incoming data reception will be causing data buffering and interrupts to receive the data. Would not be surprising to have it affect the SPI interface at full speed.

If it works for small file - it is odd that it hangs so quickly on the start of a larger file without some error - or that the small file was buffered and done as the writes completed.
 
Yes, I think there is something about needing to unplug/plug in again. Although I have got small files copied without unplugging at all between loading and running the 2 sketches Copy and List. But some times the python cannot find the com5 port and if I unplug/plugin and run script before blinking LEDs it works.

I put a blank new sketch (just file new) on teensy, with USB serial and port Com5 (COM5 needed because Python cant open COM5 if it not plugged in and in System Devices) and then ran the cCMD line python script trying to copy the 700kb file....on the command screen it got as far as listing the file and then crashed.....????
PC just does not "Hang" it crashes completely and reboots PC.
I will pu Python on another Win10 laptop ad see what happens....and post back again.
 
Yes, that worked, I put Python 2.7 x86 version on Windows 10 64 bit laptop and pyserial 2.6 version as per earlier posts

I had put Python 2.6 64 bit version on but couldnt find pyserial2.6 for 64bit....googled alot of info saying there was problems with 64bit version but that x86 version of both worked OK on 64 bit.... so installed that.

I have the Arduino environment on an Windows XP so I still loaded the same sketches on XP and unplugged and plugged in Win10 and ran the Python Script from there starting it at the first double blink of the LEDS. then when LEDS out unplugged and back to XP to upload the Listfiles sketch...compiled it first with teensy unplugged the plugged in and press button right away before any LED flashing so files were not deleted.....Files listed OK.....Then uploaded the Player sketch and it played OK. a bit of extra noise an end of sound...need to check that out...???

A thing I hadnt noticed before the enumeration of the ports starts from 0 upwards.....so serial(4) is COM5....????? same on Win10 PC
>>> ser5 = serial.Serial(4)
>>> print ser5
Serial<id=0x1365bd0, open=True>(port='COM5', baudrate=9600, bytesize=8, parity='N', stopbits=1, timeout=None, xonxoff=False, rtscts=False, dsrdtr=False)
 
I copied 5 files from Serial....2 of size 2MB approx each and 3 other small files about 15 Kb each. All done listed on one command line. All copied OK, and played OK, except for a small about 2 ms glitch in one of the 2MB files. I don't see the glitch if I import this RAW file into Audacity so must be added during copying ...I then copied the same files again along with 1 aboy 700kb and another small one....The files listed OK but when played one of the large was just loud noise and one not picked up by player......I ran Erase all and then copyfromserial again and copied the 7 files about 4.8 MB again....all copied and played OK. I did the Arduino bit on the XP maching and the Python bit on the Win10 laptop. I did the same both times of copying.


Below this is the procedure I was following.......

1......CopyFromSerial sketch needs to be set USB/Serial when compiling/uploading so that when Teensy is plugged in to the Python PC it will appear as a USB/Serial COMMS device.

2. The Python PC maybe the same PC as the Arduino IDE so Teensy needs to be unplugged/pluggedin again to re-initialise the device and make it ready for Python.

3. The Python PC needs to have the COMMS port ready in System devices so that it will see/find it when the Script is started to run.

4. Compile the CopyFromSerial sketch in Arduino IDE with either ....

... Teensy Plugged in and Auto Upload to Teensy......

... OR Teensy Unplugged and wait until asked to Press Button....Plugin Teensy and Press button to upload.

... If "Reboot OK" ...let Teensy run until LED is solid on......Then unplug USB.


5. ... Open CMD Prompt Window for Python and type in command line...

... When ready to send Python command line ....Plugin Teensy and Hit Return to send command line as soon as
LEDs starts flashing....

6 ... Filenames will be listed on command window....when copying finished the LEDs go OFF.

7. ... Unplug Teensy. Do not plug in again while CopyFromSerial sketch is in Teensy or it will re-run
and erase the files just copied.

8. ... Open Arduino and load and compile the Listfiles sketch with Teensy USB unplugged.

9. ... When asked to Press Button.....Plugin Teensy and within a few seconds Press button to upload sketch.

10. ... Open IDE monitor to see list of files that were copied. Unplug/plugin to re-run the list.

11. ... Compile and upload the RawFlashPlayer sketch to hear the files or load any other sketch as normal.


It seems to be working....but not all that reliable....???
 
Last edited:
What is the best soundfile extension (easy to manage in sketch, no glitch, no stop when reading soundfiles)
to deal with Audio.h (for switching, for mixing, . . .) via Audio GUI tools ?

1) SOUNDFILE.RAW (direct from Audacity)
or
2) SOUNDFILE.TRW ( Audacity - 44000 Hz/16 bit) + (wav2trw -16)
 
For Binary files...RAW would be the most popular and Audacity would probably be the best editor/converter. With Audacity open/import various sound files and you can hear it and see its waveform and edit/convert and save/export it in a variety of formats......and then import what you have done and see/hear it again. Audacity gives a RAW binary file with no header.

SOX will convert a WAV to RAW but no visual...???.....a WAV binary with no header

Wav2Trw will convert it to TRW ....a binary file...actually a RAW file with TRW extension and a small header info.

I found sometimes there are Zeros at end of the TRW files and maybe the others as well at time which will give long gap between when playing
To play continuous loop the file need clean start and end whis is easier to do in Audacity

You can loop the sound file in Audacity and hear how it joins up...and edit the start and end to get best then export......the challenge will the to get it to loop as well in Teensy.

What type of sound file are you playing...??? long or short...or continuous sounding long playing sirens or whistles .....or intermittent sounds as in engine tick over or steam train puffing...
 
Last edited:
There are two kinds of soundfiles to play:
Type 1)
Basic soundfiles related to the engine (steam, electric or diesel) which depends on the speed (stop, start -> full speed), but also on the deceleration (soft braking, strong braking to stop). These files can last each last 1 minute.

Type 2)
Event sounfiles related to manual commands (whistle, horn, lift synchronized pantographs (with servos), coupling/ uncoupling (servo). These files can last 30 s each.
The total soundfiles could be 10 minutes.

Both types of soundfiles Type 1) and Type 2) can be played together (Type 1 + Type 2) --> eg :engine + whistle).
So I need to be able to mix these sounds.
 
I checked that my soundfile is in SPI Flash (ReadBenchmark).
But, with my sketch, I get only a very weak signal and it's not my soundfile (it's just a very weak tone).
It seems that Dac1 is opened but the soundfile is not read (soundfile is not sent to it?).
 
Are you using the TRW files......I found sometimes these seem to be generated OK but when copied an play just loud noise. Try generating and copying them again or try RAW ones. I dont know if problem is with generating or copy from serial. My version of the player on post#44 or #45 works.
Regards your previous post the engine running is a series of loud pulses and relatively quiet periods when you look at is waveform....if you listen it there is a repetive rhythm to it so about maybe 4 loud periods and cut it at the quiet periods in between maybe gives a file of about 1 second....it is only a few Kb....play this over and overand it plays like a continuous file no clicks. open another instance of the flashplayer and have it say playing a whistle controller by a button so the train driver can blow his whistle as he passes objects. put both sounds through a mixer and out DAC. that works.
 
I am using your file : "WHISTM1.TRW"
This file is in SPI Flash :
ReadBenchmark -->
All Files on SPI Flash chip:
WHISTM1.TRW = 14852 bytes
Read in = 7811
usbegin = 2233148
usend = 2240959
us, speed = 1901.42 kbytes/sec​

with following code :
Code:
#include <Audio.h>
#include <Wire.h>
#include <SPI.h>
#include <SD.h>
#include <SerialFlash.h>

#define FLASH_CHIP_SELECT 10
  
// GUItool: begin automatically generated code
AudioPlaySerialflashRaw  playFlashRaw1;  //xy=228,273
AudioOutputAnalog        dac1;           //xy=751,337
AudioConnection          patchCord1(playFlashRaw1, 0, dac1, 0);
// GUItool: end automatically generated code

void setup() {
    Serial.begin(9600);
    while (!Serial && millis()<500 );
    AudioMemory(50);

//************************************
//  Set up SPI Teensy without audio Card
  SPI.setMOSI(11); //7
  SPI.setMISO(12);
  SPI.setSCK(14);
//************************************
    delay(2000);
    if (!SerialFlash.begin(FLASH_CHIP_SELECT)) {
        while (1){
            Serial.println ("Cannot access SPI Flash chip");
            delay (1000);
        }
    }
}
void playFile(const char *filename)
{
  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(ff);

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();
  Serial.println(sz);
  Serial.println(pos);

  playFlashRaw1.play(filename);
  // Simply wait for the file to finish playing.
  while (playFlashRaw1.isPlaying()) {
   } 
}   
 
void loop() {
  playFile("WHISTM1.TRW");
  delay (1000);
}
 
WHISTM1.TRW was posted in post #38 and the WHISTM1.WAV file is there as well.....theyare in Zip file so need unzipped..... you could create your own copy of WHIST1M1.TRW using your own copy of Wav2Trw.
OR See can you import the unzipped WHISTM1.TRW to Audacity and does it play there 16bit 44100 mono.
OR open the WHISTM1.WAV in Audacity and export as RAW file and see if that plays........It is only a short whistle sound anyway.
If all plays in Audacity OK....make another copy to Serial spiflash and see if that plays

Have you a preference for using TRW files are they in common use in Model Railways sounds etc

I think you would be better using RAW and convert with either Audacity or SOX
 
I tried on many soundfiles : yours and mine.
I loaded them in SPI Flash (check with ReadBenchmark)
But I get no sound even with your files.
1) I wonder if there is an error in the code ?
2) how can I tune the volume or gain ?

Have you a preference for using TRW files are they in common use in Model Railways sounds etc

No, there is no standard.
 
This is the playfile bit of the code in post #94
While running the sketch, open the monitor and see if it is printing to the serial monitor
It should be printing "Playing file WHISTM1.RAW" and the numbers for its size and address in memory
and keep repeating that........if it is scrolling fast change the delay in loop to delay(10000).....in case it is all to "busy"


Code:
void playFile(const char *filename)
{
  SerialFlashFile ff = SerialFlash.open(filename);
  Serial.print("Playing file: ");
  Serial.println(ff);

  uint32_t sz = ff.size();
  uint32_t pos = ff.getFlashAddress();
  Serial.println(sz);
  Serial.println(pos);

  playFlashRaw1.play(filename);
  // Simply wait for the file to finish playing.
  while (playFlashRaw1.isPlaying()) {
   } 
}
 
Are we both using the same version of SerialFlash Library examples...
This is what my ReadBenchMark sketch give me for the two file I have on spiflash now

All Files on SPI Flash chip:
WHISTM2.RAW, 14622 bytes, read in 5808 us, speed = 2517.56 kbytes/sec
LOCORUN1.RAW, 89834 bytes, read in 35632 us, speed = 2521.16 kbytes/sec

you have a usend and usbegin print line.

Are you using the same CopyFromSerial as I am using...???
I am using the one I posted on an earlier Post

I think mine is the one that came in SerialFlash library in Arduino 185.....??

The player sketch is basic........ just connection between PlayRawFlash and DAC....no mixer or gain setting in between
are you using analogReference(INTERNAL)....??
 
Result on monitor :
Playing file: 1
14852
32768
Playing file: 1
14852
32768
Playing file: 1
14852
32768
...................

No "WHISTM1.TRW" ! ! !
 
This is this version :
/* SerialFlash Library - for filesystem-like access to SPI Serial Flash memory
* https://github.com/PaulStoffregen/SerialFlash
* Copyright (C) 2015, Paul Stoffregen, paul@pjrc.com
and CopyFromSerial :
Code:
/*
 * This is free and unencumbered software released into the public domain.
 * 
 * Anyone is free to copy, modify, publish, use, compile, sell, or
 * distribute this software, either in source code form or as a compiled
 * binary, for any purpose, commercial or non-commercial, and by any
 * means.
 * 
 * In jurisdictions that recognize copyright laws, the author or authors
 * of this software dedicate any and all copyright interest in the
 * software to the public domain. We make this dedication for the benefit
 * of the public at large and to the detriment of our heirs and
 * successors. We intend this dedication to be an overt act of
 * relinquishment in perpetuity of all present and future rights to this
 * software under copyright law.
 * 
 * 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 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.
 * 
 * For more information, please refer to <http://unlicense.org>
 * -------------------------------------------------------------------------
 * 
 * This is example code to 1) format an SPI Flash chip, and 2) copy raw 
 * audio files (mono channel, 16 bit signed, 44100Hz) to it using the 
 * SerialFlash library.  The audio can then be played back using the 
 * AudioPlaySerialflashRaw object in the Teensy Audio library.
 * 
 * To convert a .wav file to the proper .RAW format, use sox:
 * sox input.wav -r 44100 -b 16 --norm -e signed-integer -t raw OUTPUT.RAW remix 1,2
 * 
 * Note that the OUTPUT.RAW filename must be all caps and contain only the following
 * characters: A-Z, 0-9, comma, period, colon, dash, underscore.  (The SerialFlash
 * library converts filenames to caps, so to avoid confusion we just enforce it here).
 * 
 * It is a little difficult to see what is happening; aswe are using the Serial port
 * to upload files, we can't just throw out debug information.  Instead, we use the LED
 * (pin 13) to convey state.
 * 
 * While the chip is being formatted, the LED (pin 13) will toggle at 1Hz rate.  When 
 * the formatting is done, it flashes quickly (10Hz) for one second, then stays on 
 * solid.  When nothing has been received for 3 seconds, the upload is assumed to be 
 * completed, and the light goes off.
 * 
 * Use the 'rawfile-uploader.py' python script (included in the extras folder) to upload
 * the files.  You can start the script as soon as the Teensy is turned on, and the
 * USB serial upload will just buffer and wait until the flash is formatted.
 * 
 * This code was written by Wyatt Olson <wyatt@digitalcave.ca> (originally as part 
 * of Drum Master http://drummaster.digitalcave.ca and later modified into a 
 * standalone sample).
 * 
 * Enjoy!
 */

#include <SerialFlash.h>
#include <SPI.h>

//Buffer sizes
#define USB_BUFFER_SIZE      128
#define FLASH_BUFFER_SIZE    4096

//Max filename length (8.3 plus a null char terminator)
#define FILENAME_STRING_SIZE      13

//State machine
#define STATE_START      0
#define STATE_SIZE      1
#define STATE_CONTENT    2

//Special bytes in the communication protocol
#define BYTE_START      0x7e
#define BYTE_ESCAPE      0x7d
#define BYTE_SEPARATOR    0x7c


//SPI Pins (these are the values on the Audio board; change them if you have different ones)
#define MOSI               7
#define MISO              12
#define SCK               14
#define CSPIN              6
//#define CSPIN           21  // Arduino 101 built-in SPI Flash

void setup(){
  Serial.begin(9600);  //Teensy serial is always at full USB speed and buffered... the baud rate here is required but ignored

  pinMode(13, OUTPUT);
  
  //Set up SPI
  //SPI.setMOSI(MOSI);  // uncomment these if using the alternate pins
  //SPI.setMISO(MISO);
  //SPI.setSCK(SCK);
  if (!SerialFlash.begin(CSPIN)) {
    while (1) {
      Serial.println("Unable to access SPI Flash chip");
      delay(1000);
    }
  }


  //We start by formatting the flash...
  uint8_t id[5];
  SerialFlash.readID(id);
  SerialFlash.eraseAll();
  
  //Flash LED at 1Hz while formatting
  while (!SerialFlash.ready()) {
    delay(500);
    digitalWrite(13, HIGH);
    delay(500);
    digitalWrite(13, LOW);
  }

  //Quickly flash LED a few times when completed, then leave the light on solid
  for(uint8_t i = 0; i < 10; i++){
    delay(100);
    digitalWrite(13, HIGH);
    delay(100);
    digitalWrite(13, LOW);
  }
  digitalWrite(13, HIGH);
  
  //We are now going to wait for the upload program
  while(!Serial.available());
  
  SerialFlashFile flashFile;
  
  uint8_t state = STATE_START;
  uint8_t escape = 0;
  uint8_t fileSizeIndex = 0;
  uint32_t fileSize = 0;
  char filename[FILENAME_STRING_SIZE];
  
  char usbBuffer[USB_BUFFER_SIZE];
  uint8_t flashBuffer[FLASH_BUFFER_SIZE];
  
  uint16_t flashBufferIndex = 0;
  uint8_t filenameIndex = 0;
  
  uint32_t lastReceiveTime = millis();
  
  //We assume the serial receive part is finished when we have not received something for 3 seconds
  while(Serial.available() || lastReceiveTime + 3000 > millis()){
    uint16_t available = Serial.readBytes(usbBuffer, USB_BUFFER_SIZE);
    if (available){
      lastReceiveTime = millis();
    }

    for (uint16_t usbBufferIndex = 0; usbBufferIndex < available; usbBufferIndex++){
      uint8_t b = usbBuffer[usbBufferIndex];
      
      if (state == STATE_START){
        //Start byte.  Repeat start is fine.
        if (b == BYTE_START){
          for (uint8_t i = 0; i < FILENAME_STRING_SIZE; i++){
            filename[i] = 0x00;
          }
          filenameIndex = 0;
        }
        //Valid characters are A-Z, 0-9, comma, period, colon, dash, underscore
        else if ((b >= 'A' && b <= 'Z') || (b >= '0' && b <= '9') || b == '.' || b == ',' || b == ':' || b == '-' || b == '_'){
          filename[filenameIndex++] = b;
          if (filenameIndex >= FILENAME_STRING_SIZE){
            //Error name too long
            flushError();
            return;
          }
        }
        //Filename end character
        else if (b == BYTE_SEPARATOR){
          if (filenameIndex == 0){
            //Error empty filename
            flushError();
            return;
          }
          
          //Change state
          state = STATE_SIZE;
          fileSizeIndex = 0;
          fileSize = 0;
          
        }
        //Invalid character
        else {
          //Error bad filename
          flushError();
          return;
        }
      }
      //We read 4 bytes as a uint32_t for file size
      else if (state == STATE_SIZE){
        if (fileSizeIndex < 4){
          fileSize = (fileSize << 8) + b;
          fileSizeIndex++;
        }
        else if (b == BYTE_SEPARATOR){
          state = STATE_CONTENT;
          flashBufferIndex = 0;
          escape = 0;
          
          if (SerialFlash.exists(filename)){
            SerialFlash.remove(filename);  //It doesn't reclaim the space, but it does let you create a new file with the same name.
          }
          
          //Create a new file and open it for writing
          if (SerialFlash.create(filename, fileSize)) {
            flashFile = SerialFlash.open(filename);
            if (!flashFile) {
              //Error flash file open
              flushError();
              return;
            }
          }
          else {
            //Error flash create (no room left?)
            flushError();
            return;
          }
        }
        else {
          //Error invalid length requested
          flushError();
          return;
        }
      }
      else if (state == STATE_CONTENT){
        //Previous byte was escaped; unescape and add to buffer
        if (escape){
          escape = 0;
          flashBuffer[flashBufferIndex++] = b ^ 0x20;
        }
        //Escape the next byte
        else if (b == BYTE_ESCAPE){
          //Serial.println("esc");
          escape = 1;
        }
        //End of file
        else if (b == BYTE_START){
          //Serial.println("End of file");
          state = STATE_START;
          flashFile.write(flashBuffer, flashBufferIndex);
          flashFile.close();
          flashBufferIndex = 0;
        }
        //Normal byte; add to buffer
        else {
          flashBuffer[flashBufferIndex++] = b;
        }
        
        //The buffer is filled; write to SD card
        if (flashBufferIndex >= FLASH_BUFFER_SIZE){
          flashFile.write(flashBuffer, FLASH_BUFFER_SIZE);
          flashBufferIndex = 0;
        }
      }
    }
  }

  //Success!  Turn the light off.
  digitalWrite(13, LOW);
}

void loop(){
  //Do nothing.
}

void flushError(){
  uint32_t lastReceiveTime = millis();
  char usbBuffer[USB_BUFFER_SIZE];
  //We assume the serial receive part is finished when we have not received something for 3 seconds
  while(Serial.available() || lastReceiveTime + 3000 > millis()){
    if (Serial.readBytes(usbBuffer, USB_BUFFER_SIZE)){
      lastReceiveTime = millis();
    }
  }
}
 
Status
Not open for further replies.
Back
Top