class library to access fischertechnik interfaces via USB

Dependencies:   FatFileSystem mbed myBlueUSB neigbourhood rfcomm sdp

ftlib/ftlibclassdev.h

Committer:
networker
Date:
2013-03-11
Revision:
1:4676e8b9b357
Parent:
0:7da612835693

File content as of revision 1:4676e8b9b357:

#ifndef FTLIBCLASSDEV_H
#define FTLIBCLASSDEV_H

#include "ftlib.h"
#include "message.h"

#define ABF_IF_COMPLETE_NUM_WRITE 32
#define ABF_IF_COMPLETE_NUM_READ 42

/*****************************************************************************************
  The interfaces use a combination of synchronous (blocking) and asynchronous (non-blocking)
  I/O. For serial I/O it is essential that non-blocking I/O is used otherwise the entire 
  transfer timeslot would be consumed with busy waiting. For USB this constraint is less
  severe but I nevertheless used non-blocking I/O also for USB in the transfer thread (which
  is not a real thread). Outside the transfer thread, I/O can be synchronous which I indeed
  used because it is easier to write and easier to understand.
  The timing of the transfer thread is determined by a Ticker interrupt. But in order not
  to occupy the interrupt system for too long, it just increments a counter in every
  interface object. The main event loop polls this counter, initiates a transfer and resets
  it. Starting a thread works by calling FtThreadInit (which does some initialisation) and
  setting transferAktiv to FTX1RUN. The poll routine will then call guardedFtThreadBegin
  which in turn will call FtThreadBegin provided the previous run of the thread has ended.
  The thead is protected by a busy flag which is set in guardedFtThreadBegin and released
  in FtThreadEnd, as long as busy is active a new thread should not be begun (enforced by
  guardedFtThreadBegin). FtThreadBegin copies the transferArea (TA) to a buffer and calls
  the send routine which (being non-blocking) returns immediately. When the send completes
  a callback (interrupt) occurs which initiates the corresponding read (request-reply model).
  When the read finished another callback (interrupt) occurs which invokes FtThreadEnd.
  FtThreadEnd may call notification routines which will all like FtThreadEnd but unlike
  FtThreadBegin run in interrupt context. Both FtThreadBegin and FtThreadEnd operate on
  the TA which is shared between the application and the transfer thread. As this transfer-
  thread is not a real thread synchronisation is not strictly neccesary because FtThreadBegin
  runs in the background (like the application) and FtThreadEnd+callback run as interrupt
  and cannot be interrupted by the background. Still a semaphore 'lock' is in place to
  protect the TA from simultaneous access. When the area is locked, the transfer is simply
  skipped. A user application cal call test_and_set() which returns falls when the area is
  locked and true when it is free. After using the TA the user must then call increment()
  to release the lock on the TA. At the moment the onlu use-case is to provide a consistent
  set of motor-settings to the TX which will be communicated in the same packet.
*****************************************************************************************/

inline char* strdup(const char *s) {
    char *d = new char[strlen(s)+1];
    strcpy(d, s);
    return d;
}

