I messed up the merge, so pushing it over to another repo so I don't lose it. Will tidy up and remove later

Dependencies:   BufferedSerial FatFileSystemCpp mbed

main.cpp

Committer:
JamieB
Date:
17 months ago
Revision:
85:0cc5931bb9ef
Parent:
79:1910ae03cb2e
Parent:
81:aee60dcce61b

File content as of revision 85:0cc5931bb9ef:

#define APP_VERSION 0.32

/*
Settings file options

On startup system will look for settings.txt on the built in mbed drive.

This file should be ascii text with one option per line.
The following options supported:

Output_Format=n
    Sets the serial output format.
    n = 0 - VIPS
    n = 1 - FreeD


FIZ_Format=n
    Sets the FIZ reader to use
    n = 0 - Preston
    n = 1 - Fuji passive listen mode (skycam)
    n = 2 - Fuji active mode
    n = 3 - Canon
    n = 4 - Arri

FreeD_Port=pppp
    Sets the UDP port for FreeD network output.
    Data is sent as a UDP broadcast on the select port number.
    A port number of 0 disables UDP output.

VIPS_UDP_Port=pppp
    Same As Above

IP_addr=aaa.bbb.ccc.ddd
Subnet=aaa.bbb.ccc.ddd
Gateway=aaa.bbb.ccc.ddd
    Set the IPv4 address to use for the ethernet interface.
    All 3 values must be set for a static address to be used otherwise DHCP will be used.


FilterOrder=n
FilterFreq=m.mm
FilterRate=r.rr
Low pass filter settings for channels that have it enabled.
Filter is of order n with a cut off at m Hz assuming input data rate is at r Hz
Filter order must be set to enable filters.
Frequency default is 10Hz
Rate default is 100Hz

FilterXY=1
FilterZ=1
FilterRoll=1
FilterPitch=1
FilterYaw=1
Enable channels to low pass filter. All filters use the settings given above.
A value of 1 enables the filter. A value of 0 or skipping the line disables the filter.

NOTE-The filter will add latency so a filtered channel will be delayed relative to an unfiltered one.


ExtendedOutput=1
Enable extra fields in VIPS output.


All settings are case sensitive.
Do NOT include spaces in the options lines.
All options default to a value of 0 is omitted from the file.

*/

#include "mbed.h"
#include "LTCApp.h"
#include "EthernetInterface.h"
#include <vector>

//#define enableUSBStick
//#define enableFakePPF

// delay transmit to n ms after the frame
// comment out rather than set to 0 to disable
//#define Delay_TX_By 10

#ifdef enableUSBStick
#include "MSCFileSystem.h"
MSCFileSystem msc("msc");
#endif

BufferedSerial pc(USBTX, USBRX);
VIPSSerial VIPS(p28, p27);
BufferedSerial COM1(p13, p14);
FIZReader *FIZPort;
EthernetInterface eth;

DigitalOut led1(LED1);
DigitalOut led2(LED2);
DigitalOut led3(LED3);
DigitalOut frameToggle(LED4);

LTCDecode LTCInput(p7);
InterruptIn PPFin(p29);
InterruptIn Syncin(p8);

DigitalIn logButton(p17,PullDown);

DigitalOut RedLED(p18); // red
DigitalOut GreenLED(p19);
DigitalOut BlueLED(p20);

LocalFileSystem localFS("local");

#define LED_OFF 1
#define LED_ON 0

#define setRED() ({GreenLED=LED_OFF;BlueLED = LED_OFF;RedLED = LED_ON;})
#define setGREEN() ({GreenLED=LED_ON;BlueLED = LED_OFF;RedLED = LED_OFF;})
#define setBLUE() ({GreenLED=LED_OFF;BlueLED = LED_ON;RedLED = LED_OFF;})
#define setOFF() ({GreenLED=LED_OFF;BlueLED = LED_OFF;RedLED = LED_OFF;})

frameclock movieTime;

// clock to time everything with
Timer inputTimer;
Timeout resetTimeout;
Timeout filteringTimeout;
Timeout BypassTimeout;

#ifdef enableFakePPF
Ticker FakePPF;
#endif

float logButtonDownTime;
float logButtonUpTime;
int logButtonLastState;

bool bypassMode = false;
bool logging = false;
FILE *logFile = NULL;


// Time since last frame event, used for position output interpolation
Timer TimeSinceLastFrame;
uint32_t TimeSinceLastFrameWrap;

//Debug Timer for Ethernet
Timer EthernetTimer;
uint32_t TimeSinceLastEthernetPacket;

// used to start PPS at the correct point
Timeout PPSsyncTimer;

Timeout OutputDelayTimer;
Timeout UDPOutputDelayTimer;

// used to generate PPS edges
Ticker PPSOutputTimer;

frameRates detectedRate;
bool ppsRunning = false; // set when PPS start has been scheduled
volatile bool ppsActive = false;  // set when PPS is actuallt going (up to 1 second later)

volatile bool PPSHigh;
bool resync = false;
bool resyncDone = false;
uint32_t resyncPeriod;
bool OKToCheckSync = false;
volatile uint32_t VBOXTicks = 0; // time at the NEXT PPS edge
uint32_t lastPPSSecondStart;
volatile bool StopTCPListening = false;

#define _longPPMTrackLen_ 20
float PPMErrors[_longPPMTrackLen_];
float PPMTrackTotal;
int PPMTrackIndex;
float PPMHighAcc;
float remainingClockError;
bool ppmCorrection;

enum SerialOutput {mode_VIPS, mode_FreeD};
enum FIZFormats {formatPreston, formatFujiPassive, formatFujiActive, formatCanon, formatArri};

UserSettings_t UserSettings;

uint8_t FlexibleVIPSOut[200];
int VIPSOutSize;

struct D1MsgFormat_s fdPacket;

volatile bool EthTxNow = false;
Mutex NewData;

bool TXFrame = true;

// int pos_lower = 0;
// int pos_upper = 0;
// int pos_value = 0;

void filterOff(void)
{
    VIPS.EnableSmoothing(false);
    pc.puts("FilterTimeout");
}

/***************************
*
* Input format is
* enable filter $RLFIZ FILTER ON\n
* disable filter $RLFIZ FILTER OFF\n
*
* Filter mode auto exits after 30 seconds
*
****************************/

const int C1InputBufferSize = 20;
char C1InputBuffer[C1InputBufferSize];
int C1InputPtr = 0;

void parseC1Input(void)
{
    if (C1InputBuffer[1] != 'R')
        return;
    if (C1InputBuffer[2] != 'L')
        return;
    if (C1InputBuffer[3] != 'F')
        return;
    if (C1InputBuffer[4] != 'I')
        return;
    if (C1InputBuffer[5] != 'Z')
        return;

    if (C1InputBuffer[7] == 'F') {
        if (C1InputBuffer[8] != 'I')
            return;
        if (C1InputBuffer[9] != 'L')
            return;
        // 10 = T, 11 = E, 12=R, 13= space, 14 = O, 15 = N or F
        if (C1InputBuffer[14] != 'O')
            return;

        if (C1InputBuffer[15] == 'N') {
            VIPS.ForceSmoothing(true);
            filteringTimeout.attach(callback(&filterOff),30.0f);
            pc.puts("FilterOn\n");
            return;
        } else {
            VIPS.ForceSmoothing(false);
            filteringTimeout.detach();
            pc.puts("FilterOFF\n");
            return;
        }
    } // if F

}


