Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
main.cpp
- Committer:
- uci1
- Date:
- 2013-01-23
- Revision:
- 32:20877f862cf0
- Parent:
- 31:b5bd3b189150
- Child:
- 33:06eb182d8813
File content as of revision 32:20877f862cf0:
#include "mbed.h" // start a watchdog as soon as possible #include "Watchdog.h" Watchdog::SnKickStarter gKickStarter(WDFAILSAFE); //#define DISABLE_CONFIG_SAFETYNETS #define ENABLE_AFAR_COMM #define ENABLE_SBD_COMM //#define ENABLE_USB_COMM #define ENABLE_AFAR_TWITTER //#define USE_RTOS_TIMER //#define USE_ETH_INTERFACE //#define EVT_TIME_PROFILE //#define DEBUG //#define SSNOTIFY #define USE_MODSERIAL #include <stdint.h> #include "SDFileSystem.h" #ifdef USE_MODSERIAL #include "MODSERIAL.h" #define MODSERIAL_RX_BUF_SIZE 512 #define MODSERIAL_TX_BUF_SIZE 512 #endif #include "FATDirHandle.h" #include "EthernetPowerControl.h" #include "SnConstants.h" #include "SnBitUtils.h" #include "SnSDUtils.h" #include "SnConfigFrame.h" #include "SnEventFrame.h" #include "SnStatusFrame.h" #include "SnHeaderFrame.h" #include "SnHeartbeatFrame.h" #include "SnCommWin.h" #ifdef USE_ETH_INTERFACE #include "SnCommAfarTCP.h" #else #include "SnCommAfarNetIf.h" #ifdef ENABLE_AFAR_TWITTER #include "SnCommAfarNetIfTwitter.h" #endif #endif #include "SnCommUsb.h" #include "SnCommSBD.h" #include "SnBase64.h" #ifdef USE_RTOS_TIMER #include "RtosTimer.h" #endif // // 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); // SD card select DigitalOut PIN_SD_CS(p8); // 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 #ifdef USE_MODSERIAL #define SERIAL_TYPE MODSERIAL #else #define SERIAL_TYPE Serial #endif static SERIAL_TYPE gCpu( USBTX, USBRX // defined here so it might be used for debugging output #ifdef USE_MODSERIAL ,MODSERIAL_TX_BUF_SIZE, MODSERIAL_RX_BUF_SIZE #endif ); static SERIAL_TYPE gSBDport(p28, p27, "sbd"); static SDFileSystem sd(p5, p6, p7, p8, SnSDUtils::kSDdir+1); // no leading '/' static LocalFileSystem local((SnCommWin::kLocalDir)+1); // no leading '/' // // fwd declare fcns // void ReadAllRegisters(); void ReadRegister(const uint8_t chan, int16_t* dev); void SaveHeartbeat(); void SaveEvent(const int32_t etms); void WaitTrigAndSendClock(); void SetConfigAndMakeOutputFile(); SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig=false); void MakeOutputFile(const bool stopRunning=false); void SetPower(const bool isCommWin); void procForceTrigger(); void procHeartbeat(); void procPowerCheck(); void procCommWin(); #ifdef USE_RTOS_TIMER void procForceTrigger(void const *) { return procForceTrigger(); } void procHeartbeat(void const *) { return procHeartbeat(); } void procPowerCheck(void const *) { return procPowerCheck(); } void procCommWin(void const *) { return procCommWin(); } #endif // // globals // // readout objs // TODO: use RtosTimer instead of Ticker? #ifdef USE_RTOS_TIMER static rtos::RtosTimer* gForceTicker; static rtos::RtosTimer* gHeartbeatTicker; static rtos::RtosTimer* gCommWinTicker; static rtos::RtosTimer* gPowerCheckTicker; #else static Ticker gForceTicker; static Ticker gHeartbeatTicker; static Ticker gCommWinTicker; static Ticker gPowerCheckTicker; #endif static Timer gTrgTimer; static Timer gAdcToMBtimer; #ifdef DISABLE_CONFIG_SAFETYNETS static SnConfigFrame gConf(false); #else static SnConfigFrame gConf; #endif static SnEventFrame gEvent; static SnPowerFrame gPower; // parameters static bool gCardsPowered = false; static bool gFirstEvt = true; static volatile bool gReadingOut = false; static volatile bool gCommWinOpen = false; // if it's open static volatile bool gOpenCommWin = false; // if it should be opened static volatile bool gCheckPower = false; // if it should be checked static uint32_t gPowNum = 0; static uint32_t gEvtNum = 0; // num of evt written static uint32_t gTrgNum[kNumTrgs] = {0}; // num of this type of trg received // i/o static time_t gLastCommWin = 0; // time static uint32_t gCommWinChecks = 0; static uint32_t gNcommWinChecks = 0; // heartbeat static time_t gLastHrtbt = 0; static volatile bool gHrtbtFired = false; static uint32_t gHrtbtNum = 0; // rates static double gThmDtSum = 0; // sum of all time diffs between thermal trigs static double gEvtDtSum = 0; // sum of all time diffs between events static uint32_t gThmNumDt = 0; // number of thermal trig time diffs added up static uint32_t gEvtNumDt = 0; // number of event time diffs added up // this should be bigger than anything that will actually be used static const uint32_t gBufSize=SnStatusFrame::kMaxSizeOf + (2u*SnHeaderFrame::kMaxSizeOf) + SnPowerFrame::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] = { 0 }; // order => priority. afar uses RTOS, and must be made inside main #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) static SnCommAfarNetIfTwitter* gTwit = 0; #endif void procForceTrigger() { if (gReadingOut==false && gCommWinOpen==false) { led3=!led3; #ifdef DEBUG printf("proc force\r\n"); #endif gEvent.SetTrgBit(kFrcTrg); gEvent.SetTrgNum(++(gTrgNum[kFrcTrg])); //PIN_forceTrigger = 0; PIN_forceTrigger = 1; // force a trigger PIN_forceTrigger = 0; #ifdef DEBUG printf("PIN_forceTrigge=%d, PIN_turn_on_system=%d, " "PIN_a_sf_clk=%d\r\n", PIN_forceTrigger.read(), PIN_turn_on_system.read(), PIN_a_sf_clk.read()); #endif } } void procHeartbeat() { if (gReadingOut==false && gCommWinOpen==false) { #ifdef DEBUG printf("proc heartbeat\r\n"); #endif //PIN_heartbeat = 0; PIN_heartbeat = 1; // heartbeat pulse PIN_heartbeat = 0; gLastHrtbt = time(0); gHrtbtFired = true; ++gHrtbtNum; } } void procPowerCheck() { #ifdef DEBUG printf("proc power\r\n"); #endif gCheckPower=true; } void procCommWin() { ++gCommWinChecks; //if ( (time(0) - gLastCommWin) > gConf.GetCommWinPeriod() ) { #ifdef DEBUG printf("<><><><><><> gCommWinChecks=%u, gNcommWinChecks=%u\r\n", gCommWinChecks, gNcommWinChecks); #endif if ( gCommWinChecks >= gNcommWinChecks ) { #ifdef DEBUG printf("proc comm win.\r\n"); #endif led3=!led3; gOpenCommWin = true; } } bool AreCardsPowered(const bool checkPin) { #ifdef DEBUG printf("acp: PIN_turn_on_system=%d, gCardsPowered=%d\r\n", PIN_turn_on_system.read(), gCardsPowered); #endif if (checkPin) { gCardsPowered = (PIN_turn_on_system.read()==0); } return gCardsPowered; } void GetAvePowerReading() { // use one measurement as the assumed average // in order to reduce computational errors int32_t v1, v2; const uint16_t aaveV1 = PIN_vADC1.read_u16(); const uint16_t aaveV2 = PIN_vADC2.read_u16(); float n=0, ave1=0, ave2=0, rms1=0, rms2=0; for (uint16_t i=0; i<kNvoltsAve; i++) { v1 = PIN_vADC1.read_u16() - aaveV1; v2 = PIN_vADC2.read_u16() - aaveV2; n += 1; ave1 += v1; rms1 += v1*v1; ave2 += v2; rms2 += v2*v2; } rms1 -= (ave1*ave1)/n; rms2 -= (ave2*ave2)/n; rms1 /= n-1; rms2 /= n-1; rms1 = sqrt(rms1); rms2 = sqrt(rms2); ave1 /= n; ave2 /= n; ave1 += aaveV1; ave2 += aaveV2; gPower.Set(ave1, ave2, rms1, rms2, time(0)); } void CheckPower(const bool isCommWin) { #ifdef DEBUG printf("CheckPower\r\n"); #endif // read power GetAvePowerReading(); // save to disk FILE* cf = SnSDUtils::GetCurFile(); if (cf!=0) { PIN_lockRegisters = 0; // unlock so we can talk to SD card. #ifdef DEBUG printf("writing power. v1=%g, v2=%g, r1=%g, r2=%g, t=%u, pownum=%u\r\n", gPower.GetAveV1(), gPower.GetAveV2(), gPower.GetRmsV1(), gPower.GetRmsV2(), gPower.GetTime(), gPowNum); #endif SnSDUtils::WritePowerTo(cf, gPower, gPowNum); } // do we need to change modes? bool changed = false; if (gConf.IsLowPowerMode()) { if (gPower.GetAveV1() > gConf.GetBatVoltLowPwr()) { #ifdef DEBUG printf("chaing to normal power!\r\n"); #endif gConf.ChangeToNormPower(); changed = true; } } else { if (gPower.GetAveV1() < gConf.GetBatVoltLowPwr()) { #ifdef DEBUG printf("chaing to low power!\r\n"); #endif gConf.ChangeToLowPower(); changed = true; } } if (changed) { SetPower(isCommWin); // TODO: This will fail if isCommWin==false? (currently not possible, but..) #ifdef DEBUG printf("Using config %s\r\n",gConf.GetLabel()); #endif SetConfigAndMakeOutputFile(); // setup defaults in case no communication } // checking done gCheckPower = false; } void ResetCountersClearEvt() { const uint32_t evtStartCurSeq = (SnSDUtils::GetCurSeqNum()) // no -1; start with seq=0 * gConf.GetEvtsPerFile(); gEvent.ClearEvent(); gEvtNum = gConf.GetFirstEvt() + evtStartCurSeq; gPowNum = evtStartCurSeq; memset(gTrgNum, 0, sizeof(uint32_t)*kNumTrgs); // reset rate counters gThmDtSum = 0; gThmNumDt = 0; gEvtDtSum = 0; gEvtNumDt = 0; // reset heartbeat counters gLastHrtbt = 0; gHrtbtFired = false; gHrtbtNum = 0; #ifdef DEBUG printf("Reset: gEvtNum=%u, gPowNum=%u, evtStartCS=%u\r\n", gEvtNum, gPowNum, evtStartCurSeq); #endif } void GetRates(float& thmrate, float& evtrate) { thmrate = evtrate = 0; #ifdef DEBUG printf("** Getting rates: gThmNumDt=%d, gThmDtSum=%g, " "gEvtNumDt=%d, gEvtDtSum=%g\r\n", gThmNumDt, gThmDtSum, gEvtNumDt, gEvtDtSum); #endif thmrate = (gThmDtSum>0.0) ? static_cast<float>(gThmNumDt) / (gThmDtSum/1e3) : 0; evtrate = (gEvtDtSum>0.0) ? static_cast<float>(gEvtNumDt) / (gEvtDtSum/1e3) : 0; } void AddToRate(const float dt, const bool isThm) { if (isThm) { gThmDtSum += dt; gThmNumDt += 1u; } else { gEvtDtSum += dt; gEvtNumDt += 1u; } #ifdef DEBUG printf("** AddToRate: dt=%g, isThm=%d\r\n",dt,(int)isThm); printf("** AddToRate: gThmNumDt=%d, gThmDtSum=%g, " "gEvtNumDt=%d, gEvtDtSum=%g\r\n", gThmNumDt, gThmDtSum, gEvtNumDt, gEvtDtSum); #endif } bool IsSeqComplete() { #ifdef DEBUG printf("IsSeqComplete: eps=%u, cntpow=%d, fe=%u, pow=%u, evt=%u, seq=%hu\r\n", gConf.GetEvtsPerFile(), (int)gConf.IsCountingPowerReadings(), gConf.GetFirstEvt(), gPowNum, gEvtNum, SnSDUtils::GetCurSeqNum()); #endif if (gConf.GetEvtsPerFile()>0) { const uint32_t evtEndCurSeq = (SnSDUtils::GetCurSeqNum()+1) // account for seq=0 * gConf.GetEvtsPerFile(); #ifdef DEBUG printf("evtEndCurSeq=%u\r\n",evtEndCurSeq); #endif if (gConf.IsCountingPowerReadings()) { return (gPowNum>=evtEndCurSeq); } else { // first event num is a one-time per run offset, not one per sequence return (gEvtNum>=(gConf.GetFirstEvt()+evtEndCurSeq)); } } else { return false; } } #ifdef USE_RTOS_TIMER void stopTicker(rtos::RtosTimer* tik) { if (tik!=0) { tik->stop(); } } #else void stopTicker(Ticker& tik) { tik.detach(); } #endif #ifdef USE_RTOS_TIMER float resetTicker(rtos::RtosTimer* tik, const float timSec, const float maxTimSec) { if (tik!=0) { tik->stop(); if (timSec>0) { float tp = timSec > maxTimSec ? maxTimSec : timSec; tp *= 1000u; // ms tik->start(tp); return tp; } } return 0; } #else float resetTicker(Ticker& tik, const float timSec, const float maxTimSec, void (*fptr)(void)) { tik.detach(); if (timSec>0) { const float tp = timSec > maxTimSec ? maxTimSec : timSec; tik.attach(fptr, tp); return tp; } return 0; } #endif void StopAllTickers() { stopTicker(gForceTicker); stopTicker(gHeartbeatTicker); stopTicker(gCommWinTicker); stopTicker(gPowerCheckTicker); } void ResetAllTickers() { #ifdef USE_RTOS_TIMER const float ftp = resetTicker(gForceTicker, gConf.GetForceTrigPeriod(), kAbsMaxTimer); wait_ms(131); // make it less likely for multiple triggers to fire too close together const float hbp = resetTicker(gHeartbeatTicker, gConf.GetHeartbeatPeriod(), kAbsMaxTimer); wait_ms(173); // make it less likely for multiple triggers to fire too close together const float cwp = resetTicker(gCommWinTicker, gConf.GetCommWinPeriod(), kCommWinLongPrdTk); wait_ms(169); // make it less likely for multiple triggers to fire too close together const float pcp = resetTicker(gPowerCheckTicker, gConf.GetVoltCheckPeriod(), kAbsMaxTimer); #else const float ftp = resetTicker(gForceTicker, gConf.GetForceTrigPeriod(), kAbsMaxTimer, &procForceTrigger); wait_ms(131); // make it less likely for multiple triggers to fire too close together const float hbp = resetTicker(gHeartbeatTicker, gConf.GetHeartbeatPeriod(), kAbsMaxTimer, &procHeartbeat); wait_ms(173); // make it less likely for multiple triggers to fire too close together const float cwp = resetTicker(gCommWinTicker, gConf.GetCommWinPeriod(), kCommWinLongPrdTk, &procCommWin); wait_ms(169); // make it less likely for multiple triggers to fire too close together const float pcp = resetTicker(gPowerCheckTicker, gConf.GetVoltCheckPeriod(), kAbsMaxTimer, &procPowerCheck); #endif #ifdef DEBUG printf("attach force trig %g\r\n",ftp); printf("attach heart beat %g\r\n",hbp); printf("attach comm win %g\r\n",cwp); printf("attach power chk %g\r\n",pcp); #endif } void StopRunning() { #if defined(DEBUG) || defined(SSNOTIFY) printf("stop running\r\n"); #endif StopAllTickers(); OpenCommWin(); while (true) { led3 = 1; led4=1; wait(0.5); led3 = 0; led4=0; wait(0.5); // don't kick the watchdog // if we do, the station is unrecoverable without physical access } } int main() { // a failsafe Watchdog::kick(WDFAILSAFE); { gCpu.baud(CPUBAUD_SN); #if defined(SSNOTIFY) || defined(DEBUG) printf("main: start\r\n"); #endif 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; } #ifdef DEBUG printf("initializing SD card..\r\n"); #endif // initialize the SD card. this should prevent the issue with // seq 0 being overwritten upon power up or the SD card first // being insterted sd.disk_initialize(); #ifdef DEBUG printf("making comm objects\r\n"); #endif uint8_t comi(0); #ifdef ENABLE_AFAR_COMM // RTOS stuff must be made inside main for some reason #ifdef USE_ETH_INTERFACE gComms[comi++] = new SnCommAfarTCP(gConf); #else gComms[comi++] = new SnCommAfarNetIf(gConf); #ifdef ENABLE_AFAR_TWITTER gTwit = new SnCommAfarNetIfTwitter(gConf); #endif #endif #endif #ifdef ENABLE_SBD_COMM gComms[comi++] = new SnCommSBD(&gSBDport, &gCpu); #endif #ifdef ENABLE_USB_COMM gComms[comi++] = new SnCommUsb(&gCpu); #endif #ifdef DEBUG printf("made comm objects\r\n"); #endif #ifdef USE_RTOS_TIMER gForceTicker = new rtos::RtosTimer(&procForceTrigger); gHeartbeatTicker = new rtos::RtosTimer(&procHeartbeat); gCommWinTicker = new rtos::RtosTimer(&procCommWin); gPowerCheckTicker = new rtos::RtosTimer(&procPowerCheck); #endif led2=1; //wait_ms(100); #ifdef DEBUG printf("\n\n\n\n\n\nstarting\r\n"); #endif // set the clock to the BS time, if it's not set if ( (static_cast<int32_t>(time(0)))<0 ) { set_time(kBStime); } #ifdef DEBUG printf("time = %d\r\n",(int32_t)time(0)); #endif gLastCommWin = time(0); // prevent comm win proc #ifdef USE_RTOS_TIMER gForceTicker->stop(); #else gForceTicker.detach(); #endif gFirstEvt = true; // (probably) power down comms and power up cards,amps SetPower(false); // // get config // #ifdef DEBUG printf("call OpenCommWin\r\n"); #endif OpenCommWin(true); // alwasy configure, even if no new config // get ready to trigger PIN_spi.format( 16, 1 ); // change to data readout format PIN_spi.frequency( 10000000 ); // Max is 12.5 MHz led2=0; // the main event loop. wait for triggers in SendClock AreCardsPowered(true); gTrgTimer.start(); register int32_t etms=0; // time between written events while( true ) { // in here, we wait for triggers from the MB-FPGA Watchdog::kick(); // don't reset! led1 = !led1; #ifdef DEBUG printf("calling wait trig\r\n"); printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); printf("readingout=%d\r\n",(int)gReadingOut); #endif PIN_lockRegisters = 0; // allow data to come from DFPGA WaitTrigAndSendClock(); PIN_lockRegisters = 1; // block registers during readout #ifdef EVT_TIME_PROFILE Timer prof; prof.start(); int befReadWv=0, aftReadWv=0, befSaveEvt=0, aftSaveEvt=0, befChkPow=0, aftChkPow=0, befNewSeq=0, aftNewSeq=0, endOfLoop=0; #endif if (gReadingOut) { const int32_t ttms = gTrgTimer.read_ms(); // time since last trigger gTrgTimer.reset(); gTrgTimer.start(); // restart trigger timer etms += ttms; Watchdog::kick(); // don't reset! // // got trigger. read registers to mbed and build the event // led4=1; if ( gEvent.IsForcedTrg() || gFirstEvt || (etms>gConf.GetEvtThrtlPeriodMs()) ) { // read data & calc CRC #ifdef EVT_TIME_PROFILE prof.stop(); befReadWv=prof.read_us(); prof.start(); #endif // get the data to the MBED gEvent.ReadWaveforms(PIN_spi, PIN_selCardHiBit, PIN_selCardLoBit); #ifdef EVT_TIME_PROFILE prof.stop(); aftReadWv=prof.read_us(); prof.start(); #endif gEvent.SetCurMbedTime(); // TODO: no way to check for external trigger? if (gEvent.IsForcedTrg()==false) { gEvent.SetTrgBit(kThmTrg); gEvent.SetTrgNum(++(gTrgNum[kThmTrg])); AddToRate(ttms, true); } // else already set by procForceTrigger // (no need to calc if we throw this event away) Watchdog::kick(); // don't reset! #ifdef DEBUG printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); #endif led2=1; /* gRecentCountTime = static_cast<uint32_t>(time(0)); gRecentEvtNum = gEvtNum; // do start time second so that if we get only one event, // the delta(t) will be less than 0 and the rates not calculated if (gDoResetLastCount) { gLastCountReset = static_cast<uint32_t>(time(0)); // to calc rates gLastEventReset = gEvtNum; gDoResetLastCount = false; } */ PIN_lockRegisters = 0; // done reading, unlock so we can talk to SD card. #ifdef EVT_TIME_PROFILE prof.stop(); befSaveEvt=prof.read_us(); prof.start(); #endif SaveEvent(etms); AddToRate(etms, false); etms=0; #ifdef EVT_TIME_PROFILE prof.stop(); aftSaveEvt=prof.read_us(); prof.start(); #endif } } #ifdef DEBUG printf("past reading out\r\n"); #endif if (gHrtbtFired) { SaveHeartbeat(); gHrtbtFired=false; } led4=0; led2=0; #ifdef EVT_TIME_PROFILE prof.stop(); befChkPow=prof.read_us(); prof.start(); #endif // check the power? if (gCheckPower) { #ifdef DEBUG printf("call check power\r\n"); #endif CheckPower(false); } #ifdef EVT_TIME_PROFILE prof.stop(); aftChkPow=prof.read_us(); prof.start(); #endif // open comm win? if (gOpenCommWin) { #ifdef DEBUG printf("gOpenComWin=%s, opening\r\n",gOpenCommWin?"true":"false"); #endif OpenCommWin(); gOpenCommWin=false; gFirstEvt = true; gTrgTimer.reset(); etms=0; } else { #ifdef DEBUG printf("gOpenCommWin=false, gCommWinChecks=%u, gNcommWinChecks=%u\r\n", gCommWinChecks, gNcommWinChecks); #endif } #ifdef EVT_TIME_PROFILE prof.stop(); befNewSeq=prof.read_us(); prof.start(); #endif // make new seq? if (IsSeqComplete()) { #ifdef DEBUG printf("seq complete. sngseq=%d\r\n",gConf.IsSingleSeqRunMode()); #endif MakeOutputFile(gConf.IsSingleSeqRunMode()); gFirstEvt = true; gTrgTimer.reset(); etms=0; } #ifdef EVT_TIME_PROFILE prof.stop(); aftNewSeq=prof.read_us(); prof.start(); #endif #ifdef EVT_TIME_PROFILE prof.stop(); endOfLoop=prof.read_us(); prof.start(); printf("befReadWv=%d, aftReadWv=%d, befSaveEvt=%d, aftSaveEvt=%d, " "befChkPow=%d, aftChkPow=%d, befNewSeq=%d, aftNewSeq=%d, endOfLoop=%d\r\n", befReadWv, aftReadWv, befSaveEvt, aftSaveEvt, befChkPow, aftChkPow, befNewSeq, aftNewSeq, endOfLoop); #endif // get ready to trigger PIN_spi.format( 16, 1 ); // change to data readout format PIN_spi.frequency( 10000000 ); // Max is 12.5 MHz // reset event // clear after comm win, so full event can be sent with status // but don't clear counters or trigger bits, as gEvent.ClearEvent(true); } } // // save a heartbeat tag // void SaveHeartbeat() { if (gHrtbtNum>0) { #ifdef DEBUG printf("save heartbeat #%u, time %u\r\n", gHrtbtNum-1, gLastHrtbt); #endif // save to SD PIN_lockRegisters = 0; // unlock so we can talk to SD card. SnSDUtils::WriteHeartbeatTo(SnSDUtils::GetCurFile(), gLastHrtbt, gHrtbtNum-1); // -1 so it counts from 0 } } // // save the event // void SaveEvent(const int32_t etms) { // write the event #ifdef DEBUG printf("save event\r\n"); #endif // set the event number & dt gEvent.SetEvtNum(gEvtNum); gEvent.SetDTms(etms); // save to SD PIN_lockRegisters = 0; // unlock so we can talk to SD card. SnSDUtils::WriteEventTo(SnSDUtils::GetCurFile(), gGenBuf, gEvent, gConf); // increment event number ++gEvtNum; #ifdef DEBUG printf("gEvtNum=%u\r\n",gEvtNum); #endif } void MakeOutputFile(const bool stopRunning) { PIN_lockRegisters = 0; // unlock so we can talk to SD card. #ifdef DEBUG printf("closing output file. gEvtNum=%u, gPowNum=%u, stop=%d\r\n", gEvtNum,gPowNum,(int)stopRunning); #endif SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile()); #ifdef DEBUG printf("file closed\r\n"); #endif if (stopRunning) { StopRunning(); } FILE* cf = SnSDUtils::OpenNewOutputFile(gConf.GetMacAddress(), gConf.GetRun()); // reset event, timers, trigger counters ResetCountersClearEvt(); if (cf!=0) { wait_ms(200); GetAvePowerReading(); #ifdef DEBUG printf("writing power. v1=%g, v2=%g, r1=%g, r2=%g, t=%u, pownum=%u\r\n", gPower.GetAveV1(), gPower.GetAveV2(), gPower.GetRmsV1(), gPower.GetRmsV2(), gPower.GetTime(), gPowNum); #endif SnSDUtils::WritePowerTo(cf, gPower, gPowNum); } #ifdef DEBUG printf("made output file with run %u\r\n",gConf.GetRun()); printf("filename=%s\r\n",SnSDUtils::GetCurFileName()); #endif SnSDUtils::WriteConfig(SnSDUtils::GetCurFile(), gConf); #ifdef DEBUG printf("write config to file\r\n"); #endif } // // power stuff // void SetPower(const bool isCommWin) { #ifdef DEBUG printf("set power. isCommWin=%s\r\n",(isCommWin)?"true":"false"); printf("bef: pconp=%u (%08x), pcenet=%u (%08x)\r\n", LPC_SC->PCONP, LPC_SC->PCONP, LPC1768_PCONP_PCENET, LPC1768_PCONP_PCENET); printf("pcenet bef power: status=%d\r\n",Peripheral_GetStatus(LPC1768_PCONP_PCENET)); #endif SnConfigFrame::EPowerModeBit cardpb(SnConfigFrame::kCardDatTak), ampspb(SnConfigFrame::kAmpsDatTak), iridpb(SnConfigFrame::kIridDatTak), afarpb(SnConfigFrame::kAfarDatTak); if (isCommWin) { cardpb = SnConfigFrame::kCardComWin; ampspb = SnConfigFrame::kAmpsComWin; iridpb = SnConfigFrame::kIridComWin; afarpb = SnConfigFrame::kAfarComWin; } // TODO: turn on amps individually, when that's possible PIN_turn_on_system = gConf.GetPowPinSetting(cardpb); wait_ms(10); PIN_turn_on_amps = gConf.GetPowPinSetting(ampspb); wait_ms(10); PIN_iridSbd_power = (kIridAfarPwrSame) ? gConf.GetPowPinSetting(iridpb, false) // leave the iridium relay off. use afar relay. : gConf.GetPowPinSetting(iridpb); wait_ms(10); #ifdef DEBUG printf("afar pin=%d, com powsetting=%d\r\n",PIN_afar_power.read(), gConf.GetPowPinSetting(afarpb)); #endif if (gConf.IsPoweredFor(afarpb)) { #ifdef DEBUG printf("PHY cowin powering up\r\n"); #endif PHY_PowerUp(); wait(1); #ifdef DEBUG printf("PHY cowin powered up\r\n"); #endif } else { #ifdef DEBUG printf("PHY cowin powering down\r\n"); #endif PHY_PowerDown(); wait(1); #ifdef DEBUG printf("PHY cowin powered down\r\n"); #endif } #ifdef DEBUG printf("PHY done\r\n"); #endif wait_ms(100); int afpp = gConf.GetPowPinSetting(afarpb); if (kIridAfarPwrSame) { afpp |= gConf.GetPowPinSetting(iridpb); } PIN_afar_power = afpp; wait(1.5); // let things power up #ifdef DEBUG printf("aft: pconp=%u (%08x), pcenet=%u (%08x)\r\n", LPC_SC->PCONP, LPC_SC->PCONP, LPC1768_PCONP_PCENET, LPC1768_PCONP_PCENET); #endif #ifdef DEBUG printf("power word (%hhu): ",gConf.GetPowerMode()); SnBitUtils::printBits(gConf.GetPowerMode(),true); printf("set power (iscom %d, pw %hhu): cards %d, amps %d, irid %d, afar %d\r\n", isCommWin, gConf.GetPowerMode(), PIN_turn_on_system.read(), PIN_turn_on_amps.read(), PIN_iridSbd_power.read(), PIN_afar_power.read()); printf("pcenet aft power: status=%d\r\n",Peripheral_GetStatus(LPC1768_PCONP_PCENET)); #endif } // // set configuration // void SetConfigAndMakeOutputFile() { #ifdef DEBUG printf("SetConfigAndMakeOutputFile\r\n"); #endif // 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); gCommWinChecks = 0; gNcommWinChecks = gConf.GetCommWinPeriod() / kCommWinLongPrdTk; if (AreCardsPowered(true)) { // 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); #ifdef DEBUG printf("pla hi %hu, lo %hu\r\n",hi,lo); #endif } else { PIN_spi.write(kNoTrigPla); // hi PIN_spi.write(kNoTrigPla); // lo #ifdef DEBUG printf("pla hi %hu, lo %hu\r\n",kNoTrigPla,kNoTrigPla); #endif } 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. #ifdef DEBUG printf("setting dacs\r\n"); #endif 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; #ifdef DEBUG printf("dac %04x\r\n",dv); #endif // send to FPGA PIN_start_fpga=1; PIN_spi.write(dv); PIN_start_fpga=0; Watchdog::kick(); } #ifdef DEBUG printf("dacs set\r\n"); #endif wait_ms(20); } else { #ifdef DEBUG printf("cards off. skipping PLA and DAC setting\r\n"); #endif } // 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 // make new output file // put after PLA/DAC, in case they affect the power readings wait_ms(200); MakeOutputFile(); // reset tickers ResetAllTickers(); Watchdog::kick(); // don't reset! #ifdef DEBUG printf("set config done\r\n"); #endif } // // readout functions // void WaitTrigAndSendClock() { #ifdef DEBUG printf("WaitTrigAndSendClock\r\n"); printf("wait trig: (pw %hhu): cards %d, amps %d, irid %d, afar %d\r\n", gConf.GetPowerMode(), PIN_turn_on_system.read(), PIN_turn_on_amps.read(), PIN_iridSbd_power.read(), PIN_afar_power.read()); printf("cards powered=%d\r\n",(int)AreCardsPowered(true)); #endif PIN_spi.format( 16, 1 ); // back to trigger mode PIN_spi.frequency( 10000000 ); // Max is 12.5 MHz if (AreCardsPowered(false)) { #ifdef DEBUG printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); #endif 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. // #ifdef DEBUG printf("starting wait for trig\r\n"); #endif gReadingOut = false; // this will allow forced triggers (see procForceTrigger()) while ( PIN_a_sf_clk == 1 ) { if (gOpenCommWin || gCheckPower) { #ifdef DEBUG printf("break com=%d, pow=%d\r\n",gOpenCommWin,gCheckPower); #endif return; // break out to open comms or check power } } //PIN_forceTrigger=0; // necessary for forced triggers, harmless for other triggers gReadingOut = true; // disallow new forced triggers /* #ifdef DEBUG printf("after wait for trig. PIN_a_sf_clk=%d\r\n", PIN_a_sf_clk.read()); #endif */ // we can't be interrupted before data arrives at the MB FPGA //StopAllTickers(); /* procForceTrigger(); procHeartbeat(); procPowerCheck(); procCommWin(); */ //wait_us(5); // // 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) gAdcToMBtimer.start(); for( uint8_t i = 0; i < 128; ++i ) { while (PIN_a_sf_clk==1) {} while (PIN_a_sf_clk==0) {} /* if ((i == 10)&&(gEvtNum % 20)) { wait_us(8); } */ PIN_ADC_CS = 0; PIN_spi.write( 0x00 ); PIN_ADC_CS = 1; /* 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--; } */ } gAdcToMBtimer.stop(); #ifdef DEBUG printf("total time = %d us\r\n", gAdcToMBtimer.read_us()); #endif if ( kAdcToMBtimeCut < gAdcToMBtimer.read_us() ) { gEvent.SetTrgBit(kAdcToMBflag); } gAdcToMBtimer.reset(); // restart the timers //ResetAllTickers(); } else { // cards have no power. don't try reading out gReadingOut=false; } } SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig) { // loop through each comm mode: // a) try to connect // b) if connected, listen for config // c) if config requests data, send it /* for (int i=0; i<5; i++) { led4=1; led3=1; wait(0.5); led4=0; led3=0; wait(0.5); } */ gLastCommWin = time(0); SnCommWin::ECommWinResult res = SnCommWin::kUndefFail; // get the trigger rates float thmrate=0, evtrate=0; GetRates(thmrate, evtrate); #ifdef DEBUG printf("thmrate=%g, evtrate=%g\r\n",thmrate,evtrate); #endif StopAllTickers(); if (gConf.GetCommWinDuration()==0) { // TODO: set min so this is not possible res = SnCommWin::kOkNoMsg; } else { gCommWinOpen = true; Watchdog::kick(); // don't reset! #ifdef DEBUG printf("opening comm window at %d\r\n", (int32_t)gLastCommWin); printf("duration=%u\r\n",gConf.GetCommWinDuration()); #endif // close the file so that the data is all written out. // and open it back up at the beginning (for reading) #ifdef DEBUG printf("close & open file. gEvtNum=%u, gPowNum=%u\r\n",gEvtNum,gPowNum); printf("curfile=%p, filename=%s\r\n",SnSDUtils::GetCurFile(), SnSDUtils::GetCurFileName()); #endif PIN_lockRegisters = 0; // unlock so we can talk to SD card. #ifdef DEBUG printf("closing output file\r\n"); #endif SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile()); #ifdef DEBUG printf("open existing file (%d)\r\n",strlen(SnSDUtils::GetCurFileName())); #endif SnSDUtils::OpenExistingFile(SnSDUtils::GetCurFileName(), true, false); #ifdef DEBUG printf("setting power\r\n"); #endif // (probably) power down cards,amps and power up comms SetPower(true); // time to recount files for the status update SnStatusFrame::fgRecalcFiles = true; #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) bool doTwitter = false; #endif #ifdef DEBUG printf("start loop over comms\r\n"); #endif 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; } // skip if no comm object if ((*cw)==0) { continue; } // skip if no power for this comm // THIS IS VITAL! For example, if the ethernet // port is powered down, making an Ethernet obejct // (done in netif) will stall forever waiting for the clock. // Do it here to keep all PIN usage in main.cpp bool havePower=false; switch ((*cw)->GetCommType()) { case SnConfigFrame::kIrid: havePower = gConf.IsPoweredFor(SnConfigFrame::kIridComWin) && ( (kIridAfarPwrSame) ? PIN_afar_power.read() : PIN_iridSbd_power.read() == gConf.GetPowPinSetting(SnConfigFrame::kIridComWin)); break; case SnConfigFrame::kAfar: havePower = gConf.IsPoweredFor(SnConfigFrame::kAfarComWin) && (PIN_afar_power.read() == gConf.GetPowPinSetting(SnConfigFrame::kAfarComWin)); break; case SnConfigFrame::kUSB: havePower = true; // USB always on (for now) break; case SnConfigFrame::kSDcard: // shouldn't happen. skip it default: // unknown.. skip it break; }; if (havePower==false) { continue; } const uint32_t conto = (gConf.GetCommWinDuration() < (*cw)->GetConnectTimeout()) ? gConf.GetCommWinDuration() : (*cw)->GetConnectTimeout(); const uint32_t listo = (gConf.GetCommWinDuration() < (*cw)->GetListenTimeout()) ? gConf.GetCommWinDuration() : (*cw)->GetListenTimeout(); // update power reading in case we want to send it in status GetAvePowerReading(); // open window and (mabye) send status update #ifdef DEBUG printf("calling OpenWindow. ss=%d\r\n",(int)(*ss)); printf("gtt=%u, ct=%d, lcw=%d, dur=%u\r\n",gConf.GetTimeoutTime(gLastCommWin,conto), time(0), gLastCommWin, gConf.GetCommWinDuration()); #endif const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow( gConf.GetTimeoutTime(gLastCommWin, conto), *ss, gConf, gEvent, gPower, SnSDUtils::GetCurSeqNum(), thmrate, evtrate, gGenBuf); if (conres>=SnCommWin::kConnected) { Watchdog::kick(); // don't reset! // connected. listen for config *ss = false; // don't send status next time #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) if ((*cw)->GetCommType()==SnConfigFrame::kAfar) { // if we connected by Afar doTwitter = true; } #endif #ifdef DEBUG printf("get conf gtt=%u\r\n",gConf.GetTimeoutTime(gLastCommWin, listo)); #endif const SnCommWin::ECommWinResult cfgres = (*cw)->GetConfig( gConf, gConf.GetTimeoutTime(gLastCommWin, listo), gGenBuf, gBufSize); if (cfgres>=SnCommWin::kOkWithMsg) { Watchdog::kick(); // don't reset! #ifdef DEBUG printf("received config!\r\n"); printf("send data = %d\r\n", gConf.GetCommSendData()); #endif // send data if need be (files, some events, etc) const uint32_t winto = gConf.GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration()); const uint32_t gtt = gConf.IsObeyingTimeout() ? winto : 0; if (gConf.GetCommSendData()!=0) { #ifdef DEBUG printf("sending data, gtt=%u. lcw=%u, dur=%u, obey=%s\r\n", gConf.GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration()), gLastCommWin, gConf.GetCommWinDuration(), gConf.IsObeyingTimeout() ? "true" : "false"); #endif res = (*cw)->SendData(gConf, gEvent, gPower, gGenBuf, gBufSize, gtt, gConf.GetCommWinDuration()); } else { // don't send anything res = cfgres; } #ifdef DEBUG printf("Got config!\r\n"); #endif Watchdog::kick(); // don't reset! break; } } else { (*cw)->CloseConn(gConf.GetTimeoutTime(gLastCommWin, listo)); } // if connected Watchdog::kick(); // don't reset! } // end loop over comms // check Iridium time & close the connection(s) cw = gComms; for (uint8_t i=0; i<kNcomms; i++, cw++) { if ((*cw)==0) { continue; } // check Iridium time if ((*cw)->GetCommType()==SnConfigFrame::kIrid) { #ifdef DEBUG printf("try to set iridium time\r\n"); #endif // set the clock before closing connection const bool con = (*cw)->Connect(gConf.GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration())); if (con) { const uint32_t nt = (*cw)->TrySetSysTimeUnix( gConf.GetTimeoutTime(gLastCommWin,gConf.GetCommWinDuration())); } } // close the connection (*cw)->CloseConn(gConf.GetTimeoutTime(gLastCommWin,gConf.GetCommWinDuration())); Watchdog::kick(); // don't reset! // after normal Afar connection closed, try to tweet #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) if ((*cw)->GetCommType()==SnConfigFrame::kAfar) { // tweet #ifdef DEBUG printf("for twitter: gTwit=%p, doTwitter=%d\r\n",gTwit,(int)doTwitter); #endif // send a twitter update if ( (gTwit!=0) && doTwitter ) { const uint32_t conto = (gConf.GetCommWinDuration() < gTwit->GetConnectTimeout()) ? gConf.GetCommWinDuration() : gTwit->GetConnectTimeout(); const uint32_t listo = (gConf.GetCommWinDuration() < gTwit->GetListenTimeout()) ? gConf.GetCommWinDuration() : gTwit->GetListenTimeout(); #ifdef DEBUG printf("open twit window. conto=%u, listo=%u\r\n", conto, listo); #endif const SnCommWin::ECommWinResult conres = gTwit->OpenWindow( gConf.GetTimeoutTime(gLastCommWin, conto), false, gConf, gEvent, gPower, SnSDUtils::GetCurSeqNum(), thmrate, evtrate, gGenBuf); if (conres>=SnCommWin::kConnected) { Watchdog::kick(); // don't reset! gTwit->Tweet(gConf, thmrate, evtrate, gGenBuf, gConf.GetTimeoutTime(time(0), listo)); } } } #endif } } // if duration >0 /* not working. must use DEFCONF.DAT to change IP's. // change comm parameters (IP addresses) #ifdef DEBUG printf("set comm params\r\n"); #endif for (uint8_t cc=0; cc<kNcomms; cc++) { if (gComms[cc]!=0) { gComms[cc]->Set(gConf); } } */ // (probably) power down comms and power up cards,amps SetPower(false); // reset config with system powered (for DAC/PLA setting) #ifdef DEBUG printf("calling SetConfigAndMakeOutputFile\r\n"); #endif SetConfigAndMakeOutputFile(); #ifdef DEBUG printf("closing comm win at %d\r\n",(int32_t)time(0)); #endif gCommWinOpen = false; return res; }