Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
Diff: main.cpp
- Revision:
- 0:664899e0b988
- Child:
- 1:e392595b4b76
diff -r 000000000000 -r 664899e0b988 main.cpp --- /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; +}