void ExitBypass(void)
{
    VIPS.EnableBypass(false);
    bypassMode = false;
}


void vipsBypassRx(char byte)
{
    COM1.putc(byte);
}


void onOutputSerialRx(void)
{
    static bool got0x07 = false;
    led1=!led1;
    while (COM1.RawSerial::readable()) {
        if (bypassMode) {
            VIPS.bypassTx(COM1.RawSerial::getc());
            BypassTimeout.attach(&ExitBypass,5);
        } else {
            C1InputBuffer[C1InputPtr] = COM1.RawSerial::getc();
            pc.putc(C1InputBuffer[C1InputPtr]);
            if (C1InputPtr == 0) {
                if (got0x07) {
                    got0x07 = false;
                    if ((C1InputBuffer[0] >= 5) && (C1InputBuffer[0] <=11)) {
                        VIPS.bypassTx(0x07);
                        VIPS.bypassTx(C1InputBuffer[0]);
                        bypassMode = true;
                        BypassTimeout.attach(&ExitBypass,5);
                    }
                } else if (C1InputBuffer[0] == '$')
                    C1InputPtr = 1;
                else if (C1InputBuffer[0] == 0x07)
                    got0x07 = true;
            } else if (C1InputBuffer[C1InputPtr] == '\n') {
                parseC1Input();
                C1InputPtr = 0;
            } else {
                C1InputPtr++;
                if (C1InputPtr == C1InputBufferSize)
                    C1InputPtr = 0;
            }
        }
    }
}




void prepPacketOut()
{
    FlexibleVIPSOut[0]=0x24;
    FlexibleVIPSOut[1]=0xd9;
}

void onOutputTxTime(void)
{
    switch (UserSettings.SerialOutMode) {
        case mode_FreeD: {
            char *dataPtr = (char *)&fdPacket;
            for (int byte=0; byte<sizeof(struct D1MsgFormat_s); byte++)
                COM1.putc(*(dataPtr+byte));
        }
        break;
        case mode_VIPS:
        default: {
            char *dataPtr = (char *)FlexibleVIPSOut;
            for (int byte=0; byte<VIPSOutSize; byte++)
                COM1.putc(*(dataPtr+byte));
        }
        break;
    }
}

void createFreeDPacket(position *posPtr)
{
    if (posPtr) {
        fdPacket.header = 0xD1;
        fdPacket.id = 0xFF - posPtr->ID;
        set24bitValue(fdPacket.yaw, (int)(((posPtr->yaw > 180)? posPtr->yaw - 360 : posPtr->yaw) *32768)); ;
        set24bitValue(fdPacket.pitch, (int)(posPtr->pitch *32768));
        set24bitValue(fdPacket.roll, (int)(posPtr->roll *32768));
//        fdPacket.yaw = (int)(posPtr->yaw *32768);
//        fdPacket.pitch = (int)(posPtr->pitch *32768);
//        fdPacket.roll = (int)(posPtr->roll *32768);
        set24bitValue(fdPacket.x, (int)(posPtr->X *64000));
        set24bitValue(fdPacket.y, (int)(posPtr->Y *64000));
        set24bitValue(fdPacket.z, (int)(posPtr->Height *64000));
//        fdPacket.x = (int)(posPtr->X *64000);
//        fdPacket.y = (int)(posPtr->Y)*64000;
//        fdPacket.z = (int)(posPtr->Height *64000);
        if (posPtr->KFStatus < 0x200) {
            led2 = 0;
            RedLED = LED_ON;
        } else {
            led2 = 1;
            RedLED = LED_OFF;
        }
    } else {
        fdPacket.header = 0xD1;
        fdPacket.id = 0xFF - posPtr->ID;
        set24bitValue(fdPacket.yaw, 0);
        set24bitValue(fdPacket.pitch, 0);
        set24bitValue(fdPacket.roll, 0);
        set24bitValue(fdPacket.x, 0);
        set24bitValue(fdPacket.y, 0);
        set24bitValue(fdPacket.z, 0);
        led2 = 1;
        RedLED = LED_OFF;
    }
    uint32_t temp_focus;
    uint16_t temp_iris, temp_zoom; //can't directly address bitfield
    FIZPort->getMostRecent(&temp_focus, &temp_iris, &temp_zoom);
    set24bitValue(fdPacket.focus, temp_focus);
    set24bitValue(fdPacket.zoom, temp_zoom);
    fdPacket.checksum = GetFdCRC((void *)&fdPacket);
    //pc.puts("\r\n'");
}

void sendFreeDpacketSerial()
{
    if (UserSettings.SerialTxDelayMS > 0)
        OutputDelayTimer.attach_us(&onOutputTxTime,UserSettings.SerialTxDelayMS*1000);
    else
        onOutputTxTime();//    COM1.write(&packetOut, sizeof(struct outputFormat_s));

    if (logging) {
        if (!fwrite(&fdPacket, sizeof(struct D1MsgFormat_s), 1, logFile)) { // write failed
            GreenLED = LED_OFF;
            logging = false;
            fclose(logFile);
            logFile = NULL;
        }
    }
}


void createVIPSPacket(position *posPtr)
{

    int byteCount = 4;
    //uint32_t mask = 0x0446; // Status,orientation,accuracy,FIZ
    uint32_t mask = 0x0546; // Status,orientation,accuracy,FIZ,RAW_IMU
    if (posPtr && UserSettings.FlexibleVIPSOut) {
        if (posPtr->UsedBeaconsValid) {
            mask |= 0x1000;
        }
        if (posPtr->LLAPosition)
            mask |= 0x0001;
    }

    *((uint32_t*)(FlexibleVIPSOut + byteCount)) = mask;
    byteCount +=4;

    *((uint32_t*)(FlexibleVIPSOut + byteCount)) = movieTime.getTimeMS();
    byteCount +=4;

    if (posPtr) {
        *((double*)(FlexibleVIPSOut + byteCount)) = posPtr->X;
        byteCount +=8;
        *((double*)(FlexibleVIPSOut + byteCount)) = posPtr->Y;
        byteCount +=8;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->Height;
        byteCount +=4;
        FlexibleVIPSOut[byteCount++] = posPtr->beacons;
        FlexibleVIPSOut[byteCount++] = posPtr->solutionType;
        *((uint16_t*)(FlexibleVIPSOut + byteCount)) = posPtr->KFStatus;
        byteCount +=2;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->roll;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->pitch;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->yaw;
        byteCount +=4;
    } else {
        int blankBytes = 8+8+4+1+1+2+4+4+4;
        memset(FlexibleVIPSOut + byteCount,0,blankBytes);
        byteCount += blankBytes;
    }

    FlexibleVIPSOut[byteCount++] = 0;
    FlexibleVIPSOut[byteCount++] = 0;
    FlexibleVIPSOut[byteCount++] = 0;
    FlexibleVIPSOut[byteCount++] = posPtr?posPtr->ID:0;

   if (posPtr) {
            //RAWIMU
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->x_accel;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->y_accel;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->z_accel;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->x_gyro;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->y_gyro;
        byteCount +=4;
        *((float*)(FlexibleVIPSOut + byteCount)) = posPtr->z_gyro;
        byteCount +=4;
    }

    FIZPort->getMostRecent((uint32_t*)(FlexibleVIPSOut + byteCount), (uint16_t*)(FlexibleVIPSOut + byteCount+4), (uint16_t*)(FlexibleVIPSOut + byteCount+6));
    byteCount+=8;

    if (mask & 0x1000) { // pos must be valid for this to be set
        memcpy(FlexibleVIPSOut + byteCount,posPtr->UsedBeacons,12);
        byteCount+=12;
    }

    // set length to current size plus checksum.
    VIPSOutSize = byteCount+2;
    *((uint16_t*)(FlexibleVIPSOut + 2)) = VIPSOutSize;

    VIPSSerial::getCRC(FlexibleVIPSOut, byteCount, (void *)(FlexibleVIPSOut+byteCount));
}