class ftdev {
protected:
    FT_TRANSFER_AREA* ta;
    NOTIFICATION_EVENTS ne;
    msgbuffer<SMESSAGE, 10> *messages;
    int type, sn;
    unsigned fw;
    unsigned char out[ABF_IF_COMPLETE_NUM_WRITE]; //these buffers have maximum size, alternatively each subclass could have its own properly sized buffer
    unsigned char in[ABF_IF_COMPLETE_NUM_READ];
    int num_write, num_read;
    enum _ta_state {FTX1STOP, FTX1RUN, FTX1SYNC} transferAktiv;
    volatile int lock; //semaphore to control concurrent access to transferarea, FtThreadEnd is called in interrupt context
    volatile bool busy; //semaphore to prevent a transfer from being started while another is still in progress
    volatile bool interface_connected;
    volatile int triggered;//when >0 indicates that the next transfer should take place
    ftdev() {} //private default, construction takes place through subclasses
    ftdev(int t, int s): type(t), sn(s) {
        ta = 0;
        fw = 0;
        triggered = 0;
        busy = false;
        lock = 1;
        interface_connected = false;
        messages = 0;
        transferAktiv = FTX1STOP;
    }
    void trigger() {
        if (transferAktiv != FTX1STOP) triggered++;    //called by onTick
    }
    bool guardedFtThreadBegin(); //called by 'poll'
    bool guardedStop();
    virtual void FtThreadInit() { busy = false; if (ta) ta->TransferAktiv = true;} //called by StartFtTransferArea
    virtual void FtThreadBegin() = 0; //called by 'guardedFtThreadBegin'
    virtual void FtThreadEnd();   //called by interrupt when transfer completes
    virtual void FtThreadFinish() { if(ta) ta->TransferAktiv = false;} //called by StopFtTransferArea
    bool test_and_set(); //'lock' semphore
    void increment(); //'lock' semphore
    virtual unsigned pgm_message(unsigned code, unsigned dwMemBlock) = 0;
public:
    virtual ~ftdev() {
        delete ta;
        delete messages;
    }
//public API: These functions match those of the original ftlib
    virtual unsigned  CloseFtDevice() = 0;
    virtual unsigned  GetFtDeviceTyp() {
        return type;
    }
    virtual char*     GetFtSerialNrStrg();
    virtual unsigned  GetFtSerialNr() {
        return sn;
    }
    virtual char*     GetFtFirmwareStrg();
    virtual unsigned  GetFtFirmware() {
        return fw;
    }
    virtual char*     GetFtManufacturerStrg() = 0;
    virtual char*     GetFtShortNameStrg() = 0;
    virtual char*     GetFtLongNameStrg() = 0;
    /*
    virtual unsigned      GetFtDeviceSetting(FT_SETTING *pSet);
    virtual unsigned      SetFtDeviceSetting(FT_SETTING *pSet);
    */
    virtual unsigned      SetFtDistanceSensorMode(unsigned dwMode, unsigned dwTol1, unsigned dwTol2,
            unsigned dwSchwell1, unsigned dwSchwell2, unsigned dwRepeat1, unsigned dwRepeat2) {
        return FTLIB_ERR_NOT_SUPPORTED;
    }
    virtual unsigned      StartFtTransferArea(NOTIFICATION_EVENTS* sNEvent = 0);
    virtual unsigned      StartFtTransferAreaWithCommunication(NOTIFICATION_EVENTS* sNEvent = 0);
    virtual unsigned      StopFtTransferArea();
    virtual FT_TRANSFER_AREA*     GetFtTransferAreaAddress() {
        return ta;
    }
    virtual unsigned      IsFtTransferActiv();
    unsigned      ResetFtTransfer ();
    unsigned      SendFtMessage(unsigned char bHwId, unsigned char bSubId, unsigned dwMessage, unsigned dwWaitTime, unsigned dwOption);
    unsigned      ClearFtMessageBuffer();
    virtual unsigned StartFtProgram(unsigned dwMemBlock) {
        return FTLIB_ERR_NOT_SUPPORTED;
    }
    virtual unsigned StopFtProgram() {
        return FTLIB_ERR_NOT_SUPPORTED;
    }
    unsigned DeleteFtProgram(unsigned dwMemBlock) {
        return pgm_message(0xf5, dwMemBlock);
    }
    unsigned SetFtProgramActiv(unsigned dwMemBlock) {
        return pgm_message(0xf9, dwMemBlock);
    }
};


/* still to be implemented
    unsigned GetFtMemoryLayout(unsigned char * pbArray, unsigned dwSize);
    unsigned DownloadFtProgram(unsigned dwMemBlock, unsigned char* pbArray, unsigned dwSize, unsigned dwParameter, unsigned char *pbName, unsigned dwNameLen);
    unsigned GetFtProgramName(unsigned dwMemBlock, unsigned dwSize, char* pName);
    unsigned WriteFtMemoryData(unsigned dwData, unsigned dwAddress);
    unsigned GetFtMemoryData(unsigned char * pbArray, unsigned dwSize, unsigned dwAddress);
*/

#endif