Zmodem transfer from Teensy to PC

I'm sorry if i wasn't clear. I want to send data from an SD which runs on a teensy 3.2 to an SD on a Nano. I assumed that your code would be fine on the teensy, but might not fit on a Nano in complete form. All i need to do on the nano is receive the data over a serial connection to the teensy.

there is another likely problem which is that the nano serial connection is with SoftwareSerial. I wouldn't be surprised that this simply cannot be done without difficult-to-invent code.

What do you thinK?

john
 
Okay, I was hoping you wanted to send from the Nano, not receive to it. I don't know if that direction can be done. I'll let you know what I find.

One last question then - when it's time to get files to the Nano, can the ZModem sketch be the only thing flashed/loaded/running on the Nano? IF I make this work, it will consume nearly every byte the Nano has both in Flash and RAM, there won't be room for anything else.
 
You know, this may not be worth your effort. if I just belly up to the bar and replace the nano with a teensy, I'll be able to ditch softwareserial and use a hardware port, plus have plenty of room and you won't have to struggle to make it fit.

I will need a few other things on the nano end and it just might make more sense to go to the teensy. I would need some headroom in any case for other things I may want to do.

i would think that if you can make this work on an Uno, it would work on a Nano.

let me know.

John
 
there is another likely problem which is that the nano serial connection is with SoftwareSerial. I wouldn't be surprised that this simply cannot be done without difficult-to-invent code.

What do you thinK?

john