void sendVIPSPacketSerial()
{
    if (UserSettings.SerialTxDelayMS > 0)
        OutputDelayTimer.attach_us(&onOutputTxTime,UserSettings.SerialTxDelayMS*1000);
    else
        onOutputTxTime();//    COM1.write(&packetOut, sizeof(struct outputFormat_s));

    if (logging) {
        if (!fwrite(FlexibleVIPSOut, VIPSOutSize, 1, logFile)) { // write failed
            GreenLED = LED_OFF;
            logging = false;
            fclose(logFile);
            logFile = NULL;
        }
    }
}

void UDP_Tx_Now()
{
    EthTxNow = true;
    NewData.unlock();
}

void applyOffsets(float *value, int offset, bool invert, int max_wrap)
{
    int min_wrap = max_wrap - 360;

    *value += offset;
    if (invert)
        *value = 360-*value;

    *value += 360-max_wrap;

    if (*value<min_wrap)
        *value+=((int)(*value/-360)+1)*360;
    if (*value>=max_wrap)
        *value-=((int)(*value/360))*360;

    *value -= 360-max_wrap;
}

void sendPosition(position *posPtr)
{
    NewData.lock();
    static bool NoDataWarn = true;
    if (!posPtr) {
        if (NoDataWarn) { // only warn once per dropout
            pc.puts("No VIPS Data\r\n");
            NoDataWarn = false;
        }
    } else
        NoDataWarn= true;

    if (posPtr) {
        applyOffsets(&posPtr->roll,  UserSettings.OffsetRoll,  UserSettings.InvertRoll, 180);
        applyOffsets(&posPtr->pitch, UserSettings.OffsetPitch, UserSettings.InvertPitch, 180);
        applyOffsets(&posPtr->yaw,   UserSettings.OffsetYaw,   UserSettings.InvertYaw, 360);
    }


// FreeD could be output by two different methods so calculate first if needed rather than at Tx.
    if ((UserSettings.SerialOutMode==mode_FreeD) || UserSettings.FreeDPort)
        createFreeDPacket(posPtr);

    if ((UserSettings.SerialOutMode==mode_VIPS) || UserSettings.VipsUDPPort || (UserSettings.DataOutPort && !UserSettings.FreeDPort))
        createVIPSPacket(posPtr);


// Network is faster so send that first.
    if (UserSettings.DataOutPort || UserSettings.VipsUDPPort) {
        if (UserSettings.UDPTxDelayMS > 0) {
            UDPOutputDelayTimer.attach_us(&UDP_Tx_Now,UserSettings.UDPTxDelayMS*1000);
        } else
            UDP_Tx_Now();
    }
    if (TXFrame) {

        switch (UserSettings.SerialOutMode) {
            case mode_FreeD:
                sendFreeDpacketSerial();
                break;
            case mode_VIPS:
            default:
                sendVIPSPacketSerial();
                break;
        }

        if (posPtr && (posPtr->KFStatus < 0x200)) {
            led2 = 0;
            RedLED = LED_ON;
        } else {
            led2 = 1;
            RedLED = LED_OFF;
        }

    }
    if (UserSettings.HalfRate) {
        TXFrame = !TXFrame;
    }
}


//called once per frame to output the current postition
void framePositionOutput()
{
    led3 = !led3;
    uint32_t outputTime = TimeSinceLastFrame.read_us() + UserSettings.InterpolationOffset_uS;
    TimeSinceLastFrame.reset();
    sendPosition(VIPS.sendPositionForTime(outputTime));
    FIZPort->requestCurrent();
}

int getNextFileNumber()
{

#ifdef enableUSBStick
    static unsigned int fileNbr = 0;
    char fileName[32];
    FILE *filePtr = NULL;
    pc.puts("DiskInit\r\n");
    if (!msc.disk_initialize()) {
        pc.puts("DiskInit failed/r/n");
        return fileNbr;
    }

    do {
        if (filePtr != NULL)
            fclose(filePtr);
        pc.printf("Looking to see if %d exists\r\n",fileNbr);
        sprintf(fileName,"/msc/VIPS%04u.bin",fileNbr);
        filePtr = fopen(fileName,"rb");
        if (filePtr) fileNbr++;
    } while (filePtr != NULL);
    pc.puts("File not found\r\n");
    return fileNbr;
#else
    return 0;
#endif
}

FILE *nextBinaryFile(void)
{
#ifdef enableUSBStick
//   pc.puts("DiskInit\r\n");
//   int initResult = msc.disk_initialize();
//   pc.printf("Init returned %d\r\n",initResult);

//   if (msc.disk_initialize()==) {
//       pc.puts("DiskInit failed/r/n");
//       return NULL;
//   }
    char fileName[32];
    int file = getNextFileNumber();
    sprintf(fileName,"/msc/VIPS%04u.bin",file);
//   pc.printf("Opending output file %s\r\n",fileName);
    return fopen(fileName,"wb");
#else
    pc.puts("Disk support disabled\r\n");
    return NULL;
#endif
}


volatile bool NewFramePulse= false;
volatile int framesIn = 0;
void OnPPFInputStartup(void)
{
    framesIn++;
}

volatile int SyncInCount = 0;
void OnSyncInputStartup(void)
{
    SyncInCount++;
}


void OnPPFInput(void)
{
    frameToggle=!frameToggle;
    movieTime.nextFrame();
    NewFramePulse = true;
}

void OnResetTimeout()
{
    __disable_irq();
    led1=1;
    led2=1;
    led3=1;
    frameToggle=1;
    RedLED=1; // red
    GreenLED=1;
    BlueLED=1;
    wait(1);
    NVIC_SystemReset();
}

