Functions for operating the uDrive by 4D Systems:

The data logger doesn't use most of the functions for RAW mode but they should work.

#include <NewSoftSerial.h>
#include <WString.h>

const int uDrive_AcknowledgementTimeout = 1000;


// const

#define ACK 0x06  // Acknowledge byte (means ok)
#define NACK 0x15 // Negative acknoledge byte (means not ok)
#define EXTENDED 0x40
#define DEVICE_INFO 0x56

#define INITIALIZE_MODULE 0x55
#define INITIALIZE_DISK 0x69
#define SET_ADDR 0x41
#define READ_BYTE 0x72
#define WRITE_BYTE 0x77

#define READ_SECTOR 0x52
#define WRITE_SECTOR 0x57

#define FAT_READ 0x61
#define FAT_WRITE 0x74
#define FAT_LIST 0x64
#define FAT_DELETE 0x65
#define APPEND_MODE_ON 0x80
#define APPEND_MODE_OFF 0x00

#define TX_PIN 9
#define RX_PIN 10
#define RESET_PIN 8
#define LED_PIN 13

NewSoftSerial uDrive_serial(TX_PIN, RX_PIN);
boolean uDrive_isIntitialized = false;

boolean uDrive_isDiskloaded = false;

unsigned long uDrive_sectorAddress = 1; // next sector to write

byte uDrive_buffer[0];
int uDrive_buffer_index = 0;

/*******************/
/* COMMON COMMANDS */
/*******************/

// Initialize uDrive

boolean uDrive_Initialize ()
{
        // Reset device

        pinMode (RESET_PIN, OUTPUT);

        digitalWrite (RESET_PIN, LOW);
        delay (10);

        digitalWrite (RESET_PIN, HIGH);
        delay (1000);

        // Setup device
        uDrive_serial.begin(9600); // 38400, 28800, 14400, 9600, 1200 or 300
        uDrive_serial.print (INITIALIZE_MODULE, BYTE);

        if (!uDrive_CheckAcknowledgement (5000))
        {
          return false;
        }

        // return
        uDrive_isIntitialized = true;
        return true;

}

// Load Disk

boolean uDrive_LoadDisk ()
{

        uDrive_serial.print (EXTENDED, BYTE);

        uDrive_serial.print (INITIALIZE_DISK, BYTE);
        // check if successful
        if (!uDrive_CheckAcknowledgement ())

        return false;

        // return
        uDrive_isDiskloaded = true;

        return true;

}

void uDrive_DeviceInfo()
{

    uDrive_serial.print (DEVICE_INFO, BYTE);

    for (int i=0; i < 5; i++)
    {

        while (!uDrive_serial.available())
        {
            delay (10);

        }

        int val = uDrive_serial.read();

        Serial.println(val);
    }
}

void uDrive_FatProtect(boolean on)
{

    uDrive_serial.print (0x59, BYTE);

    uDrive_serial.print (0x08, BYTE);

    if (on)
      uDrive_serial.print (0x01, BYTE);

    else
      uDrive_serial.print (0x00, BYTE);

    WaitForAck();
}

// Check response if OK

boolean WaitForAck()
{
    char b = 0;
    while(b != ACK && b != NACK)
    {

        if(uDrive_serial.available() > 0)
        {
            b = uDrive_serial.read();

        }
    }

    if(b == ACK)
        {
          return true;
        }

    return false;

}

boolean uDrive_CheckAcknowledgement ()
{
        uDrive_CheckAcknowledgement (uDrive_AcknowledgementTimeout);
}

boolean uDrive_CheckAcknowledgement (int timeout)
{

        // wait for ack
        int iDelay = 10;
        int i = 0;

        while (!uDrive_serial.available())
        {
                delay (iDelay);
                if (timeout / iDelay < i)

                return false;
                i += 1;
        }

        // Read

        int val = uDrive_serial.read();

        // Return
        if (val != ACK)
        {

            return false;
        }
        return true;
}

void ClearJunk()
{

    while(uDrive_serial.available() > 0)
    {
        char c = uDrive_serial.read();
    }
}

void writeLong4(long data)
{
     uDrive_serial.print (((data >> 24) & 0xff), BYTE); // Filesize

     uDrive_serial.print (((data >> 16) & 0xff), BYTE);

     uDrive_serial.print (((data >> 8) & 0xff), BYTE);

     uDrive_serial.print (((data) & 0xff), BYTE);
}