Opinion: Software serial (bit-banging with timer interrupts, not CPU loops) is OK for low speed (say, 9600 and down), half duplex (don't send and receive at the same time), and low duty cycles. Like incoming GPS sentences, keyboards, and so on.
 
John,

I think you'll likely need to replace that Nano with a Teensy in any case because in my understanding SoftwareSerial provides absolutely no serial buffer and if that is the case the chances that this (or anything else that can provide some reliable data transfer) can work successfully with SoftwareSerial are pretty low.

I'd like to have a version that can work on the Uno so the effort is a personal challenge regardless. It's just so darn close, I'm within a few bytes of success!
 
Hi BF. it just occurred to me that since the nano isn't connected via the usb port while it's in use, I can use the hardware serial port. let me try this before we pursue this any farther.

in any case, i'd be delighted to try what you do.

john
 
With the hardware serial port you're still likely to run into some trouble at high speeds because the Arduino's small Hardware Serial so small at only 64 bytes. I can only get my Mega to receive ZModem transfers at 57600.

I think the ZModem sketch can be made to work, just barely, on a smaller device with 32K of flash and 2K of RAM but it has to be configured for only ONE of send or receive. I'm still working on slimming up the send side enough to work reliably; it appears that receive actually works as I have it now (not yet uploaded to GitHub), in an Arduino Uno simulator anyway. I don't want to release it until I have it so it can be configured for either direction. I'll let you know if I make a breakthrough incase you want to try it out.
 
With the hardware serial port you're still likely to run into some trouble at high speeds because the Arduino's small Hardware Serial so small at only 64 bytes. I can only get my Mega to receive ZModem transfers at 57600.

I recall reading here that there's an easy way to increase the size of the Teensy UART buffers.

I must say that using ZModem would be an overkill and bring lots of big code / RAM demands for a problem that is simpler.
 
Hi stevech,

I wrote the ZModem sketch more so for use on simpler Arduino boards than the Teensy. Overkill, perhaps, but then it does handle auto-starting the download with the other side, handing off the file name, ensuring that the data is correct via CRC, and allowing for resuming downloads. For me, that's all pretty useful. Yes, it's quite hungry on memory, but I really meant for the sketch to be flashed on to the board for temporary use as a "Serial File Manager".
 
I'm waking this thread up again because you guys show more signs of life than the folks at forum.arduino.cc and I'm hoping someone will test my new sketch version on a small Arduino board.

So jferguson and others who might be interested, I did a large scale overhaul to my ZModem sketch and I actually got it down (with a lot of very creative and unorthodox wrangling) to just under 30K of Flash and just under 2K of RAM needed. I even managed to do that and not have to choose to enable only one of send or receive. I didn't think it could be done at first, but it appears I proved myself wrong. I put some macros into zmodem_config.h that allow you to disable send, receive, or the file manager commands just incase, but I'm hopeful it's not necessary to do so.

It would be fabulous if someone with an SDCard on an Uno, or better yet a Nano because it has little less flash available, would take the latest version for a test drive and let me know how it runs! Over here at GitHub:

https://github.com/ecm-bitflipper/Arduino_ZModem
 
Hi BF,
let me take a look, but it'll take a day or two. it would probably be useful if you whipped up a sketch, too.

nice going.

john
 
John, it is a sketch as it stands. Have a look at my video
for how to use it.

Perhaps a good next step for it would be to break the ZModem functionality into a library and then make the file manager an "example sketch". As it stands right now, it's a stand alone sketch. Keep in mind that if you try to use it as a library on a board with only 2K of memory (Uno, Nano) that there is almost no memory left even if you comment out one of the macros in zmodem_config.h to disable one of either send or receive. Anything else the sketch is made to do will need to use very few bytes of memory.
 
Last edited:
I see now, sorry for my confusion. I should be able to get into this in the next day or so.

thanks for your fine work,

john
 
what ar you compiling with? with the arduino 1.6.5 IDE I get these sorts of errors


zmodem_rz.cpp.o:/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: first defined here
zmodem/zmodem_rz.cpp.o: In function `getfree()':
/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: multiple definition of `tryz()'
zmodem_rz.cpp.o:/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: first defined here
zmodem/zmodem_rz.cpp.o: In function `getfree()':
/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: multiple definition of `tryzhdrtype'

/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: multiple definition of `rzfile()'
zmodem_rz.cpp.o:/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: first defined here
zmodem/zmodem_rz.cpp.o: In function `getfree()':
/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: multiple definition of `rzfiles()'
zmodem_rz.cpp.o:/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: first defined here
zmodem/zmodem_rz.cpp.o: In function `getfree()':
/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: multiple definition of `wcreceive(int, char**)'
zmodem_rz.cpp.o:/usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h:128: first defined here
collect2: error: ld returned 1 exit status
Error compiling.
 
I used Arduino IDE 1.6.5 to build the sketch and tried 1.6.7 over the weekend which worked as well.

It looks like you have a similar issue to one I ran into when I created a "backup" directory inside my zmodem directory and then copied all the source files in there. It started giving me multiple definition errors for everything at that point.

From the errors you are getting, it looks like you have a primary zmodem directory where you have all the source files, then a subdirectory, again called zmodem, under that with all the source files duplicated there. Get rid of the subdirectory and try compiling again.
 
That's a good idea but from looking at the error messages you may have code in zmodem and its associated modules which duplicates definitions in /usr/share/arduino/hardware/arduino/avr/cores/arduino/HardwareSerial.h

also could be problem having both SD and sdFAT libraries in same system.

I'll look into this when i get time. I would think everyone would have the module listed above, so i wonder if you do.

One last edit: You might want to see if your work will compile on a fresh installation of the Arduino IDE with only the specific libraries added which you need such as SdFat. I suspect that you may have removed some other libraries from the base installation whose presence would cause the sorts of problem I'm having.

just an idea.

John
 
Last edited:
This code is exactly what I have been looking for. I want to be able to download files from the PC, over the USB/serial link, onto the SD card in my Teensy 3.5, for use in the application, without having to unplug the SD card and use a card reader/writer plugged into a PC USB port.

I was thinking of writing some kind of server to run on the PC (using Python?) which would allow me to use the serial I/O for debug as normal but also to transfer files from the PC to the card. This would have taken quite a few days (weeks?) of effort.

I have had all sorts of problems trying to get this to work.

I am using a Teensy 3.5, 4Gb SD card, Arduino 1.8.5 and Teensyduino 1.42.

I have found various postings in this forum about accessing the SD card for the Teensy 3.5, and have made what I believe to be the necessary modifications, however I get an error on the following line (in setup()).

Code:
if(!sd.chdir("/", true)) sd.errorHalt(F("sd.chdir"));

I have to say that I am confused by the various libraries, and even which mode the SD card is in (SPI or SDIO). In order to get the code to compile I had to install the SdFat library from the library manager (V1.1.0).

I have tried example sketches and they appear to show that everything can work correctly.

SdFat-TeensySdioInfo. I see "sd" declared either as SdFatSdioEX (works very fast) or as SdFat. If understand correctly the EX library uses high speed SDIO mode and the other uses regular SPI? When USE_SDIO is set to 1 it works, when set to 0 it fails (and my fixes like changing the chip select to BUILTIN_SDCARD and/or adding #including <SD.h> all hell breaks loose. Nightmare! NOTE: now fixed thanks to the information in this thread. Note that this code does not work out of the box for the Teensy 3.5.

SdFat-TeensySdioDemo. Uses libraries SdFatSdio and SdFatSdioEX. I am no expert with C++ and so I am confused where these libraries are defined, or even what functions they support. Compiles out of the box for the Teensy3.5 and shows a massive performance increase using the EX library.

Code:
SdFatSdioEX uses extended multi-block transfers without DMA.
SdFatSdio uses a traditional DMA SDIO implementation.
Note the difference is speed and busy yield time.

Type '1' for SdFatSdioEX or '2' for SdFatSdio

size,write,read
bytes,KB/sec,KB/sec
512,10295.69,14800.60
1024,7454.23,15108.40
2048,7295.42,15173.25
4096,7528.96,15641.63
8192,7448.75,15673.34
16384,7499.14,15429.28
32768,7446.88,15728.15

totalMicros  11398790
yieldMicros  938327
yieldCalls   183
yieldMaxUsec 29345
kHzSdClk     40000
Done
Type '1' for SdFatSdioEX or '2' for SdFatSdio

size,write,read
bytes,KB/sec,KB/sec
512,202.32,718.72
1024,404.92,903.77
2048,782.70,1815.35
4096,1480.93,3654.39
8192,2813.48,7066.20
16384,4733.90,10335.29
32768,7778.19,13057.83

totalMicros  114902946
yieldMicros  114311569
yieldCalls   67040
yieldMaxUsec 338288
kHzSdClk     40000
Done
Type '1' for SdFatSdioEX or '2' for SdFatSdio

SD-CardInfo. I have #define USE_SDIO 1 and const int chipSelect = BUILTIN_SDCARD;. I see that this uses libraries Sd2Card SdVolume and SdFile and not the SdFat libraries unless they are referenced under the hood so to speak. I'm guessing that this will use the standard SPI access and not the SDIO??? Anyway it works and shows that the card can be accessed and files seen.
Code:
const int chipSelect = BUILTIN_SDCARD; 
Initializing SD card...Wiring is correct and a card is present.

Card type: SDHC

Volume type is FAT32

Volume size (bytes): 3972005888
Volume size (Kbytes): 3878912
Volume size (Mbytes): 3788

Files found on the card (name, date and size in bytes): 
SYSTEM~1/     2019-03-21 20:46:22
  WPSETT~1.DAT  2019-03-21 20:46:22 12
  INDEXE~1      2019-03-21 20:46:22 76
TEENSY~1.BIN  2000-01-01 01:00:00 8388608
DISKMI~1.TXT  2015-11-01 16:53:10 535
YCFCTX~1.TXT  2010-09-15 21:39:00 1694
Again I'm confused about these libraries and where to find clear details of which functions exist and how to use them.

So now to the ZMODEM transfer program code which I would like to use - Arduino_ZModem (downloaded from Github). I have made changes to use the SDIO for the Teensy3.5. Here is the output.
Code:
Arduino ZModem V2.1.2
Transfer rate: 57600
About to initialize SdCard
About to change directory
error: sd.chdir

Here is the sketch (however another 8 files are in the same folder containing the ZMODEM code). I haven't included them as the problem appears to be SD related (but anyone wishing to help would need to download the other files from https://github.com/ecm-bitflipper/Arduino_ZModem).

Code:
#include "Arduino.h"
#include <avr/pgmspace.h>

#include <SPI.h>
#include <SdFat.h>

// Arghhh. These three links have disappeared!
// See this page for the original code:
// http://www.raspberryginger.com/jbailey/minix/html/dir_acf1a49c3b8ff2cb9205e4a19757c0d6.html
// From: http://www.raspberryginger.com/jbailey/minix/html/zm_8c-source.html
// docs at: http://www.raspberryginger.com/jbailey/minix/html/zm_8c.html
// The minix files here might be the same thing:
// http://www.cise.ufl.edu/~cop4600/cgi-bin/lxr/http/source.cgi/commands/zmodem/

#include "zmodem_config.h"

#include "zmodem.h"
#include "zmodem_zm.h"

// This works with Tera Term Pro Web Version 3.1.3 (2002/10/08)
// (www.ayera.com) but TeraTerm only works on COM1, 2, 3 or 4.

// It DOES NOT handle interruptions of the Tx or Rx lines so it
// will NOT work in a hostile environment.
 
/*
  Originally was an example by fat16lib of reading a directory
  and listing its files by directory entry number.
See: http://forum.arduino.cc/index.php?topic=173562.0

  Heavily modified by Pete (El Supremo) to recursively list the files
  starting at a specified point in the directory structure and then
  use zmodem to transmit them to the PC via the ZSERIAL port

  Further heavy modifications by Dylan (monte_carlo_ecm, bitflipper, etc.)
  to create a user driven "file manager" of sorts.
  Many thanks to Pete (El Supremo) who got this started.  Much work remained
  to get receive (rz) working, mostly due to the need for speed because of the
  very small (64 bytes) Serial buffer in the Arduino.

  I have tested this with an Arduino Mega 2560 R3 interfacing with Windows 10
  using Hyperterminal, Syncterm and TeraTerm.  All of them seem to work, though
  their crash recovery (partial file transfer restart) behaviours vary.
  Syncterm kicks out a couple of non-fatal errors at the beginning of sending
  a file to the Arduino, but appears to always recover and complete the transfer.

  This sketch should work on any board with at least 30K of flash and 2K of RAM.
  Go to zmodem_config.h and disable some of the ARDUINO_SMALL_MEMORY_* macros
  for maximum peace of mind and stability if you don't need all the features
  (send, receive and file management).

V2.1.2
2018-05-11
  - Fixes for Arduino IDE 1.8.5
  - Attempted to patch for use on Teensy

V2.1
2015-03-06
  - Large scale code clean-up, reduction of variable sizes where they were
    unnecessarily large, sharing variables previously unshared between sz and
    rz, and creative use of the send/receive buffer allowed this sketch to
    BARELY fit and run with all features enabled on a board with 30K flash and
    2K of RAM.  Uno & Nano users - enjoy.
  - Some boards were unstable at baud rates above 9600.  I tracked this back
    to overrunning the SERIAL_TX_BUFFER_SIZE to my surprise.  Added a check
    if a flush() is required both in the help and directory listings, as well
    as the sendline() macro.

V2.0
2015-02-23
  - Taken over by Dylan (monte_carlo_ecm, bitflipper, etc.)
  - Added Serial based user interface
  - Added support for SparkFun MP3 shield based SDCard (see zmodem_config.h)
  - Moved CRC tables to PROGMEM to lighten footprint on dynamic memory (zmodem_crc16.cpp)
  - Added ZRQINIT at start of sz.  All terminal applications I tested didn't strictly need it, but it's
    super handy for getting the terminal application to auto start the download
  - Completed adaptation of rz to Arduino
  - Removed directory recursion for sz in favour of single file or entire current directory ("*") for sz
  - Optimized zdlread, readline, zsendline and sendline
      into macros for rz speed - still only up to 57600 baud
  - Enabled "crash recovery" for both sz and rz.  Various terminal applications may respond differently
      to restarting partially completed transfers; experiment with yours to see how it behaves.  This
      feature could be particularly useful if you have an ever growing log file and you just need to
      download the entries since your last download from your Arduino to your computer.

V1.03
140913
  - remove extraneous code such as the entire main() function
    in sz and rz and anything dependent on the vax, etc.
  - moved purgeline, sendline, readline and bttyout from rz to zm
    so that the the zmodem_rz.cpp file is not required when compiling
    sz 
    
V1.02
140912
  - yup, sz transfer still works.
    10 files -- 2853852 bytes
    Time = 265 secs
    
V1.01
140912
This was originally working on a T++2 and now works on T3
  - This works on a T3 using the RTC/GPS/uSD breadboard
    It sent multiple files - see info.h
  - both rz and sz sources compile together here but have not
    yet ensured that transmit still works.
    
V1.00
130630
  - it compiles. It even times out. But it doesn't send anything
    to the PC - the TTYUSB LEDs don't blink at all
  - ARGHH. It does help to open the Serial1 port!!
  - but now it sends something to TTerm but TTerm must be answering
    with a NAK because they just repeat the same thing over
    and over again.

V2.00
130702
  - IT SENT A FILE!!!!
    It should have sent two, but I'll take it!
  - tried sending 2012/09 at 115200 - it sent the first file (138kB!)
    but hangs when it starts on the second one. The file is created
    but is zero length.
    
  - THIS VERSION SENDS MULTIPLE FILES

*/

// Set USE_SDIO to zero for SPI card access. 
#define USE_SDIO 1
/*
 * SD chip select pin.  Common values are:
 *
 * Arduino Ethernet shield, pin 4.
 * SparkFun SD shield, pin 8.
 * Adafruit SD shields and modules, pin 10.
 * Default SD chip select is the SPI SS pin.
 */
const uint8_t SD_CHIP_SELECT = SS;
  
/////////////////////////////////////////////////////////////////
// SdFatSdioEX uses extended multi-block transfers without DMA //
// SdFatSdio uses a traditional DMA SDIO implementation        //
/////////////////////////////////////////////////////////////////
#if USE_SDIO
// Use faster SdioCardEX
SdFatSdioEX sd;
// SdFatSdio sd;
#else 
SdFatSdio   sd;
#endif 

#define error(s) sd.errorHalt(s)

// Teensy 2.0 has the LED on pin 11
// Teensy++ 2.0 has the LED on pin 6
// Teensy 3.x / Teensy LC have the LED on pin 13
const int ledPin = 13;

extern int Filesleft;
extern long Totalleft;

extern SdFile fout;
//------------------------------------------------------------------------------
// store error strings in flash
#define sdErrorMsg(msg) sd.errorPrint(F(msg));
//------------------------------------------------------------------------------

// Dylan (monte_carlo_ecm, bitflipper, etc.) - This function was added because I found
// that SERIAL_TX_BUFFER_SIZE was getting overrun at higher baud rates.  This modified
// Serial.print() function ensures we are not overrunning the buffer by flushing if
// it gets more than half full.

size_t DSERIALprint(const __FlashStringHelper *ifsh)
{
  PGM_P p = reinterpret_cast<PGM_P>(ifsh);
  size_t n = 0;
  while (1) {
    unsigned char c = pgm_read_byte(p++);
    if (c == 0) break;
    if (DSERIAL.availableForWrite() > SERIAL_TX_BUFFER_SIZE / 2) DSERIAL.flush();
    if (DSERIAL.write(c)) n++;
    else break;
  }
  return n;
}

#define DSERIALprintln(_p) ({ DSERIALprint(_p); DSERIAL.write("\r\n"); })

void help(void)
{
  DSERIALprint(Progname);
  DSERIALprint(F(" - Transfer rate: "));
  DSERIAL.flush(); DSERIAL.println(ZMODEM_SPEED); DSERIAL.flush();
  DSERIALprintln(F("Available Commands:")); DSERIAL.flush();
  DSERIALprintln(F("HELP     - Print this list of commands")); DSERIAL.flush();
  DSERIALprintln(F("DIR      - List files in current working directory - alternate LS")); DSERIAL.flush();
  DSERIALprintln(F("PWD      - Print current working directory")); DSERIAL.flush();
  DSERIALprintln(F("CD       - Change current working directory")); DSERIAL.flush();
#ifdef ARDUINO_SMALL_MEMORY_INCLUDE_FILE_MGR
  DSERIALprintln(F("DEL file - Delete file - alternate RM")); DSERIAL.flush();
  DSERIALprintln(F("MD  dir  - Create dir - alternate MKDIR")); DSERIAL.flush();
  DSERIALprintln(F("RD  dir  - Delete dir - alternate RMDIR")); DSERIAL.flush();
#endif
#ifdef ARDUINO_SMALL_MEMORY_INCLUDE_SZ
  DSERIALprintln(F("SZ  file - Send file from Arduino to terminal (* = all files)")); DSERIAL.flush();
#endif
#ifdef ARDUINO_SMALL_MEMORY_INCLUDE_RZ  
  DSERIALprintln(F("RZ       - Receive a file from terminal to Arduino (Hyperterminal sends this")); DSERIAL.flush();
  DSERIALprintln(F("              automatically when you select Transfer->Send File...)")); DSERIAL.flush();
#endif
}

SdFile fout;
//dir_t *dir ;

// Dylan (monte_carlo_ecm, bitflipper, etc.) - The way I made this sketch in any way operate on
// a board with only 2K of RAM is to borrow the SZ/RZ buffer for the buffers needed by the main
// loop(), in particular the file name parameter and the SdFat directory entry.  This is very
// unorthodox, but now it works on an Uno.  Please see notes in zmodem_config.h for limitations

#define name (&oneKbuf[512])
#define dir ((dir_t *)&oneKbuf[256])

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void setup()
{
  
  // initialize the digital pin as an output.
  pinMode(ledPin, OUTPUT);
  digitalWrite(ledPin, HIGH);   // set the LED on
  delay(2000);

// NOTE: The following line needs to be uncommented if DSERIAL and ZSERIAL are decoupled again for debugging
  DSERIAL.begin(9600);
  while (!DSERIAL) {
    ; // wait for serial port to connect. Needed for native USB port only
  }
  DSERIALprintln(Progname);
  DSERIALprint(F("Transfer rate: "));
  DSERIAL.println(ZMODEM_SPEED,DEC);

  ZSERIAL.begin(ZMODEM_SPEED);
  ZSERIAL.setTimeout(TYPICAL_SERIAL_TIMEOUT);

  //Initialize the SdCard.
  DSERIALprintln(F("About to initialize SdCard"));
  if (!sd.cardBegin()) {
    sdErrorMsg("\nsd.cardBegin failed");
    return;
  }

  DSERIALprintln(F("About to change directory"));
  sd.chvol();
  if(!sd.chdir("/", true)) sd.errorHalt(F("sd.chdir"));
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ hangs here.
/////////////////////////////////////////////////////////////////////


  DSERIALprintln(F("SdCard setup complete"));

  digitalWrite(ledPin, LOW);   // set the LED on
  while (1);

  sd.vwd()->rewind();

  help();
 
}

int count_files(int *file_count, long *byte_count)
{
  *file_count = 0;
  *byte_count = 0;
  
  sd.vwd()->rewind();

  while (sd.vwd()->readDir(dir) == sizeof(*dir)) {
    // read next directory entry in current working directory

    // format file name
    SdFile::dirName(dir, name);

    // remember position in directory
    uint32_t pos = sd.vwd()->curPosition();
     
    // open file
    if (!fout.open(name, O_READ)) error(F("file.open failed"));
    
    // restore root position
    else if (!sd.vwd()->seekSet(pos)) error(F("seekSet failed"));
  
    else if (!fout.isDir()) {
      *file_count = *file_count + 1;
      *byte_count = *byte_count + fout.fileSize();
    }
     
    fout.close();
  }
  return 0;
}

////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////////////////
void loop(void)
{
  char *cmd = oneKbuf;
  char *param;

  digitalWrite(ledPin, HIGH);   // set the LED on
  delay(500);                  // wait for a second
  digitalWrite(ledPin, LOW);    // set the LED off
  delay(3000);                  // wait for a second

  *cmd = 0;
  while (DSERIAL.available()) DSERIAL.read();
  
  char c = 0;
  while(1) {
    if (DSERIAL.available() > 0) {
      c = DSERIAL.read();
      if ((c == 8 or c == 127) && strlen(cmd) > 0) cmd[strlen(cmd)-1] = 0;
      if (c == '\n' || c == '\r') break;
      DSERIAL.write(c);
      if (c != 8 && c != 127) strncat(cmd, &c, 1);
    } else {
      // Dylan (monte_carlo_ecm, bitflipper, etc.) -
      // This delay is required because I found that if I hard loop with DSERIAL.available,
      // in certain circumstances the Arduino never sees a new character.  Various forum posts
      // seem to confirm that a short delay is required when using this style of reading
      // from Serial
      delay(20);
    }
  }
   
  param = strchr(cmd, 32);
  if (param > 0) {
    *param = 0;
    param = param + 1;
  } else {
    param = &cmd[strlen(cmd)];
  }

  strupr(cmd);
  DSERIAL.println();
//  DSERIALprintln(command);
//  DSERIALprintln(parameter);

  if (!strcmp_P(cmd, PSTR("HELP"))) {
    
    help();
    
  } else if (!strcmp_P(cmd, PSTR("DIR")) || !strcmp_P(cmd, PSTR("LS"))) {
    DSERIALprintln(F("Directory Listing:"));

    sd.vwd()->rewind();

    while (sd.vwd()->readDir(dir) == sizeof(*dir)) {
      // read next directory entry in current working directory
  
      // format file name
      SdFile::dirName(dir, name);

      DSERIAL.flush(); DSERIAL.print(name); DSERIAL.flush();
      for (uint8_t i = 0; i < 16 - strlen(name); ++i) DSERIALprint(F(" "));
      if (!(dir->attributes & DIR_ATT_DIRECTORY)) {
        ultoa(dir->fileSize, name, 10);
        DSERIAL.flush(); DSERIAL.println(name); DSERIAL.flush();
      } else {
        DSERIALprintln(F("DIR"));
      }
      DSERIAL.flush();
    }
    DSERIALprintln(F("End of Directory"));
 
  } else if (!strcmp_P(cmd, PSTR("PWD"))) {
    sd.vwd()->getName(name, 13);
    DSERIALprint(F("Current working directory is "));
    DSERIAL.flush(); DSERIAL.println(name); DSERIAL.flush();
  
  } else if (!strcmp_P(cmd, PSTR("CD"))) {
    if(!sd.chdir(param, true)) {
      DSERIALprint(F("Directory "));
      DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush();
      DSERIALprintln(F(" not found"));
    } else {
      DSERIALprint(F("Current directory changed to "));
      DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush();
    }
#ifdef ARDUINO_SMALL_MEMORY_INCLUDE_FILE_MGR
  } else if (!strcmp_P(cmd, PSTR("DEL")) || !strcmp_P(cmd, PSTR("RM"))) {
    if (!sd.remove(param)) {
      DSERIALprint(F("Failed to delete file "));
      DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush();
    } else {
      DSERIALprint(F("File "));
      DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush();
      DSERIALprintln(F(" deleted"));
    }
  } else if (!strcmp_P(cmd, PSTR("MD")) || !strcmp_P(cmd, PSTR("MKDIR"))) {
    if (!sd.mkdir(param, true)) {
      DSERIALprint(F("Failed to create directory "));
      DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush();
    } else {
      DSERIALprint(F("Directory "));
      DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush();
      DSERIALprintln(F(" created"));
    }
  } else if (!strcmp_P(cmd, PSTR("RD")) || !strcmp_P(cmd, PSTR("RMDIR"))) {
    if (!sd.rmdir(param)) {
      DSERIALprint(F("Failed to remove directory "));
      DSERIAL.flush(); DSERIAL.println(param); DSERIAL.flush();
    } else {
      DSERIALprint(F("Directory "));
      DSERIAL.flush(); DSERIAL.print(param); DSERIAL.flush();
      DSERIALprintln(F(" removed"));
    }
#endif
#ifdef ARDUINO_SMALL_MEMORY_INCLUDE_SZ
  } else if (!strcmp_P(cmd, PSTR("SZ"))) {
//    Filcnt = 0;
    if (!strcmp_P(param, PSTR("*"))) {
      count_files(&Filesleft, &Totalleft);
      sd.vwd()->rewind();

      if (Filesleft > 0) {
        ZSERIAL.print(F("rz\r"));
        sendzrqinit();
        delay(200);
        
        while (sd.vwd()->readDir(dir) == sizeof(*dir)) {
          // read next directory entry in current working directory
      
          // format file name
          SdFile::dirName(dir, name);
                     
          // open file
          if (!fout.open(name, O_READ)) error(F("file.open failed"));
        
          else if (!fout.isDir()) {
            if (wcs(name) == ERROR) {
              delay(500);
              fout.close();
              break;
            }
            else delay(500);
          }
           
          fout.close();
        }
        saybibi();
      } else {
        DSERIALprintln(F("No files found to send"));
      }
    } else if (!fout.open(param, O_READ)) {
      DSERIALprintln(F("file.open failed"));
    } else {
      // Start the ZMODEM transfer
      Filesleft = 1;
      Totalleft = fout.fileSize();
      ZSERIAL.print(F("rz\r"));
      sendzrqinit();
      delay(200);
      wcs(param);
      saybibi();
      fout.close();
    }
#endif
#ifdef ARDUINO_SMALL_MEMORY_INCLUDE_RZ
  } else if (!strcmp_P(cmd, PSTR("RZ"))) {
//    DSERIALprintln(F("Receiving file..."));
    if (wcreceive(0, 0)) {
      DSERIALprintln(F("zmodem transfer failed"));
    } else {
      DSERIALprintln(F("zmodem transfer successful"));
    }
    fout.flush();
    fout.sync();
    fout.close();
#endif
  }
}

So from the various example sketches I can see that the SD card can be accessed and files can be seen (albeit using different libraries - hence my confusion as to how to fix the problem).

The first card operation to change directories fails, and it's game over. I am baffled as to what needs to be fixed.

--Gary
 
Last edited:
I wish I could help you out Gary. There are so many varieties of Arduinos out there that require different libraries. I adapted the code to work with Mega and Uno. It looks like you are very close to making it work. I do hope you eventually crack the puzzle!
 
I wish I could help you out Gary. There are so many varieties of Arduinos out there that require different libraries. I adapted the code to work with Mega and Uno. It looks like you are very close to making it work. I do hope you eventually crack the puzzle!

After much head scratching I finally got there. I am attaching the file in case it of use to anybody else. Errr, apparently I cannot do this. I'll have to figure out where to upload the ZIP file to in order to point to it in a future post.

I am now really pleased with the result. The serial text data and ZMODEM data share the same serial port, which makes life easier. I am using TeraTerm and I can upload and download files from/to the PC. In my application I use an external 68000 assembler tool to assemble some 68000 monitor code to a file I call "rom.bin". I then use the ZMODEM part of the sketch to download the latest assembled binary file from the PC to the SD card inside the Teesny3.5. I then hit a single key which my sketch interprets as "read rom.bin and download the contents to the 68000 board". Not having to mess around with removing the SD card is a real time saver.

Apologies. I cannot remember all the changes or to which files (in the end the changes were fairly minor). So download the ZIP (once I point to it!) , unzip and compare against the originals.

In my sketch use the TAB key to enter a textual command, such as "help" or "rz rom.bin", after the ">" appears. At all other times only single character keypresses are interpreted. I have left all my 68000 stuff in there, so this will need to be stripped out and replaced with your own Teensy3.5 code.

--Gary
 
Every once in a while I think about this sketch and wonder if anyone did anything new with it. Happy to see Gary got what he wanted out of it there. Happy file transferring. :)
 
BitFlipper, I'm also very interested in using the Zmodem portion of your sketch to send CSV datasets from a MEGA board to a PC running Teraterm.

I also am having problems compiling identical to Gary's above.

Code:
if(!sd.chdir("/", true)) sd.errorHalt(F("sd.chdir"));

I'm using IDE 1.8.16 and the latest SD and SDFat libraries. The author of SDfat commented about a major automated refactoring that might affect functionality and that seems a likely culprit.

I would be very interested if anyone has at least the Zmodem sz portion of the code that compiles with the latest tool chain.

Thanks, Joe
 
Back
Top