void readLensFile(char* filename)
{
    FILE *LensFile = fopen(filename,"r");
    if (LensFile) {
        char chunk[64];
        size_t len = sizeof(chunk);
        char *line = new char[len];
        pc.printf("Opened File %s\r\n", filename);
<<<<<<< working copy
        vector<int> *encoder;
        vector<float> *absolute;
=======
        vector<unsigned int> *encoder;
        vector<unsigned int> *absolute;
>>>>>>> merge rev
        int focus_datapoints;
        int iris_datapoints;
        int zoom_datapoints;

        while(fgets(chunk, sizeof(chunk), LensFile) != NULL) {
            size_t len_used = strlen(line);
            size_t chunk_used = strlen(chunk);

            if(len - len_used < chunk_used) {
                pc.printf("Line Buffer Exceeded - Failed to read file");
                free(line);
                return;
            }

            strncpy(line + len_used, chunk, len - len_used);
            len_used += chunk_used;
            if(line[len_used - 1] == '\n') {
<<<<<<< working copy
                pc.printf("Retrieved line of length %u: ", len_used);
                pc.printf("%s\n", line);
                if (sscanf(line,"FOCUS:%d", &focus_datapoints) == 1) {
                    encoder = &UserSettings.focus_encoder_map;
                    absolute = &UserSettings.focus_absolute_map;
                    printf("\tSet Focus\n");
                } else if (sscanf(line,"IRIS:%d", &iris_datapoints) == 1) {
                    encoder = &UserSettings.iris_encoder_map;
                    absolute = &UserSettings.iris_absolute_map;
                    printf("\tSet Iris\n");
                } else if (sscanf(line,"ZOOM:%d", &zoom_datapoints) == 1) {
                    encoder = &UserSettings.zoom_encoder_map;
                    absolute = &UserSettings.zoom_absolute_map;
                    printf("\tSet Zoom\n");
                } else if (strchr(line,',') != NULL) {
                    pc.printf("\tProbably some data in this line\n");
                    int encoder_val;
                    float absolute_val;
                    char *pt = strtok (line,",");
                    if (pt) {
                        encoder_val = atoi(pt);
                        printf("\tENCODER: %d\n", encoder_val);
                    }
                    pt = strtok(line, ",");
                    if (pt) {
                        absolute_val = (float)atof(pt);
                        printf("\tABSOLUTE: %f\n", absolute_val);
                    }
                    if (encoder_val != NULL && absolute_val != NULL) {
                        encoder->push_back(encoder_val);
                        absolute->push_back(absolute_val);
                        printf("\tADDED Datapoint\n");
                    }
                } else {
                    printf("\tNot Valid matching line\n");
                    }
=======
                // pc.printf("Retrieved line of length %u: ", len_used);
                // pc.printf("%s", line);
                // Thread::wait(10);
                if (sscanf(line,"FOCUS:%d", &focus_datapoints) == 1) {
                    encoder = &UserSettings.focus_encoder_map;
                    absolute = &UserSettings.focus_absolute_map;
                    UserSettings.absolute_focus = true;
                    // pc.printf(" - Set Focus\r\n");
                    // Thread::wait(10);
                } else if (sscanf(line,"IRIS:%d", &iris_datapoints) == 1) {
                    encoder = &UserSettings.iris_encoder_map;
                    absolute = &UserSettings.iris_absolute_map;
                    UserSettings.absolute_iris = true;
                    // pc.printf(" - Set Iris\r\n");
                    // Thread::wait(10);
                } else if (sscanf(line,"ZOOM:%d", &zoom_datapoints) == 1) {
                    encoder = &UserSettings.zoom_encoder_map;
                    absolute = &UserSettings.zoom_absolute_map;
                    UserSettings.absolute_zoom = true;
                    // pc.printf(" - Set Zoom\r\n");
                    // Thread::wait(10);
                } else if (strchr(line,',') != NULL) {
                    // pc.printf("\tProbably some data in this line\n");
                    unsigned int encoder_val;
                    unsigned int absolute_val;
                    if (sscanf(line, "%d,%d", &encoder_val, &absolute_val) == 2) {
                        encoder->push_back(encoder_val);
                        absolute->push_back(absolute_val);
                        // pc.printf(" - ADDED Datapoint\r\n");
                        // Thread::wait(10);
                    }
                } // else { pc.printf(" - Not Valid matching line\r\n"); }
>>>>>>> merge rev
            line[0] = '\0';
            }
        }
        pc.printf("FOCUS: ");
        for(int i = 0; i < UserSettings.focus_encoder_map.size(); i++) {
            pc.printf("(%d, ", UserSettings.focus_encoder_map[i]);
            pc.printf("%d)", UserSettings.focus_absolute_map[i]);
        }
        pc.printf("\r\n");
        pc.printf("IRIS: ");
        for(int i = 0; i < UserSettings.iris_encoder_map.size(); i++) {
            pc.printf("(%d, ", UserSettings.iris_encoder_map[i]);
            pc.printf("%d)", UserSettings.iris_absolute_map[i]);
        }
        pc.printf("\r\n");
        pc.printf("ZOOM: ");
        for(int i = 0; i < UserSettings.zoom_encoder_map.size(); i++) {
            pc.printf("(%d, ", UserSettings.zoom_encoder_map[i]);
            pc.printf("%d)", UserSettings.zoom_absolute_map[i]);
        }
        pc.printf("\r\n");
        fclose(LensFile);
        free(line);
    } else {
        pc.printf("Unable to open File %s\r\n", filename);
    }
}