void writeLong3(long data)
{

    uDrive_serial.print (((data >> 16) & 0xff), BYTE);

    uDrive_serial.print (((data >> 8) & 0xff), BYTE);

    uDrive_serial.print (((data) & 0xff), BYTE);
}

/***********************/
/* RAW ACCESS COMMANDS */
/***********************/

boolean setAddress(long addr)
{
        uDrive_serial.print (EXTENDED, BYTE);

        uDrive_serial.print (SET_ADDR, BYTE);

        writeLong4(addr);

        // check if successful
        if (uDrive_CheckAcknowledgement ())
        {
            return true;
        }
        else

        {
            return false;
        }

}

boolean writeByte(byte b)
{
    writeByte(b, -1);
}

boolean writeByte(byte b, long addr)
{
    boolean addrOk = true;

    if (addr >= 0)
    {
        addrOk = setAddress(addr);
    }

    if (addrOk)
    {
        uDrive_serial.print (EXTENDED, BYTE);

        uDrive_serial.print (WRITE_BYTE, BYTE);
        uDrive_serial.print (b, BYTE);

        if (uDrive_CheckAcknowledgement ())
        {
              return true;
        }
        else
        {

              return false;
        }
    }
    else
    {
       return false;
    }

}

byte readByte()
{
    readByte(-1);
}

byte readByte(long addr)
{

    boolean addrOk = true;
    if (addr >= 0)
    {

        addrOk = setAddress(addr);
    }

    if (addrOk)
    {

        uDrive_serial.print (EXTENDED, BYTE);
        uDrive_serial.print (READ_BYTE, BYTE);

        // wait for ack
        int iDelay = 10;
        int i = 0;

        while (!uDrive_serial.available())
        {
                delay (iDelay);
                if (uDrive_AcknowledgementTimeout / iDelay < i)

                return false;
                i += 1;
        }
        // Read
        byte val = uDrive_serial.read();

        return val;
    }
    else
    {
       return false;
    }

}

void readSector(long addr)
{
    uDrive_serial.print (EXTENDED, BYTE);

    uDrive_serial.print (READ_SECTOR, BYTE);

    writeLong3(addr);

    int count = 0;

    while (count < 512)
    {

        if (uDrive_serial.available() > 0)
        {
            uDrive_buffer[count] = uDrive_serial.read();

            count ++;
        }
        else
        {
            delay(10);
        }
    }
}

boolean writeSector(long addr)
{
    uDrive_serial.print (EXTENDED, BYTE);

    uDrive_serial.print (WRITE_SECTOR, BYTE);

    writeLong3(addr);

    for (int i=0; i < 512; i++)
    {

        uDrive_serial.print(uDrive_buffer[i], BYTE);
    }

    if (uDrive_CheckAcknowledgement ())
    {
        return true;
    }

    else
    {
        return false;
    }

}

boolean writeHeader()
{
    for (int i=0; i < 512; i++)
    {

      uDrive_buffer[i] = 0;
    }

    uDrive_buffer[0] = ((uDrive_sectorAddress >> 16) & 0xff);

    uDrive_buffer[1] = ((uDrive_sectorAddress >> 8) & 0xff);
    uDrive_buffer[2] = ((uDrive_sectorAddress) & 0xff);

    return writeSector(0);
}

void readHeader()
{
    for (int i=0; i < 512; i++)
    {

        uDrive_buffer[i] = 0;
    }
    uDrive_buffer_index = 0;

    readSector(0);

    uDrive_sectorAddress = 0;

    uDrive_sectorAddress = uDrive_sectorAddress | uDrive_buffer[0];

    uDrive_sectorAddress = uDrive_sectorAddress << 8;
    uDrive_sectorAddress = uDrive_sectorAddress | uDrive_buffer[1];

    uDrive_sectorAddress = uDrive_sectorAddress << 8;
    uDrive_sectorAddress = uDrive_sectorAddress | uDrive_buffer[2];
}

void clearDisk()
{
    for (int i=0; i < 512; i++)
    {

        uDrive_buffer[i] = 0;
    }
    uDrive_buffer_index = 0;

    uDrive_sectorAddress = 1;

    writeHeader();

}

