Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
main.cpp
- Committer:
- uci1
- Date:
- 2012-08-02
- Revision:
- 4:a91682e19d6b
- Parent:
- 3:24c5f0f50bf1
- Child:
- 5:9cea89700c66
File content as of revision 4:a91682e19d6b:
#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 "SnHeaderFrame.h" #include "SnCommWin.h" #include "SnCommAfar.h" #include "SnCommUsb.h" #include "SnBase64.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); // this turns on system 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); // afar power DigitalOut PIN_afar_power(p16); // batter voltage/current measurement AnalogIn PIN_vADC1(p19); AnalogIn PIN_vADC2(p18); // Lock daughter card registeres (during data readout). DigitalOut PIN_lockRegisters( p20 ); // iridium (SBD) power DigitalOut PIN_iridSbd_power(p21); // 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 // this needs to be first in case some other global uses a print statement static MODSERIAL gCpu( USBTX, USBRX ); // defined here so it might be used for debugging output 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 SetConfigAndMakeOutputFile(); SnCommWin::ECommWinResult OpenCommWin(); void MakeOutputFile(const bool stopRunning=false); void SetPower(const bool isCommWin); // // globals // // readout objs static Ticker gForceTicker; static Ticker gHeartbeatTicker; static Ticker gCommWinTicker; 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 volatile 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 time_t gLastCommWin = 0; static const uint32_t gBufSize=SnStatusFrame::kMaxSizeOf + SnHeaderFrame::kMaxSizeOf; static const uint32_t gB64Bsize=BASE64ENC_LEN(gBufSize)+1; static char gB64Buf[gB64Bsize]; static char gGenBuf[gBufSize]; // must be big enough for event or status or config! //static SnCommWin* gComms[kNcomms] = { new SnCommAfar, new SnCommUsb(&gCpu) }; // order => priority //static SnCommWin* gComms[kNcomms] = { new SnCommUsb(&gCpu) }; // order => priority static SnCommWin* gComms[kNcomms] = { new SnCommAfar(gB64Buf, gB64Bsize) }; // order => priority void procForceTrigger() { led3=!led3; if (gReadingOut==false && gCommWinOpen==false) { gEvent.SetTrgBit(kFrcTrg); gEvent.SetTrgNum((gTrgNum[kFrcTrg])++); PIN_forceTrigger = 1; // force a trigger } } void procHeartbeat() { if (gReadingOut==false && gCommWinOpen==false) { PIN_heartbeat = 1; // heartbeat pulse PIN_heartbeat = 0; } } void procCommWin() { if (gReadingOut==false && gCommWinOpen==false) { if ( (time(0) - gLastCommWin) > gConf.GetCommWinPeriod() ) { led3=!led3; gOpenCommWin = true; } } } uint32_t GetTimeoutTime(const uint32_t startTime, const uint32_t delta) { const uint32_t lst = time(0)-startTime; const uint32_t lio = ((lst+delta) < gConf.GetCommWinDuration()) ? lst+delta : gConf.GetCommWinDuration(); return lio+startTime; } // TODO: add block-id's to output file? (config block, event block, file header block, etc.) // TODO: HEARTBEAT! // TODO: make websocket URL settable in the config (i.e. via SBD?) int main() { { led1=1; wait(0.2); led1=0; led2=1; wait(0.2); led2=0; led3=1; wait(0.2); led3=0; led4=1; wait(0.2); led4=0; } led2=1; //wait_ms(100); printf("\n\n\n\n\n\nstarting\r\n"); // a failsafe Watchdog::kick(kWDFailsafe); // set the clock to the BS time, if it's not set if ( (static_cast<int32_t>(time(0)))<0 ) { set_time(kBStime); } printf("time = %d\r\n",(int32_t)time(0)); gLastCommWin = time(0); // prevent comm win proc gForceTicker.detach(); gFirstEvt = true; // (probably) power down comms and power up cards,amps SetPower(false); printf("Using config %s\r\n",gConf.GetLabel()); SetConfigAndMakeOutputFile(); // setup defaults in case no communication // // get config // //printf("open window\r\n"); OpenCommWin(); // get ready to trigger PIN_spi.format( 16, 1 ); // change to data readout format led2=0; // the main event loop. wait for triggers in SendClock gEvtTimer.start(); while( true ) { // in here, we wait for triggers from the MB-FPGA Watchdog::kick(); // don't reset! led1 = !led1; printf("calling wait trig\r\n"); printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); PIN_lockRegisters = 0; // allow data to come from DFPGA WaitTrigAndSendClock(); PIN_lockRegisters = 1; // block registers during readout const int32_t etms = gEvtTimer.read_ms(); // time since last trigger gEvtTimer.reset(); gEvtTimer.start(); // start counter from this trigger printf("wait trig send clock exited\r\n"); Watchdog::kick(); // don't reset! if (gReadingOut) { // // got trigger. read registers to mbed and build the event // led4=1; printf("readout\r\n"); // 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! printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); if ( gEvent.IsForcedTrg() || gFirstEvt || (etms>gConf.GetEvtThrtlPeriodMs()) ) { led2=1; PIN_lockRegisters = 0; // done reading, unlock so we can talk to SD card. SaveEvent(etms); if (gEvtNum>=(gConf.GetFirstEvt()+gConf.GetEvtsPerFile())) { MakeOutputFile(gConf.IsSingleSeqRunMode()); } /* } else { printf("forced=%s, gFirstEvt=%s, e>t %d>%hu %s\r\n", gEvent.IsForcedTrg()?"true":"false", gFirstEvt?"true":"false", etms, gConf.GetEvtThrtlPeriodMs(), etms>gConf.GetEvtThrtlPeriodMs() ? "true":"false"); */ } } printf("past reading out\r\n"); led4=0; led2=0; if (gOpenCommWin) { printf("gOpenComWin=%s, opening\r\n",gOpenCommWin?"true":"false"); OpenCommWin(); gOpenCommWin=false; } else { printf("gOpenCommWin=false\r\n"); } } } // // save the event // void SaveEvent(const int32_t etms) { // write the event printf("save event\r\n"); // set the event number & dt gEvent.SetEvtNum(gEvtNum); gEvent.SetDTms(etms); // save to SD SnSDUtils::WriteEventTo(SnSDUtils::GetCurFile(), gGenBuf, gEvent, gConf); // reset gEvent.ClearEvent(); // increment event number ++gEvtNum; printf("gEvtNum=%d\r\n",gEvtNum); } void MakeOutputFile(const bool stopRunning) { SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile()); if (stopRunning) { while (true) { led3 = 1; led4=1; wait(0.5); led3 = 0; led4=0; wait(0.5); Watchdog::kick(); } } SnSDUtils::OpenNewOutputFile(gConf.GetMacAddress(), gConf.GetRun(), PIN_vADC1.read_u16(), PIN_vADC2.read_u16()); printf("made output file with run %u\r\n",gConf.GetRun()); printf("filename=%s\r\n",SnSDUtils::GetCurFileName()); SnSDUtils::WriteConfig(SnSDUtils::GetCurFile(), gConf); } // // power stuff // void SetPower(const bool isCommWin) { if (isCommWin) { PIN_turn_on_system = gConf.IsPoweredFor(SnConfigFrame::kCardComWin); wait_ms(10); PIN_turn_on_amps = gConf.IsPoweredFor(SnConfigFrame::kAmpsComWin); wait_ms(10); PIN_iridSbd_power = gConf.IsPoweredFor(SnConfigFrame::kIridComWin); wait_ms(10); PIN_afar_power = gConf.IsPoweredFor(SnConfigFrame::kAfarComWin); wait_ms(10); } else { PIN_turn_on_system = gConf.IsPoweredFor(SnConfigFrame::kCardDatTak); wait_ms(10); PIN_turn_on_amps = gConf.IsPoweredFor(SnConfigFrame::kAmpsDatTak); wait_ms(10); PIN_iridSbd_power = gConf.IsPoweredFor(SnConfigFrame::kIridDatTak); wait_ms(10); PIN_afar_power = gConf.IsPoweredFor(SnConfigFrame::kAfarDatTak); wait_ms(10); } } // // set configuration // void SetConfigAndMakeOutputFile() { printf("SetConfigAndMakeOutputFile\r\n"); // restart watchdog Watchdog::kick(gConf.GetWatchdogPeriod()); // block (thermal) triggers during configuration PIN_enableThermTrig = 0; PIN_ADC_CS = 1; PIN_DoNotRestartAllClocks = 1; PIN_forceTrigger = 0; PIN_heartbeat = 0; wait_ms(20); // reset event, timers, trigger counters gEvent.ClearEvent(); gEvtNum = gConf.GetFirstEvt(); memset(gTrgNum, 0, sizeof(int32_t)*kNumTrgs); // make new output file MakeOutputFile(); // TODO: turn on amps individually, when that's possible PIN_turn_on_amps = gConf.IsEachAmpOn() ? 0 : 1; // Set PLA value(s) PIN_spi.format( 16, 0 ); // change mode for DAC & PLA value setting PIN_spi.frequency(1000000); PIN_MajLogHiBit=1; PIN_MajLogLoBit=1; PIN_enableThermTrig=0; uint16_t hi, lo; PIN_PLA_cs=1; wait(4); 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); printf("pla hi %hu, lo %hu\r\n",hi,lo); } else { PIN_spi.write(kNoTrigPla); // hi PIN_spi.write(kNoTrigPla); // lo printf("pla hi %hu, lo %hu\r\n",kNoTrigPla,kNoTrigPla); } Watchdog::kick(); } 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. printf("setting dacs\r\n"); uint16_t 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; printf("dac %04x\r\n",dv); // send to FPGA PIN_start_fpga=1; PIN_spi.write(dv); PIN_start_fpga=0; Watchdog::kick(); } printf("dacs set\r\n"); 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 PIN_spi.frequency( 10000000 ); // Max is 12.5 MHz // force a trigger every... gForceTicker.detach(); if (gConf.GetForceTrigPeriod()>0) { gForceTicker.attach(&procForceTrigger, gConf.GetForceTrigPeriod() > kAbsMaxTimer ? kAbsMaxTimer : gConf.GetForceTrigPeriod()); // force period has a maximum } // heartbeat every ... gHeartbeatTicker.detach(); if (gConf.GetHeartbeatPeriod()>0) { gHeartbeatTicker.attach(&procHeartbeat, gConf.GetHeartbeatPeriod() > kAbsMaxTimer ? kAbsMaxTimer : gConf.GetHeartbeatPeriod()); } // proc a comm win every... gCommWinTicker.detach(); gCommWinTicker.attach(&procCommWin, gConf.GetCommWinPeriod() > kAbsMaxTimer ? kCommWinLongPrdTk : gConf.GetCommWinPeriod()); // periodic check if above max printf("attach comm win ticker %u\r\n", gConf.GetCommWinPeriod() > kAbsMaxTimer ? kCommWinLongPrdTk : gConf.GetCommWinPeriod()); Watchdog::kick(); // don't reset! } // // readout functions // void WaitTrigAndSendClock() { printf("WaitTrigAndSendClock\r\n"); 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) { return; // break out to open comms } } 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 gLastCommWin = time(0); if (gConf.GetCommWinDuration()==0) { // TODO: set min so this is not possible return SnCommWin::kOkNoMsg; } gCommWinOpen = true; Watchdog::kick(); // don't reset! printf("opening comm window at %d\r\n", (int32_t)gLastCommWin); // close the file so that the data is all written out. // and open it back up at the beginning (for reading) SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile()); SnSDUtils::OpenExistingFile(SnSDUtils::GetCurFileName(), true); // (probably) power down cards,amps and power up comms SetPower(true); 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; bool gotNewConfig=false; bool sendStat[kNcomms]; for (uint8_t i=0; i<kNcomms; i++) { sendStat[i]=true; } bool* ss = sendStat; SnCommWin** cw = gComms; for (uint8_t i=0; ((time(0)-gLastCommWin)<gConf.GetCommWinDuration()); i++, cw++, ss++) { Watchdog::kick(); // don't reset! if (i==kNcomms) { i=0; cw = gComms; ss = sendStat; } // open window and (mabye) send status update printf("calling OpenWindow. ss=%d\r\n",(int)(*ss)); printf("gtt=%u, ct=%d, lcw=%d, dur=%u\r\n",GetTimeoutTime(gLastCommWin,conto), time(0), gLastCommWin, gConf.GetCommWinDuration()); const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow( GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gEvent, gGenBuf); if (conres>=SnCommWin::kConnected) { Watchdog::kick(); // don't reset! // connected. listen for config *ss = false; // don't send status next time const SnCommWin::ECommWinResult cfgres = (*cw)->GetConfig( gConf, GetTimeoutTime(gLastCommWin, listo), gGenBuf, gBufSize); if (cfgres>=SnCommWin::kOkWithMsg) { Watchdog::kick(); // don't reset! printf("received config (%u)!\r\n",gConf.SizeOf()); char* b = gGenBuf; gConf.WriteTo(b); const uint32_t csz = gConf.SizeOf(); for (uint32_t i=0; i<csz; i++) { printf("%02x ",gGenBuf[i]); } printf("\r\n"); // send data if need be (files, some events, etc) printf("send data = %d\r\n", gConf.GetCommSendData()); if (gConf.GetCommSendData()!=0) { printf("sending data\r\n"); res = (*cw)->SendData(gConf, gEvent, gGenBuf, gBufSize, GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration())); } else { // don't send anything res = cfgres; } printf("Got config!\r\n"); gotNewConfig=true; Watchdog::kick(); // don't reset! break; } } Watchdog::kick(); // don't reset! } // (probably) power down comms and power up cards,amps SetPower(false); gFirstEvt = true; // reset config with system powered (for DAC/PLA setting) if (gotNewConfig) { printf("calling SetConfigAndMakeOutputFile\r\n"); SetConfigAndMakeOutputFile(); // TODO: remove } printf("closing comm win at %d\r\n",(int32_t)time(0)); gCommWinOpen = false; return res; }