void readSettingsFile()
{

    UserSettings.FIZmode = formatPreston;
    UserSettings.SerialOutMode = mode_VIPS;
    UserSettings.FreeDPort = 0;
    UserSettings.DataOutPort = 0;
    UserSettings.VipsUDPPort = 0;
    UserSettings.SettingsPort = 0;
    UserSettings.IPAddress[0] = 0;
    UserSettings.Gateway[0] = 0;
    UserSettings.Subnet[0] = 0;
    UserSettings.FilterOrder = 0;
    UserSettings.FilterFreq = 10;
    UserSettings.FilterRate = 100;
    UserSettings.FilterXY = false;
    UserSettings.FilterZ = false;
    UserSettings.FilterRoll = false;
    UserSettings.FilterPitch = false;
    UserSettings.FilterYaw = false;
    UserSettings.AutoHyperSmooth = true;
    UserSettings.FlexibleVIPSOut = false;
    UserSettings.SerialTxDelayMS = 0;
    UserSettings.UDPTxDelayMS = 0;
    UserSettings.SerialTxDelayFrame = 0;
    UserSettings.UDPTxDelayFrame = 0;
    UserSettings.InterpolationOffsetFrame = 0;
    UserSettings.InterpolationOffset_uS = 0;
    UserSettings.InvertRoll = false;
    UserSettings.InvertPitch = false;
    UserSettings.InvertYaw = false;
    UserSettings.OffsetRoll =0;
    UserSettings.OffsetPitch =0;
    UserSettings.OffsetYaw =0;
    UserSettings.bypassBaud = 0;
    UserSettings.ForcePPF = 0;
    UserSettings.HalfRate = 0;
    UserSettings.focus_scale= 1;
    UserSettings.focus_offset = 0;
    UserSettings.iris_scale = 1;
    UserSettings.iris_offset = 0;
    UserSettings.zoom_scale = 1;
    UserSettings.zoom_offset= 0;
    UserSettings.low_zoom_precision = false; //TODO: Get zoom range from lens file, if over 327mm, set this flag (and set top bit in zoom output)
    UserSettings.absolute_focus = false;
    UserSettings.absolute_iris = false;
    UserSettings.absolute_zoom = false;

//    LocalFileSystem localFS("local");
    FILE *LSFile= fopen("/local/settings.txt","r");
    char lineBuffer[128];
    int valueIn;
    float floatIn;
    char lensfile[128] = "/local/";//7 characters for filepath, minus 12 chars of settings string, hence 128 shouldnt cause buffer overflow
    /*MAXIMUM FILENAME LENGTH IS 8 Characters*/

    if (LSFile) {
        while (!feof(LSFile) && !UserSettings.bypassBaud) {
            if (fgets(lineBuffer, 128, LSFile)) {
                if (sscanf(lineBuffer,"RadioConfigPassthrough=%d",&valueIn) == 1) {
                    pc.printf("Switching to RADIO/USB bypass mode at %d baud\r\n",valueIn);
                    UserSettings.bypassBaud = valueIn;
                }

                if (sscanf(lineBuffer,"Output_Format=%d",&valueIn) == 1) {
                    pc.printf("Got Output_Format value from file of %d\r\n",valueIn);
                    UserSettings.SerialOutMode = valueIn;
                }
                if (sscanf(lineBuffer,"FIZ_Format=%d",&valueIn) == 1) {
                    pc.printf("Got FIZ_Format value from file of %d\r\n",valueIn);
                    UserSettings.FIZmode = valueIn;
                }
                if (sscanf(lineBuffer,"FreeD_Port=%d",&valueIn) == 1) {
                    pc.printf("Got FreeD_Port value from file of %d\r\n",valueIn);
                    UserSettings.FreeDPort = valueIn;
                    UserSettings.DataOutPort = valueIn;
                }
                if (sscanf(lineBuffer,"FreeD_Mode=%d",&valueIn) == 1) {
                    pc.printf("Got FreeD_Mode value from file of %d\r\n",valueIn);
                    UserSettings.FreeDPort = valueIn;
                }
                if (sscanf(lineBuffer,"DataOut_Port=%d",&valueIn) == 1) {
                    pc.printf("Got DataOut_Port value from file of %d\r\n",valueIn);
                    UserSettings.DataOutPort = valueIn;
                }
                if (sscanf(lineBuffer,"VIPS_UDP_Port=%d",&valueIn) == 1) {
                    pc.printf("Got VIPS_Port value from file of %d\r\n",valueIn);
                    UserSettings.VipsUDPPort = valueIn;
                }
                if (sscanf(lineBuffer,"Settings_Port=%d",&valueIn) == 1) {
                    pc.printf("Got Settings update port value from file of %d\r\n",valueIn);
                    UserSettings.SettingsPort = valueIn;
                }
                if (sscanf(lineBuffer,"IP_addr=%s",UserSettings.IPAddress) == 1) {
                    pc.printf("Got IP_addr value from file of %s\r\n",UserSettings.IPAddress);
                }
                if (sscanf(lineBuffer,"Subnet=%s",UserSettings.Subnet) == 1) {
                    pc.printf("Got Subnet mask value from file of %s\r\n",UserSettings.Subnet);
                }
                if (sscanf(lineBuffer,"Gateway=%s",UserSettings.Gateway) == 1) {
                    pc.printf("Got gateway value from file of %s\r\n",UserSettings.Gateway);
                }
                if (sscanf(lineBuffer,"FilterOrder=%d",&valueIn) == 1) {
                    pc.printf("Got FilterOrder value from file of %d\r\n",valueIn);
                    UserSettings.FilterOrder = valueIn;
                }
                if (sscanf(lineBuffer,"FilterFreq=%f",&floatIn) == 1) {
                    pc.printf("Got FilterFreq value from file of %.2f\r\n",floatIn);
                    UserSettings.FilterFreq = floatIn;
                }
                if (sscanf(lineBuffer,"FilterRate=%f",&floatIn) == 1) {
                    pc.printf("Got FilterRate value from file of %.2f\r\n",floatIn);
                    UserSettings.FilterRate = floatIn;
                }
                if (sscanf(lineBuffer,"FilterXY=%d",&valueIn) == 1) {
                    pc.printf("Got FilterXY value from file of %d\r\n",valueIn);
                    UserSettings.FilterXY = (valueIn==1);
                }
                if (sscanf(lineBuffer,"FilterZ=%d",&valueIn) == 1) {
                    pc.printf("Got FilterZ value from file of %d\r\n",valueIn);
                    UserSettings.FilterZ = (valueIn==1);
                }
                if (sscanf(lineBuffer,"FilterRoll=%d",&valueIn) == 1) {
                    pc.printf("Got FilterRoll value from file of %d\r\n",valueIn);
                    UserSettings.FilterRoll = (valueIn==1);
                }
                if (sscanf(lineBuffer,"FilterPitch=%d",&valueIn) == 1) {
                    pc.printf("Got FilterPitch value from file of %d\r\n",valueIn);
                    UserSettings.FilterPitch = (valueIn==1);
                }
                if (sscanf(lineBuffer,"FilterYaw=%d",&valueIn) == 1) {
                    pc.printf("Got FilterYaw value from file of %d\r\n",valueIn);
                    UserSettings.FilterYaw = (valueIn==1);
                }
                if (sscanf(lineBuffer,"AutoHyperSmooth=%d",&valueIn) == 1) {
                    pc.printf("Got AutoHyperSmooth value from file of %d\r\n",valueIn);
                    UserSettings.AutoHyperSmooth = (valueIn==1);
                }
                if (sscanf(lineBuffer,"ExtendedOutput=%d",&valueIn) == 1) {
                    pc.printf("Got ExtendedOutput value from file of %d\r\n",valueIn);
                    UserSettings.FlexibleVIPSOut = (valueIn==1);
                }
                if (sscanf(lineBuffer,"DelaySerial=%f",&floatIn) == 1) {
                    pc.printf("Got serial delay value from file of %.2f ms\r\n",floatIn);
                    UserSettings.SerialTxDelayMS = floatIn;
                }
                if (sscanf(lineBuffer,"DelaySerialFrame=%f",&floatIn) == 1) {
                    pc.printf("Got serial delay value from file of %.2f frames\r\n",floatIn);
                    UserSettings.SerialTxDelayFrame = floatIn;
                }
                if (sscanf(lineBuffer,"DelayUDP=%f",&floatIn) == 1) {
                    pc.printf("Got UDP delay value from file of %.2f ms\r\n",floatIn);
                    UserSettings.UDPTxDelayMS = floatIn;
                }
                if (sscanf(lineBuffer,"DelayUDPFrame=%f",&floatIn) == 1) {
                    pc.printf("Got UDP delay value from file of %.2f frames\r\n",floatIn);
                    UserSettings.UDPTxDelayFrame = floatIn;
                }
                if (sscanf(lineBuffer,"ShiftInterpolationByFrame=%f",&floatIn) == 1) {
                    pc.printf("Got Interpolation Offset %.2f frames\r\n",floatIn);
                    UserSettings.InterpolationOffsetFrame = floatIn;
                }
                if (sscanf(lineBuffer,"ShiftInterpolationByTimeMs=%f",&floatIn) == 1) {
                    pc.printf("Got Interpolation offset of %.2f ms\r\n",floatIn);
                    UserSettings.InterpolationOffset_uS = floatIn * 1000;
                }
                if (sscanf(lineBuffer,"InvertRoll=%d",&valueIn) == 1) {
                    pc.printf("Got InvertRoll value from file of %d\r\n",valueIn);
                    UserSettings.InvertRoll = (valueIn==1);
                }
                if (sscanf(lineBuffer,"InvertPitch=%d",&valueIn) == 1) {
                    pc.printf("Got InvertPitch value from file of %d\r\n",valueIn);
                    UserSettings.InvertPitch = (valueIn==1);
                }
                if (sscanf(lineBuffer,"InvertYaw=%d",&valueIn) == 1) {
                    pc.printf("Got InvertYaw value from file of %d\r\n",valueIn);
                    UserSettings.InvertYaw = (valueIn==1);
                }
                if (sscanf(lineBuffer,"OffsetRoll=%d",&valueIn) == 1) {
                    pc.printf("Got OffsetRoll value from file of %d\r\n",valueIn);
                    UserSettings.OffsetRoll = valueIn;
                }
                if (sscanf(lineBuffer,"OffsetPitch=%d",&valueIn) == 1) {
                    pc.printf("Got OffsetPitch value from file of %d\r\n",valueIn);
                    UserSettings.OffsetPitch = valueIn;
                }
                if (sscanf(lineBuffer,"OffsetYaw=%d",&valueIn) == 1) {
                    pc.printf("Got OffsetYaw value from file of %d\r\n",valueIn);
                    UserSettings.OffsetYaw = valueIn;
                }
                if (sscanf(lineBuffer,"ForcePPF=%d",&valueIn) == 1) {
                    pc.printf("Using Forced PPF\r\n",valueIn);
                    UserSettings.ForcePPF = valueIn;
                }
                if (sscanf(lineBuffer,"HalfSerialRate=%d",&valueIn) == 1) {
                    pc.printf("Halving Serial rate output \r\n",valueIn);
                    UserSettings.HalfRate = valueIn;
                }
                if (sscanf(lineBuffer,"FocusScale=%f",&floatIn) == 1) {
                    pc.printf("Got Focus scale of %f \r\n",floatIn);
                    UserSettings.focus_scale = floatIn;
                }
                if (sscanf(lineBuffer,"FocusOffset=%f",&floatIn) == 1) {
                    pc.printf("Got Focus offset of %f \r\n",floatIn);
                    UserSettings.focus_offset = floatIn;
                }
                if (sscanf(lineBuffer,"IrisScale=%f",&floatIn) == 1) {
                    pc.printf("Got Iris scale of %f \r\n",floatIn);
                    UserSettings.iris_scale = floatIn;
                }
                if (sscanf(lineBuffer,"IrisOffset=%f",&floatIn) == 1) {
                    pc.printf("Got Iris offset of %f \r\n",floatIn);
                    UserSettings.iris_offset = floatIn;
                }
                if (sscanf(lineBuffer,"ZoomScale=%f",&floatIn) == 1) {
                    pc.printf("Got Zoom Scale of %f \r\n",floatIn);
                    UserSettings.zoom_scale = floatIn;
                }
                if (sscanf(lineBuffer,"ZoomOffset=%f",&floatIn) == 1) {
                    pc.printf("Got Zoom offset of %f \r\n",floatIn);
                    UserSettings.zoom_offset = floatIn;
                }
                if (sscanf(lineBuffer,"LensProfile=%s", &lensfile[7]) == 1) {
                    pc.printf("Found filename of %s \r\n", lensfile);
                }

            }
        }
        fclose(LSFile);
        readLensFile(lensfile);
    } else {
        pc.printf("No Settings File Found \r\n");
    }
}