boolean writeSample(byte sample)
{

    boolean result = true;
    uDrive_buffer[uDrive_buffer_index] = sample;

    if (uDrive_buffer_index == 511)
    {

        uDrive_buffer_index = 0;

        result = writeSector(uDrive_sectorAddress);

        if (result)
        {

            uDrive_sectorAddress++;
            writeHeader();
        }
    }
    else
    {
        uDrive_buffer_index++;
    }

    return result;
}

/***********************/
/* FAT ACCESS COMMANDS */
/***********************/

boolean uDrive_WriteFile(char *file, boolean overwrite, long numBytes, char *buff)
{

        ClearJunk();

        // command header
        uDrive_serial.print(EXTENDED, BYTE);

        uDrive_serial.print(FAT_WRITE, BYTE);

        // handshaking, append
        if(overwrite)

                uDrive_serial.print(0x00 | APPEND_MODE_OFF, BYTE);
        else

                uDrive_serial.print(0x00 | APPEND_MODE_ON, BYTE);

        for(int i = 0; i < strlen(file); i++)
        {

            uDrive_serial.print(file[i], BYTE);

        }

        uDrive_serial.print(0x00, BYTE);

        // file size
        writeLong4(numBytes+1);

        // wait for ack

        if (!WaitForAck())
        {

            return false;
        }

        for(int i = 0; i < numBytes; i++)
        {

                uDrive_serial.print(buff[i], BYTE);

        }

        uDrive_serial.print(0x0A, BYTE);

        // wait for ack
        if (!WaitForAck())
        {
            return false;
        }

        return true;
}

String uDrive_ListFiles()
{
        ClearJunk();

        // command header
        uDrive_serial.print(EXTENDED, BYTE);

        uDrive_serial.print(FAT_LIST, BYTE);

        uDrive_serial.print("*.*");

        uDrive_serial.print(0x00, BYTE);

        int count = 0;

        String inString = String(50);

        while (count < 50)
        {

            if (uDrive_serial.available() > 0)
            {
                char c = uDrive_serial.read();

                if (c == ACK)
                {
                break;
                }
                else

                {
                    inString.append(c);
                    count++;
                }
            }
            else

            {
            delay(10);
            }
        }

        return inString;
}

boolean uDrive_EraseFile(char *file)
{

        ClearJunk();

        // command header
        uDrive_serial.print(EXTENDED, BYTE);

        uDrive_serial.print(FAT_DELETE, BYTE);

        for(int i = 0; i < strlen(file); i++)
        {

            uDrive_serial.print(file[i], BYTE);

        }

        uDrive_serial.print(0x00, BYTE);

        // wait for ack
        if (!WaitForAck())
        {
            return false;
        }

        return true;
}

int uDrive_ReadInt()
{
        int iDelay = 10;
        int i = 0;

        while (!uDrive_serial.available())
        {
                delay (iDelay);
                if (uDrive_AcknowledgementTimeout / iDelay < i)

                return false;
                i += 1;
        }
        // Read
        int val = uDrive_serial.read();

        return val;
}

char uDrive_ReadChar()
{
        int iDelay = 10;

        int i = 0;
        while (!uDrive_serial.available())
        {

                delay (iDelay);
                if (uDrive_AcknowledgementTimeout / iDelay < i)

                return false;
                i += 1;
        }
        // Read
        char val = uDrive_serial.read();

        return val;
}

boolean uDrive_ReadFile(char *file)
{
        ClearJunk();

        // command header
        uDrive_serial.print(EXTENDED, BYTE);
        uDrive_serial.print(FAT_READ, BYTE);

        uDrive_serial.print(0x32, BYTE);

        for(int i = 0; i < strlen(file); i++)
        {

            uDrive_serial.print(file[i], BYTE);

        }

        uDrive_serial.print(0x00, BYTE);

        long size = 0;
        long data = 0;

        data = uDrive_ReadInt();
        size = size | (data << 24);

        data = uDrive_ReadInt();
        size = size | (data << 16);

        data = uDrive_ReadInt();
        size = size | (data << 8);

        data = uDrive_ReadInt();
        size = size | (data);

        uDrive_serial.print(ACK, BYTE);

        String inString = String(50);

        char count = 0;
        for(int i = 0; i < size; i++)
        {

          char c = uDrive_ReadChar();
          inString.append(c);

          // handshake
          if(count == 49)
          {
            Serial.print(inString);

            inString.clear();
            count = 0;
            uDrive_serial.print(ACK, BYTE);
          }

          else
          {
             count++;
          }

        }

        Serial.print(inString);

        // wait for ack
        if (!WaitForAck())
        {
            return false;
        }

        return true;
}

