Arianna autonomous DAQ firmware

Dependencies:   mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW

Revision:
0:664899e0b988
Child:
1:e392595b4b76
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/main.cpp	Sat Jun 30 02:03:51 2012 +0000
@@ -0,0 +1,430 @@
+#include "mbed.h"
+
+#include <stdint.h>
+#include "SDFileSystem.h"
+#include "MODSERIAL.h"
+#include "Watchdog.h"
+#include "SnConstants.h"
+#include "SnBitUtils.h"
+#include "SnSDUtils.h"
+#include "SnConfigFrame.h"
+#include "SnEventFrame.h"
+#include "SnStatusFrame.h"
+#include "SnCommWin.h"
+#include "SnCommAfar.h"
+#include "SnCommUsb.h"
+
+//
+// MBED PINS (ordered by number)
+//
+// leds (for debugging)
+DigitalOut led1(LED1);
+DigitalOut led2(LED2);
+DigitalOut led3(LED3);
+DigitalOut led4(LED4);
+// Set up power pins - Note that it's Zero for "on"
+DigitalOut PIN_turn_on_system(p17);
+DigitalOut PIN_turn_on_amps(p25);
+// Activate/select chip by falling edge
+DigitalOut PIN_ADC_CS( p9 );
+// clock signal to activate PLA setting
+DigitalOut PIN_PLA_cs(p10);
+// To force a trigger
+DigitalOut PIN_forceTrigger(p11);  //modification
+// To suppress thermal triggers
+DigitalOut PIN_enableThermTrig(p12);
+// Restart clock on all FPGAs.
+DigitalOut PIN_DoNotRestartAllClocks( p13 );
+// This tells the DFPGAs to store the data on motherboard FPGA and
+// read it out.
+DigitalIn PIN_a_sf_clk( p14 );
+DigitalIn PIN_rst_a_sf(p15);
+// Lock daughter card registeres (during data readout).
+DigitalOut PIN_lockRegisters( p20 );
+// Majority logic pins
+DigitalOut PIN_MajLogHiBit(p22);
+DigitalOut PIN_MajLogLoBit(p23);
+// Tell FPGA to be ready to accept DAC values
+DigitalOut PIN_start_fpga(p26); 
+// Two bits to the select the daughter card for readout
+DigitalOut PIN_selCardHiBit( p29 );
+DigitalOut PIN_selCardLoBit( p30 );
+// To launch a heartbeat pulse
+DigitalOut PIN_heartbeat(p24);
+// Setup SPI pins
+SPI PIN_spi( p5, p6, p7 );
+// The SD card
+SDFileSystem sd(p5, p6, p7, p8, SnSDUtils::kSDsubDir+1);
+LocalFileSystem local("local");
+
+
+//
+// fwd declare fcns
+//
+void                      ReadAllRegisters();
+void                      ReadRegister(const uint8_t chan, int16_t* dev);
+void                      SaveEvent(const int32_t etms);
+void                      WaitTrigAndSendClock();
+void                      SetConfig();
+SnCommWin::ECommWinResult OpenCommWin();
+
+//
+// globals
+//
+// readout objs
+static Ticker         gForceTicker;
+static Ticker         gIOticker;
+static Timer          gEvtTimer;
+static SnConfigFrame  gConf;
+static SnEventFrame   gEvent;
+// parameters
+static bool           gFirstEvt         = true;
+static bool           gReadingOut       = false;
+static bool           gCommWinOpen      = false; // if it's open
+static bool           gOpenCommWin      = false; // if it should be opened
+static int32_t        gEvtNum           = 0;   // num of evt written
+static int32_t        gTrgNum[kNumTrgs] = {0}; // num of this type of trg received
+// i/o
+static Timer          gIOtimer;
+static MODSERIAL      gCpu( USBTX, USBRX ); // defined here so it might be used for debugging output
+static SnCommWin*     gComms[kNcomms]   = { new SnCommAfar, new SnCommUsb(&gCpu) }; // order => priority
+static FILE*          gCurFile          = 0;
+//static char           gEvtBuf[SnEventFrame::kMaxSizeOf];
+//static char           gConfBuf[SnConfigFrame::kMaxSizeOf];
+//static char           gStatBuf[SnStatusFrame::kMaxSizeOf];
+static char           gGenBuf[SnStatusFrame::kMaxSizeOf]; // must be big enough for event or status or config!
+
+void procForceTrigger() {
+    led1=!led1;
+    if (gReadingOut==false && gCommWinOpen==false) {
+        gEvent.SetTrgBit(kFrcTrg);
+        gEvent.SetTrgNum((gTrgNum[kFrcTrg])++);
+        PIN_forceTrigger = 1;     // force a trigger
+    }
+}
+
+void procCommWin() {
+    if (gReadingOut==false && gCommWinOpen==false) {
+        gOpenCommWin = true;
+    }
+}
+
+
+// TODO: add block-id's to output file? (config block, event block, file header block, etc.)
+
+int main() {
+    led2=1;
+    //wait_ms(100);
+
+    // a failsafe
+    Watchdog::kick(kWDFailsafe);
+
+    // Turn on all power
+    // Note that zero means "on"
+    PIN_turn_on_system=0;
+
+    // block (thermal) triggers during configuration
+    PIN_enableThermTrig       = 0;
+    PIN_ADC_CS                = 1;
+    PIN_DoNotRestartAllClocks = 1;
+    PIN_forceTrigger          = 0;
+    wait_ms(20);
+    
+    // setup SPI
+    PIN_spi.frequency( 10000000 );  // Max is 12.5 MHz
+    
+    gForceTicker.detach();
+    gFirstEvt = true;
+    
+    gConf.Reset();
+    
+    //
+    // get config
+    //
+    
+    // TODO: communication window
+    // TODO: call usb port setup
+    //OpenCommWin();
+    // TODO: get config
+    SetConfig();
+    
+    // get ready to trigger
+    PIN_spi.format( 16, 1 ); // change to data readout format
+
+    // force a trigger every dForceTrigPeriod seconds
+    gForceTicker.attach(&procForceTrigger, gConf.GetForceTrigPeriod());
+        
+    led2=0;
+    
+    // the main event loop. wait for triggers in SendClock
+    while( true )
+    {
+        // in here, we wait for triggers from the MB-FPGA
+        led4 = !led4;
+        Watchdog::kick(); // don't reset!
+        gEvtTimer.reset();
+        gEvtTimer.start();
+        PIN_lockRegisters = 0; // allow data to come from DFPGA
+        WaitTrigAndSendClock();
+        PIN_lockRegisters = 1; // block registers during readout
+        gEvtTimer.stop();
+        Watchdog::kick(); // don't reset!
+        
+        if (gOpenCommWin) {
+            OpenCommWin();
+            gOpenCommWin=false;
+            continue;
+        }
+        
+        //
+        // got trigger. read registers to mbed and build the event
+        //
+
+        // read data & calc CRC
+        gEvent.ReadWaveforms(PIN_spi, PIN_selCardHiBit, PIN_selCardLoBit);
+        gEvent.SetCurMbedTime();
+        // TODO: no way to check for external trigger?
+        if (gEvent.IsForcedTrg()==false) {
+            gEvent.SetTrgBit(kThmTrg);
+            gEvent.SetTrgNum((gTrgNum[kThmTrg])++);
+        } // else already set by procForceTrigger
+        // (no need to calc if we throw this event away)
+        
+        Watchdog::kick(); // don't reset!
+
+        const int32_t etms = gEvtTimer.read_ms();
+        if ( gEvent.IsForcedTrg() || 
+            (etms>gConf.GetEvtThrtlPeriodMs()) ) {
+            
+            PIN_lockRegisters = 0; // done reading, unlock so we can talk to SD card.
+            SaveEvent(etms);
+
+        }
+    }
+
+}
+
+//
+// save the event
+//
+void SaveEvent(const int32_t etms) {
+    // write the event
+        
+    // set the event number & dt
+    gEvent.SetEvtNum(gEvtNum++);
+    gEvent.SetDTms(etms);
+    
+    // save to SD
+    SnSDUtils::WriteEventTo(gCurFile, gGenBuf, gEvent, gConf);
+    
+    // reset
+    gEvent.ClearEvent();
+    
+    if (gEvtNum==5) {
+        fclose(gCurFile);
+        while (1) {
+            led3 = 1;
+            wait(0.5);
+            led3 = 0;
+            wait(0.5);
+        }
+    }
+    
+}
+
+//
+// set configuration
+//
+void SetConfig() {
+    // restart watchdog
+    Watchdog::kick(gConf.GetWatchdogPeriod());
+    
+    // reset event, timers, trigger counters
+    gEvent.ClearEvent();
+    gEvtNum = gConf.GetFirstEvt();
+    gEvtTimer.reset();
+    memset(gTrgNum, 0, sizeof(int32_t)*kNumTrgs);
+    
+    // make new output file
+    SnSDUtils::CloseOutputFile(gCurFile);
+    
+    gCurFile = SnSDUtils::OpenNewOutputFile(gConf.GetMacAddress(),
+                                            gConf.GetRun());
+    SnSDUtils::WriteFileHeader(gCurFile, gConf.GetMacAddress());
+    SnSDUtils::WriteConfig(gCurFile, gConf);
+    
+    // TODO: turn on amps individually, when that's possible
+    if (gConf.IsEachAmpOn()) {
+        PIN_turn_on_amps=0;
+    }
+    
+    // Set PLA value(s)
+    // TODO: send multiple values when FPGA code is ready for it
+    // TODO: uncomment when using new version of FPGA code
+    PIN_spi.format( 16, 0 ); // change mode for DAC & PLA value setting
+    PIN_MajLogHiBit=1;
+    PIN_MajLogLoBit=1;
+    PIN_enableThermTrig=0;
+
+    uint16_t hi, lo;
+    PIN_PLA_cs=1;
+    wait(3);
+    for (uint8_t pi=0; pi<kNplas; pi++) {
+        if (pi < gConf.GetNumPlas()) {
+            SnConfigFrame::GetHiLoPlas(gConf.GetPla(pi), hi, lo);
+            PIN_spi.write(hi);
+            PIN_spi.write(lo);
+        } else {
+            PIN_spi.write(kNoTrigPla); // hi
+            PIN_spi.write(kNoTrigPla); // lo
+        }
+    }
+    wait(3);
+    PIN_PLA_cs=0;
+    wait(3);
+    
+    // DAC values
+    //
+    // first 12 bits = DAC value
+    // next 2 bits = DAC ID
+    // last 2 bits = dFPGA ID
+    //
+    // But FPGA uses "gray encoding" which means only 1 bit
+    // can change at a time (of the last 4 bits). So even tho
+    // the card/dac# is encoded, the order is also important
+    // 0000 (dac0,card0), 0001 (dac0,card1), 0011 (dac0,card3), 0010 (dac0,card2),
+    // 0110 (dac1,card2), 0111 (dac1,card3), 0101 (dac1,card1), etc.
+    int dv=0;
+    for (uint8_t i=0, gri=0; i<kTotDacs; i++) {
+        // get the gray-codes for this iteration
+        gri = SnBitUtils::binToGray(i);
+        
+        // build bit word
+        dv   = static_cast<int>(gConf.GetDac(gri & 0x0003u, gri >> 2u));
+        dv <<= 4u;
+        dv  |= gri;
+        
+        // send to FPGA
+        PIN_start_fpga=1;
+        PIN_spi.write(dv);
+        PIN_start_fpga=0;
+    }
+        
+    wait_ms(20);
+    
+    // Majority Logic Trigger selection (# of cards)
+    SnBitUtils::SetChanNumBits(gConf.GetNumCardsMajLog() - 1u,
+                   PIN_MajLogHiBit, PIN_MajLogLoBit);
+    
+    // Enable thermal trigger?
+    PIN_enableThermTrig = gConf.IsThermTrigEnabled();
+
+    PIN_spi.format( 16, 1 ); // back to trigger mode
+    
+    Watchdog::kick(); // don't reset!
+
+}
+
+//
+// readout functions
+//
+void WaitTrigAndSendClock() {
+
+    if (gFirstEvt==false) {
+        PIN_DoNotRestartAllClocks    = 0;
+        wait_us(1);
+        PIN_DoNotRestartAllClocks    = 1;
+        //led3 = !led3; // toggle send clock led
+    } else {
+        gFirstEvt = false;
+    }
+    
+    //
+    // wait for a trigger here.
+    //
+    gReadingOut = false;  // this will allow forced triggers (see procForceTrigger())
+    while ( PIN_a_sf_clk == 1 ) {
+        if (gOpenCommWin) {
+            // break out to open comms
+            return;
+        }
+    }
+    PIN_forceTrigger=0;   // necessary for forced triggers, harmless for other triggers
+    gReadingOut = true;   // disallow new forced triggers
+    
+    //
+    // collect data from daughter cards
+    //
+    
+    // TODO: what if some card (set of channels) doesn't respond?
+    // currently, will wait forever?
+    // also, if ch1 is dead, will wait forever (due to FPGA code)
+    
+    for( uint8_t i = 0; i < kNsamps; i++ ) {
+        if( PIN_a_sf_clk == 1 ) {
+            if( i == 0 )
+                wait_us( 1 );
+
+            PIN_ADC_CS = 0;
+            PIN_spi.write( 0x00 );
+            PIN_ADC_CS = 1;
+        } else {
+            i--;
+        }
+    }
+    
+}
+
+SnCommWin::ECommWinResult OpenCommWin() {
+    // loop through each comm mode:
+    //  a) try to connect
+    //  b) if connected, listen for config
+    //  c) if config requests data, send it
+    
+    gCommWinOpen = true;
+    Watchdog::kick(); // don't reset!
+    
+    // TODO: power up comm systems
+    
+    gIOtimer.reset();
+    gIOtimer.start();
+    
+    const uint32_t conto = (gConf.GetCommWinDuration() < kConnectTimeout) ?
+        gConf.GetCommWinDuration() : kConnectTimeout;
+    const uint32_t listo = (gConf.GetCommWinDuration() < kListenTimeout) ?
+        gConf.GetCommWinDuration() : kListenTimeout;
+    
+    SnCommWin::ECommWinResult res = SnCommWin::kUndefFail;
+    
+    SnCommWin** cw = gComms;
+    for (uint8_t i=0; (i<kNcomms) && 
+                     (gIOtimer.read()<gConf.GetCommWinDuration()); i++, cw++) {
+        
+        // open window and (mabye) send status update
+        const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow(
+            gIOtimer, conto, true, gConf, gEvent, gGenBuf, gGenBuf);
+        if (conres>=SnCommWin::kConnected) {
+            // connected. listen for config
+            const SnCommWin::ECommWinResult cfgres = (*cw)->GetConfig(
+                gConf, gIOtimer, listo, gGenBuf);
+            if (cfgres>=SnCommWin::kOkWithMsg) {
+                // got config. set it up.
+                SetConfig();
+                // send data if need be (files, some events, etc)
+                if (gConf.GetCommSendData()!=0) {
+                    res = (*cw)->SendData(gConf, gEvent, gGenBuf, gGenBuf);
+                } else {
+                    // don't send anything
+                    res = cfgres;
+                }
+                break;
+            }
+        }
+        
+        Watchdog::kick(); // don't reset!
+
+    }
+    
+    gCommWinOpen = false;
+    return res;
+}