void settingsNetUpdate(void const* netInterface)
{
    //FILE *LSFile;
    const int rxBufferSize = MaxBuffSize; // making this 1024 causes a crash. Probably out of memory somewhere.
    //char settingsOutBuffer[rxBufferSize];
    char settingsInBuffer[rxBufferSize];
    int bytesToSend = 0;
    unsigned char *bufferToSend;
    bool validated_connection = false;

    Thread::wait(1000);
    pc.puts("Starting TCP network listen server\r\n");
    Thread::wait(50);


//    int fileSize = 0;
    TCPSocketServer server;
    server.bind(UserSettings.SettingsPort);
    server.set_blocking(false, 1000);
    server.listen();

    TCPSocketConnection connection;
    pc.puts("TCP thread waiting for connection\r\n");

    while (!StopTCPListening) {
        server.accept(connection);
        if (connection.is_connected()) {
            pc.puts("TCP Connected\r\n");
            connection.set_blocking(false,50);

            int bytesIn = 0;
            do {
                bytesIn = connection.receive(settingsInBuffer,rxBufferSize);
                if (bytesIn > 0) {
                    if (!validated_connection) {
                        printf("Recieved %d bytes on unvalidated connection\r\n",bytesIn);
                        if ((settingsInBuffer[0] == 0x07) &&
                                (settingsInBuffer[1] == 0x05) &&
                                (settingsInBuffer[2] == 0x02)) {
                            validated_connection = true;
                            printf("Validated Connection - Sending 'set quiet' command\r\n");
                            VIPS.sendQuiet();
                            Thread::wait(50);
                            VIPS.EnableDirectTX(true);
                            GreenLED = LED_ON;
                            VIPS.sendDirectTX((unsigned char *)settingsInBuffer, bytesIn);
                            printf("Sent first %d bytes to VIPS\r\n",bytesIn); //also a set-quiet command but good to send twice
                        } else {
                            printf("Invalid: %X %X %X", settingsInBuffer[0], settingsInBuffer[1], settingsInBuffer[2]);
                        }
                    } else if (validated_connection) {
                        VIPS.sendDirectTX((unsigned char *)settingsInBuffer, bytesIn);
                        printf("Sent %d bytes to VIPS\r\n",bytesIn);
                    }
                }
                if (VIPS.getWaitingBuffer(&bufferToSend, &bytesToSend)) {
                    connection.send((char *)bufferToSend, bytesToSend);
                    printf("Recieved %d bytes from VIPS\r\n",bytesIn);
                }
            } while (connection.is_connected());

            VIPS.EnableDirectTX(false);
            GreenLED = LED_OFF;
            validated_connection = false;
            pc.puts("Disconnected TCP \r\n");
            connection.close();
            Thread::wait(50);
        }
    }
    VIPS.EnableDirectTX(false);
    GreenLED = LED_OFF;
    pc.puts("Ending TCP Task\r\n");
}