int uDrive_FileSize(char *file)
{
        ClearJunk();

        // command header

        uDrive_serial.print(EXTENDED, BYTE);
        uDrive_serial.print(FAT_READ, BYTE);

        uDrive_serial.print(0x32, BYTE);

        for(int i = 0; i < strlen(file); i++)
        {

            uDrive_serial.print(file[i], BYTE);

        }

        uDrive_serial.print(0x00, BYTE);

        long size = 0;
        long data = 0;

        data = uDrive_ReadInt();
        size = size | (data << 24);

        data = uDrive_ReadInt();
        size = size | (data << 16);

        data = uDrive_ReadInt();
        size = size | (data << 8);

        data = uDrive_ReadInt();
        size = size | (data);

        uDrive_serial.print(NACK, BYTE);

        return size;
}

This is the main data logger code:

/* Arduino sketch for Inspeed Vortex windspeed instrument
The anemometer.


=========================================================
ANEMOMETER
=========================================================
This is connected to Arduino ground on one side, and pin 2 (for the
attachInterrupt(0, ...) on the other.
Pin 2 is pulled up, and the reed switch on the anemometer will send
that to ground once per revolution, which will trigger the interrupt.
We count the number of revolutions in 5 seconds, and divide by 5.
One Hz (rev/sec) = 2.5 mph.

*********************************************************************/

#include <LiquidCrystal.h>
#include<stdlib.h>

#define uint  unsigned int
#define ulong unsigned long

#define DEBUG_MODE false
#define SERIAL_MODE true

#define PIN_ANEMOMETER  2     // Digital 2

// How often we want to calculate wind speed (msec)
#define MSECS_CALC_WIND_SPEED 10000.0 // 10 sec
#define AVG_SPEED_MULTIPLIER 30.0 // 5 min

volatile int numRevsAnemometer = 0; // Incremented in the interrupt


float avgSpeedTotal = 0;
ulong nextCalcSpeed;                // When we next calc the wind speed
ulong nextAvgCalcSpeed;                // When we next calc the average wind speed

ulong time;   // Millis() at each start of loop().
unsigned writeCount = 0;

LiquidCrystal lcd(12, 11, 6, 5, 4, 3);

void setup()
{

        // LED (2 * blink)
        pinMode(LED_PIN, OUTPUT);

        digitalWrite(LED_PIN, HIGH);
        delay(200);
        digitalWrite(LED_PIN, LOW);

        delay(200);
        digitalWrite(LED_PIN, HIGH);

        pinMode(PIN_ANEMOMETER, INPUT);

    digitalWrite(PIN_ANEMOMETER, HIGH);
    attachInterrupt(0, countAnemometer, FALLING);

    nextCalcSpeed = millis() + MSECS_CALC_WIND_SPEED;
        nextAvgCalcSpeed = millis() + (MSECS_CALC_WIND_SPEED * AVG_SPEED_MULTIPLIER);

    // set up the LCD's number of rows and columns:

    lcd.begin(16, 2);

    // Print a message to the LCD.
    lcd.clear();

    lcd.print("Setup begin");

        // Serial

        if ((DEBUG_MODE) || (SERIAL_MODE))
        {

          Serial.begin(9600);
          Console ("Setup begin");
        }

        // Initialize uDrive
        if (!uDrive_Initialize ())
        {
            Console ("Device not initialized");

            lcd.clear();
            lcd.print("Device not initialized");
        }

        // Check if Disk is inserted
        if (!uDrive_LoadDisk())
        {

                Console ("Disk not loaded");
                lcd.clear();
                lcd.print("Disk not loaded");
        }

        char buffer[] = "START";

        uDrive_WriteFile("SPEED.TXT", false, strlen(buffer), buffer);

        lcd.clear();
        lcd.print("Setup done");

        lcd.clear();

        lcd.setCursor(0,0);
    lcd.print("Spd:");

        lcd.setCursor(0,1);
    lcd.print("Avg:");

}

void Console(char *text)
{
   if (DEBUG_MODE)
   {

       Serial.println(text);
   }
}