void ethernetTask(void const* settings)
{

    Thread* ListenTask=NULL;
    UDPSocket* PrimaryDataSocket = NULL;
    Endpoint PrimaryDataTarget;

    UDPSocket* VIPSSocket = NULL;
    Endpoint VIPSTarget;

    UserSettings_t *settingsPtr = (UserSettings_t *) settings;

    pc.puts("Ethernet task startup\r\n");
    if (!settingsPtr->DataOutPort && !settingsPtr->VipsUDPPort && !settingsPtr->SettingsPort) {
        pc.puts("No ports set. Ethernet task exiting\r\n");
        return;
    }
    int Result = -1;
    while (Result != 0) {
        if ((UserSettings.IPAddress[0] != 0) && (UserSettings.Gateway[0] != 0) && (UserSettings.Subnet[0] != 0)) {
            pc.puts("Static IP init attempt\r\n");
            Result = eth.init(UserSettings.IPAddress, UserSettings.Subnet, UserSettings.Gateway);
        } else {
            pc.puts("Dynamic IP init attempt\r\n");
            Result = eth.init();
        }

        if (Result) {
            pc.puts("Ethernet init failed\r\n");
            Thread::wait(500);
        }
    }
    pc.puts("Ethernet init complete\r\n");

    while (true) {

        Result = -1;
        while (Result != 0) {
            Result = eth.connect();
            if (Result) {
                pc.puts("Ethernet connect failed\r\n");
                Thread::wait(500);
            }
        }
        pc.puts("Ethernet connect complete\r\n");
        Thread::wait(100);
        printf("IP Address is %s\r\n", eth.getIPAddress());
        if (ListenTask)
            delete ListenTask;
        if (settingsPtr->SettingsPort) {
            pc.puts("Starting network update task\r\n");
            Thread::wait(100);
            StopTCPListening = false;
            ListenTask = new Thread(settingsNetUpdate, NULL, osPriorityHigh, 256 * 4);
        }
        if (PrimaryDataSocket)
            delete PrimaryDataSocket;
        if (UserSettings.DataOutPort) {
            pc.printf("Starting Primary data socket - %s\r\n", (UserSettings.FreeDPort ? "FreeD Output Mode" : "VIPS Output Mode"));
            Thread::wait(50);
            PrimaryDataSocket = new UDPSocket();
            PrimaryDataSocket->init();
            PrimaryDataSocket->set_broadcasting(true);
            PrimaryDataTarget.set_address(0xFFFFFFFF, UserSettings.DataOutPort);
            int option = (1);
            int tos_option = (IPTOS_LOWDELAY|IPTOS_THROUGHPUT|IPTOS_PREC_IMMEDIATE);
//            PrimaryDataSocket->get_option(IPPROTO_IP, IP_TOS, &option, sizeof(option))
//            pc.printf("Socket IPTOS Option: %d\r\n", option);
            PrimaryDataSocket->set_option(IPPROTO_IP, IP_TOS, &tos_option, sizeof(option));
//            PrimaryDataSocket->set_option(IPPROTO_TCP, TCP_NODELAY, &option, sizeof(option));
//            PrimaryDataSocket->set_option(SOL_SOCKET, SO_NO_CHECK, &option, sizeof(option));

        }

        if (VIPSSocket)
            delete VIPSSocket;
        if (UserSettings.VipsUDPPort) {
            pc.puts("Starting VIPS socket\r\n");
            Thread::wait(50);
            VIPSSocket = new UDPSocket();
            VIPSSocket->init();
            VIPSSocket->set_broadcasting(true);
            VIPSTarget.set_address(0xFFFFFFFF, UserSettings.VipsUDPPort);
        }
        EthernetTimer.reset();
        EthernetTimer.start();
        pc.puts("Network ready for TX\r\n");
        Thread::wait(50);
        while (true) {
            if (EthTxNow) {
//                NewData.lock();
                EthTxNow = false;
                if (!PrimaryDataSocket && UserSettings.DataOutPort) {
                    pc.puts("No FreeD UDP socket\r\n");
                    break;
                }
                if (!VIPSSocket && UserSettings.VipsUDPPort) {
                    pc.puts("No VIPS UDP socket\r\n");
                    break;
                }
                if (PrimaryDataSocket) {
                    if (UserSettings.FreeDPort)
                        Result = PrimaryDataSocket->sendTo(PrimaryDataTarget,(char *)&fdPacket, sizeof(struct D1MsgFormat_s));
                    else
                        Result = PrimaryDataSocket->sendTo(PrimaryDataTarget,(char *)FlexibleVIPSOut, VIPSOutSize);
                    //uint32_t ethtime = EthernetTimer.read_us();
                    //EthernetTimer.reset();
                    int expected_size = UserSettings.FreeDPort ? sizeof(struct D1MsgFormat_s) :  VIPSOutSize;
                    if (Result != expected_size) {
                        pc.puts("Primary Port UDP Tx Failed!\r\n");
                        break;
                    } //else
                    //pc.printf("%d\r\n", ethtime);
                }
                if (VIPSSocket) {
                    Result = VIPSSocket->sendTo(VIPSTarget,(char *)FlexibleVIPSOut, VIPSOutSize);
                    if (Result != VIPSOutSize) {
                        pc.puts("VIPS UDP Tx Failed!\r\n");
                        break;
                    }
                }
//                pc.puts("UDP Tx\r\n");
            } else
//                NewData.unlock();
                Thread::wait(1);
        }
        StopTCPListening = true;
        Thread::wait(1);

        while (ListenTask->get_state()) {
            Thread::wait(50);
        }
//        int ListenState = ListenTask->get_state();
//        pc.printf("Listen State: %d\r\n", ListenState);

        eth.disconnect();
        pc.puts("Attempting to restart network\r\n");
    }
    pc.puts("Eth Task ending. Should never happen!\r\n");
}


void XBEEBypassmode(int baud)
{
    pc.baud(baud);

    /*
        COM1.baud(9600);
        COM1.puts("+++");
        wait(1.2);
        switch (baud) {
            case 1200:
                COM1.puts("ATBD0\n");
                break;
            case 2400:
                COM1.puts("ATBD1\n");
                break;
            case 4800:
                COM1.puts("ATBD2\n");
                break;
            case 9600:
                COM1.puts("ATBD3\n");
                break;
            case 19200:
                COM1.puts("ATBD4\n");
                break;
            case 38400:
                COM1.puts("ATBD5\n");
                break;
            case 57600:
                COM1.puts("ATBD6\n");
                break;
            case 115200:
                COM1.puts("ATBD7\n");
                break;
            default:
                COM1.printf("ATBD%d\n",baud);
                break;
        }

        wait(0.1);
        COM1.puts("ATCN\n");
        wait(0.5);
    */

    COM1.baud(baud);
    while (true) {
        if (pc.readable()) {
            char commandIn = pc.getc();
            COM1.putc(commandIn);
        }
        if (COM1.readable())
            pc.putc(COM1.getc());
    }
}

int main()
{
    pc.baud(115200);
    pc.printf("\r\n\r\nStartup - v%.3f\r\n", APP_VERSION); //Change via Line 1
    setRED();

    readSettingsFile();

    if (UserSettings.bypassBaud) {
        XBEEBypassmode(UserSettings.bypassBaud);
    }

    switch(UserSettings.FIZmode) {
        case formatPreston :
            FIZPort = new FIZDisney(p9, p10);
            pc.printf("Set Preston");
            break;
        case formatFujiPassive :
            FIZPort = new FIZDigiPower(p9, p10);
            pc.printf("Set FujiPassive");
            break;
        case formatFujiActive :
            FIZPort = new FIZDigiPowerActive(p9, p10);
            pc.printf("Set FujiActive\r\n");
            break;
        case formatCanon :
            FIZPort = new FIZCanon(p9, p10);
            pc.printf("Set Canon\r\n");
            break;
        case formatArri:
            FIZPort = new FIZ_ArriCmotion(p9, p10);
            pc.printf("Set Arri\r\n");
            break;
        default:
            FIZPort = new FIZDisney(p9, p10); //preston
            pc.printf("Set Default - Preston");

    }
//    FIZPort = new FIZDigiPowerActive(p9, p10);
    COM1.baud(115200); // radio port

    Thread ethernetThread(ethernetTask, &UserSettings, osPriorityHigh, 256 * 4);
    led1 = 0;
    inputTimer.reset();
    inputTimer.start();

    prepPacketOut();

    LTCInput.enable(true);

    if (!VIPS.setFilters(&UserSettings))
        pc.puts("Failed to create VIPS filters\r\n");

    VIPS.run();

    pc.printf("System init complete\r\n");
    setBLUE();
    COM1.attach(&onOutputSerialRx);

    TimeSinceLastFrame.reset();
    TimeSinceLastFrame.start();


    pc.printf("Waiting for sync input clock\r\n");

#ifdef enableFakePPF
    FakePPF.attach(callback(&OnPPFInputStartup),1/50.0);
#endif

    PPFin.rise(callback(&OnPPFInputStartup));
    Syncin.rise(callback(&OnSyncInputStartup));
    framesIn = 0;
    SyncInCount = 0;
    bool LockToSync = false;

    while (true) {
        if (SyncInCount == 100) {
            LockToSync= true;
            break;
        }
        if ((framesIn == 100) && (SyncInCount<45)) { // prefer frame sync
            break;
        }
    }

    if (LockToSync && !UserSettings.ForcePPF) {
        pc.printf("Using Genlock sync input\r\n");
        Syncin.rise(callback(&OnPPFInputStartup));
        PPFin.rise(NULL);
    } else {
        pc.printf("Using pulse per frame input\r\n");
        Syncin.rise(NULL);
    }

    setGREEN();
    pc.printf("Measuring frame rate\r\n");

    int currentFrames = framesIn;
    while (framesIn == currentFrames);  // wait for next frame;
    inputTimer.reset();
    framesIn = 0;


    while (framesIn < 100);  // wait for 100 frames;
    uint32_t frameTime = inputTimer.read_us()/100;

    int framesPerSecond = frameRates::getClosestRate(frameTime);

    pc.printf("Detected frame rate %d\r\n",framesPerSecond);
    if (UserSettings.SerialTxDelayFrame != 0) {
        UserSettings.SerialTxDelayMS = (UserSettings.SerialTxDelayFrame*1000)/framesPerSecond;
        pc.printf("Serial delay of %.2f frames calculated as %.2f ms\r\n",UserSettings.SerialTxDelayFrame,UserSettings.SerialTxDelayMS);
    }
    if (UserSettings.UDPTxDelayFrame != 0) {
        UserSettings.UDPTxDelayMS = (UserSettings.UDPTxDelayFrame*1000)/framesPerSecond;
        pc.printf("Serial delay of %.2f frames calculated as %.2f ms\r\n",UserSettings.UDPTxDelayFrame,UserSettings.UDPTxDelayMS);
    }
    if (UserSettings.InterpolationOffsetFrame != 0) {
        UserSettings.InterpolationOffset_uS = (UserSettings.InterpolationOffsetFrame*1000000)/framesPerSecond;
        pc.printf("Interpolation Delay of %.2f frames calculated as %.2f ms\r\n", UserSettings.InterpolationOffsetFrame,UserSettings.InterpolationOffset_uS);
    }

    if (LTCInput.synced()) { // getting LTC so set the clock.
        currentFrames = framesIn;
        while (framesIn == currentFrames);  // wait for next frame;
        wait_us (frameTime/4); // ensure the LTC decode for the last frame is done.
        int hour,minute,second,frame;
        bool drop = LTCInput.isFrameDrop();
        LTCInput.getTime(&hour,&minute,&second,&frame);
        movieTime.setMode(framesPerSecond,drop);
        movieTime.setTime(hour,minute,second,frame);
    } else { // no time code so clock time doesn't matter
        movieTime.setMode(framesPerSecond,false);
    }

    if (LockToSync)
        Syncin.rise(callback(&OnPPFInput));
    else
        PPFin.rise(callback(&OnPPFInput));

#ifdef enableFakePPF
    FakePPF.attach(callback(&OnPPFInput),1/50.0);
#endif

    pc.printf("Current time is %02d:%02d:%02d %02d\r\n",movieTime.hours(),movieTime.minutes(),movieTime.seconds(),movieTime.frame());
    LTCInput.enable(false);
    setOFF();

    pc.printf("Running\r\n",framesPerSecond);


    getNextFileNumber();
    COM1.attach(callback(onOutputSerialRx));


    while (true) {
        if (NewFramePulse) { // New frame. Output data.
            //framePulse(FramePulseTime);
            NewFramePulse = false;
            framePositionOutput();
        }
        VIPS.sendQueued(); // should ideally be called on 100Hz PPS edge but we don't have that in this code...

        // if (pos_value) {
        //     pc.printf("Z: %d - (%d, %d)\r\n", pos_value, pos_lower, pos_upper);
        //     pos_value = 0;
        // }

        if (logButtonLastState != logButton) {
            logButtonLastState = logButton;
            if (logButtonLastState) { // pressed
                logButtonDownTime = inputTimer.read();
                if ((logButtonDownTime - logButtonUpTime) > 0.2f) {
//                    pc.puts("Down\r\n");
                    resetTimeout.attach(callback(&OnResetTimeout),5);
                    if (logging) {
                        //           pc.puts("Logging off\r\n");
                        GreenLED = LED_OFF;
                        logging=false;
                        fclose(logFile);
                    } else {
                        logFile = nextBinaryFile();
                        if(logFile) {
                            //                pc.puts("Logging on\r\n");
                            GreenLED = LED_ON;
                            logging = true;
                        }
                        //else         pc.puts("Logging failed\r\n");
                    }
                }
            } else { // released
                logButtonUpTime = inputTimer.read();
                resetTimeout.attach(NULL,0);
                if ((logButtonUpTime-logButtonDownTime) > 0.05f) {
                    //        pc.puts("Up\r\n");
                }
            }
        }
    }
}