//=======================================================
// Calculate the wind speed
// 1 rev/sec = 2.5 mph
//=======================================================
void calcWindSpeed2()
{

  writeCount++;

  char buffer[6];

  float seconds = MSECS_CALC_WIND_SPEED / 1000.0;

  float revsPerSecond = (float)numRevsAnemometer / seconds;

  float fspeed = revsPerSecond * 2.5;

  Console("Speed:");
  Console(dtostrf(fspeed,4,1,buffer));

  dtostrf(fspeed,4,1,buffer);

  lcd.setCursor(5,0);

  lcd.print(buffer);

  avgSpeedTotal += fspeed;

  if (time > nextAvgCalcSpeed)
  {

      float aspeed = avgSpeedTotal / AVG_SPEED_MULTIPLIER;

      avgSpeedTotal = 0;

      char abuffer[6];
      dtostrf(aspeed,4,1,abuffer);

      lcd.setCursor(5,1);
      lcd.print(abuffer);

      nextAvgCalcSpeed = time + (MSECS_CALC_WIND_SPEED * AVG_SPEED_MULTIPLIER);
  }

  //writeSample(numRevsAnemometer);


  if (uDrive_WriteFile("SPEED.TXT", false, strlen(buffer), buffer))
  {

    Console("Write OK");
    lcd.setCursor(15,1);
    lcd.print("*");
  }

  else
  {
    Console("Write Failed");
    lcd.setCursor(15,1);

    lcd.print("e");
  }

  lcd.setCursor(10,0);

  char count[11];
  sprintf(count, "%06d", writeCount);

  lcd.print(count);

  numRevsAnemometer = 0;        // Reset counter

}
//=======================================================
// Interrupt handler for anemometer. Called each time the reed
// switch triggers (one revolution).
//=======================================================
void countAnemometer()
{
  numRevsAnemometer++;
}

//=======================================================
// Main loop.
//=======================================================
void loop()
{

    boolean paused = false;

    if (SERIAL_MODE)
    {
        int incomingByte = 0;

        if (Serial.available() > 0)
        {
            incomingByte = Serial.read();

            if ((incomingByte == 76) || (incomingByte==108)) // L
            {

               String list = uDrive_ListFiles();
               Serial.println("Files:");
               Serial.println(list);

            }

            else if ((incomingByte == 115) || (incomingByte==83)) // S - Start Writing
            {
                 numRevsAnemometer = 0;
                 nextCalcSpeed = millis() + MSECS_CALC_WIND_SPEED;

                 nextAvgCalcSpeed = millis() + (MSECS_CALC_WIND_SPEED * AVG_SPEED_MULTIPLIER);

                 paused = false;
                 lcd.setCursor(15,1);

                 lcd.print(" ");
                 Serial.println("Data logging started.");
            }
            else if ((incomingByte == 112) || (incomingByte==80)) // P - Pause Writing

            {
                 paused = true;
                 lcd.setCursor(15,1);

                 lcd.print("P");
                 Serial.println("Data logging paused.");
            }
            else if ((incomingByte == 100) || (incomingByte==68)) // D - Delete File

            {
                 if (uDrive_EraseFile("SPEED.TXT"))
                 {
                     Serial.println("File deleted successfully");

                     writeCount = 0;
                 }
                 else
                 {
                     Serial.println("Error deleting file");
                 }
            }

            else if ((incomingByte == 114) || (incomingByte==82)) // R - Read File
            {
                 uDrive_ReadFile("SPEED.TXT");
            }

            else if ((incomingByte == 70) || (incomingByte==102)) // F - Read File Size
            {
                 Serial.print("File Size: ");
                 Serial.println(uDrive_FileSize("SPEED.TXT"));

            }

            else if ((incomingByte == 77) || (incomingByte==109)) // M - Show Menu
            {

                 Serial.println("M - Show this menu");
                 Serial.println("L - List files");
                 Serial.println("P - Pause file writing");

                 Serial.println("S - Start file writing");
                 Serial.println("R - Read file");
                 Serial.println("D - Delete file");

                 Serial.println("F - Show file size");
            }

        }
    }

    if (!paused)
    {
        time = millis();

        if (time >= nextCalcSpeed)
        {
            calcWindSpeed2();
            nextCalcSpeed = time + MSECS_CALC_WIND_SPEED;
        }
    }
}