Arianna autonomous DAQ firmware
Dependencies: mbed SDFileSystemFilinfo AriSnProtocol NetServicesMin AriSnComm MODSERIAL PowerControlClkPatch DS1820OW
main.cpp
- Committer:
- uci1
- Date:
- 2015-11-24
- Revision:
- 110:d1da040a0cf2
- Parent:
- 100:3a27edf9ce16
- Child:
- 114:554fa3a956b4
File content as of revision 110:d1da040a0cf2:
#include "mbed.h" const uint32_t gPowerOnTime( time(0) ); // start a watchdog as soon as possible #include "Watchdog.h" Watchdog::SnKickStarter gKickStarter(WDFAILSAFE); // CHIPBOARD is defined in SnPreCompOptions.h #include <stdint.h> #include "SnConstants.h" #ifndef USE_INTERFACE_CHIP // to avoid calling the interface chip, // the mac address is hard coded (ugh!) extern "C" void mbed_mac_address(char * mac) { #ifdef DEBUG printf("calling MY mbed_mac_address\r\n"); #endif memmove(mac, kDefaultMacAdress, sizeof(kDefaultMacAdress)); }; #endif #ifdef DEBUG #include "SnMemMonitor.h" #endif #include "SDFileSystem.h" #ifdef USE_MODSERIAL #define MODSERIAL_RX_BUF_SIZE 512 #define MODSERIAL_TX_BUF_SIZE 512 #include "MODSERIAL.h" #endif // USE_MODSERIAL #include "FATDirHandle.h" #include "EthernetPowerControl.h" #include "SnBitUtils.h" #include "SnSDUtils.h" #include "SnConfigFrame.h" #include "SnEventFrame.h" #include "SnStatusFrame.h" #include "SnHeaderFrame.h" #include "SnHeartbeatFrame.h" #include "SnClockSetFrame.h" #include "SnSignalStrengthFrame.h" #include "SnCommWin.h" #ifdef ENABLE_AFAR_COMM #ifdef USE_ETH_INTERFACE #include "SnCommAfarTCP.h" #else #include "SnCommWinAfar.h" #ifdef ENABLE_AFAR_TWITTER #include "SnCommWinTwitter.h" #endif // ENABLE_AFAR_TWITTER #endif // USE_ETH_INTERFACE #endif // ENABLE_AFAR_COMM #ifdef ENABLE_USB_COMM #include "SnCommWinUsb.h" #endif // ENABLE_USB_COMM #ifdef ENABLE_SBD_COMM #include "SnCommWinSBD.h" #endif // ENABLE_SBD_COMM //#include "SnBase64.h" #ifdef USE_RTOS_TIMER #include "RtosTimer.h" #endif // USE_RTOS_TIMER #include "DS1820.h" #include "SnL1SingleFreqSupp.h" extern "C" void mbed_reset(); // // MBED PINS (ordered by number) // // leds (for debugging) DigitalOut led1(LED1,1); DigitalOut led2(LED2,1); DigitalOut led3(LED3,1); DigitalOut led4(LED4,1); // Set up power pins - Note that it's Zero for "on" in ATWD2013, but high for "on" in SST2014 #if CHIPBOARD==ATWD4CH DigitalOut PIN_turn_on_system(p17,1); // this turns off the system DigitalOut PIN_turn_on_amps(p25,1); // this turns off the amps #else DigitalOut PIN_turn_on_system(p17,0); // this turns off the system DigitalOut PIN_turn_on_amps(p25,0); // this turns off the amps #endif // ATWD4CH // SD card select DigitalOut PIN_SD_CS(p8,0); #if CHIPBOARD==ATWD4CH // Activate/select chip by falling edge DigitalOut PIN_ADC_CS(p9,0); // clock signal to activate PLA setting DigitalOut PIN_PLA_cs(p10,0); #else I2C PIN_i2c(p9, p10); #endif // ATWD4CH // To force a trigger DigitalOut PIN_forceTrigger(p11,0); //modification // To suppress thermal triggers DigitalOut PIN_enableThermTrig(p12,0); #if CHIPBOARD==ATWD4CH // Restart clock on all FPGAs. DigitalOut PIN_DoNotRestartAllClocks(p13,0); #else DigitalOut PIN_ResetChips(p13,0); #endif // ATWD4CH #if CHIPBOARD==ATWD4CH // 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); #else DigitalIn PIN_dataReady(p14); // when triggered data is stored in the mb FPGA and ready for readout by mbed #endif // ATWD4CH // afar power DigitalOut PIN_afar_power(p16,0); // batter voltage/current measurement AnalogIn PIN_vADC1(p19); AnalogIn PIN_vADC2(p18); #if CHIPBOARD==ATWD4CH // Lock daughter card registeres (during data readout). DigitalOut PIN_lockRegisters(p20,0); #else DigitalOut PIN_readingData(p20,0); #endif // ATWD4CH // iridium (SBD) power DigitalOut PIN_iridSbd_power(p21,0); // Majority logic pins DigitalOut PIN_MajLogHiBit(p22,0); DigitalOut PIN_MajLogLoBit(p23,0); // To launch a heartbeat pulse DigitalOut PIN_heartbeat(p24,0); #if CHIPBOARD==ATWD4CH // Tell FPGA to be ready to accept DAC values DigitalOut PIN_start_fpga(p26,0); #else DigitalIn PIN_unused26(p26); #endif // ATWD4CH #if CHIPBOARD==ATWD4CH // Two bits to the select the daughter card for readout DigitalOut PIN_selCardHiBit(p29,0); DigitalOut PIN_selCardLoBit(p30,0); #else DigitalOut PIN_dualOrSingleThresholds(p29, 1); // 1 = dual (hi AND lo thresh crossings) DigitalOut PIN_differentialTrigSignal(p30, 1); // 1 = chip sends one trigger signal per channel with reduced noise, 0 = chip sends each comparator signal separately #endif // ATWD4CH // Setup SPI pins SPI PIN_spi( p5, p6, p7 ); #if CHIPBOARD==SST4CH PinName gThermPinName(p15); DS1820 PIN_therm(gThermPinName, gThermPinName, false); // be default, on external power #endif // we have to do this shit because Serial and MODSERIAL don't have virtual functions // so calling, e.g. readable from a Serial* will call Serial::readable instead of MODSERIAL::readable // and the comms will wait forever #ifdef USE_MODSERIAL #define MAIN_SERIALTYPE AjK::MODSERIAL #else #define MAIN_SERIALTYPE Serial #endif // USE_MODSERIAL // this needs to be first in case some other global uses a print statement static MAIN_SERIALTYPE gCpu( USBTX, USBRX ); // defined here so it might be used for debugging output static MAIN_SERIALTYPE gSBDport(p28, p27, #ifdef USE_MODSERIAL MODSERIAL_TX_BUF_SIZE, MODSERIAL_RX_BUF_SIZE, #endif // USE_MODSERIAL "sbd"); // The SD card static SDFileSystem sd(p5, p6, p7, p8, SnSDUtils::kSDdir+1); // no leading '/' // local file system is still created even if USE_INTERFACE_CHIP is not defined // this is done to allow the mbed to be reprogrammed remotely 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, const bool isStartupWin=false); void MakeOutputFile(const bool stopRunning=false); bool IsPowerAllowedFor(const bool isCommWin, const uint8_t devicesInUse, const SnConfigFrame::EDatPackBit b); void SetPower(const bool isCommWin, const uint8_t devicesInUse); void CheckPower(const bool isCommWin, const bool saveReading=true, const uint8_t devicesInUse= SnConfigFrame::kIrid | SnConfigFrame::kAfar); void CheckTemp(); void UpdateTemperature(); bool AreCardsPowered(const bool checkPin); void GetAvePowerReading(); #if CHIPBOARD==SST4CH void InitTempProbe(); #endif void ResetCountersClearEvt(); void CalcRate(const uint32_t numtrgs, const double tottime_ms, float& rate); void GetRates(float& thmrate, float& evtrate); void AddToRate(const double dt, const bool isThm); bool IsSeqComplete(); void procForceTrigger(); void procHeartbeat(); void procPowerCheck(); void procTempCheck(); void procCommWin(); #ifdef USE_RTOS void procForceTrigger(void const *) { return procForceTrigger(); } void procHeartbeat(void const *) { return procHeartbeat(); } void procPowerCheck(void const *) { return procPowerCheck(); } void procCommWin(void const *) { return procCommWin(); } void procTempCheck(void const *) { return procTempCheck(); } #endif // USE_RTOS // // globals // // readout objs // TODO: use RtosTimer instead of Ticker? #ifdef USE_RTOS static rtos::RtosTimer* gForceTicker; static rtos::RtosTimer* gHeartbeatTicker; static rtos::RtosTimer* gCommWinTicker; static rtos::RtosTimer* gPowerCheckTicker; static rtos::RtosTimer* gTempCheckTicker; #else static Ticker gForceTicker; static Ticker gHeartbeatTicker; static Ticker gCommWinTicker; static Ticker gPowerCheckTicker; static Ticker gTempCheckTicker; #endif // USE_RTOS static Timer gAllTrgTimer; static Timer gThmTrgTimer; static Timer gAdcToMBtimer; static Timer gSinceClkSet; static SnClockSetFrame gClkSet; static SnSignalStrengthFrame gSigStr; #ifdef DISABLE_CONFIG_SAFETYNETS static SnConfigFrame gConf(false); static SnConfigFrame gConfCopy(false); #else static SnConfigFrame gConf; static SnConfigFrame gConfCopy; #endif // DISABLE_CONFIG_SAFETYNETS static SnEventFrame gEvent; //static SnEventFrame gLastEvent; static SnPowerFrame gPower; static SnTempFrame gTemperature; // parameters static bool gCardsPowered = false; static bool gFirstEvt = true; static volatile bool gReadingOut = false; // if data is being read from the FPGA 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 volatile bool gCheckTemp = false; // if it should be checked static uint32_t gPowNum = 0; static uint32_t gEvtNum = 0; // num of evt written static volatile bool gForcedTrig = false; // forced trigger bit static volatile bool gAdcToMBflag = false; // flag in case getting the ADC values took too long //static uint32_t gTrgNum[kNumTrgs] = {0}; // num of this type of trg received static uint32_t gNumThmTrigs = 0; // number of thermal triggers counted static uint32_t gNumFrcTrigs = 0; // number of forced triggers counted static uint8_t gL1ScaledownCount = 0; // write an event every X L1 failures // i/o static time_t gLastCommWin = 0; // time static uint32_t gCommWinChecks = 0; static uint32_t gNcommWinChecks = 0; static uint16_t gConsecCommFails = 0; // heartbeat static SnHeartbeatFrame gHrtbt; 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 + SnEventFrame::kMaxSizeOf // (this is redundant and could be removed if mem is sparse) + 256; // breathing room 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 static float gChanFFT[kNsamps] = { 0 }; // only one chan at a time to save RAM // status update data cache and flags static SnClockSetFrame gStTrgStartClk; static SnClockSetFrame gStTrgStopClk; static SnPowerFrame gStPower; static SnTempFrame gStTemperature; static volatile bool gStNewPower(false); static volatile bool gStNewEvent(false); static volatile bool gStNewHeartbeat(false); static volatile bool gStNewTemperature(false); #ifdef EVT_TIME_PROFILE Timer gProfiler; #endif void procForceTrigger() { if (gReadingOut==false && gCommWinOpen==false) { led3=!led3; #ifdef DEBUG printf("proc force\r\n"); #if CHIPBOARD==ATWD4CH 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()); #else printf("PIN_forceTrigge=%d, PIN_turn_on_system=%d, " "PIN_dataReady=%d\r\n", PIN_forceTrigger.read(), PIN_turn_on_system.read(), PIN_dataReady.read()); #endif // ATWD4CH #endif gForcedTrig = true; ++gNumFrcTrigs; // ++(gTrgNum[kFrcTrg]); // gEvent.SetTrgBit(kFrcTrg); // gEvent.SetTrgNum(++(gTrgNum[kFrcTrg])); //PIN_forceTrigger = 0; PIN_forceTrigger = 1; // force a trigger PIN_forceTrigger = 0; } } void procHeartbeat() { if (gReadingOut==false && gCommWinOpen==false) { #ifdef DEBUG printf("proc heartbeat\r\n"); #endif led3=!led3; //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 led3=!led3; gCheckPower=true; } void procTempCheck() { #ifdef DEBUG printf("proc temp check\r\n"); #endif led3=!led3; gCheckTemp=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 call: PIN_turn_on_system=%d, gCardsPowered=%d\r\n", PIN_turn_on_system.read(), gCardsPowered); #endif if (checkPin) { #if CHIPBOARD==ATWD4CH gCardsPowered = (PIN_turn_on_system.read()==0); #else gCardsPowered = (PIN_turn_on_system.read()==1); #endif // ATWD4CH } #ifdef DEBUG printf("acp return: PIN_turn_on_system=%d, gCardsPowered=%d\r\n", PIN_turn_on_system.read(), gCardsPowered); #endif 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)); #ifdef DEBUG printf("ave power. v1=%g, v2=%g, r1=%g, r2=%g, t=%u\r\n", gPower.GetAveV1(), gPower.GetAveV2(), gPower.GetRmsV1(), gPower.GetRmsV2(), gPower.GetTime()); #endif } #if CHIPBOARD==SST4CH void InitTempProbe() { #ifdef DEBUG printf("setting temp probe power mode\r\n"); #endif // set power style for temperature probe PIN_therm.set_use_parasite_power( gConf.IsTempUsingParasitePower() ); // setup the probe #ifdef DEBUG printf("calling therm probe search_ROM_setup\r\n"); #endif PIN_therm.search_ROM_setup(); const int tsr = PIN_therm.search_ROM(); // this is necessary for some reason #ifdef DEBUG printf("search ROM = %d\r\n", tsr); #endif } #endif void UpdateTemperature() { // ask chip to convert temperature #if CHIPBOARD==SST4CH PIN_therm.convert_temperature(true, DS1820::all_devices); gTemperature.SetTempAndTime( PIN_therm.temperature('c'), time(0) ); #ifdef DEBUG printf("TTTTTTTT temp = %g at %u\r\n", gTemperature.GetTemperature(), gTemperature.GetTime()); #endif #else return; // do nothing #endif } void CheckTemp() { #ifdef DEBUG printf("CheckTemp\r\n"); #endif UpdateTemperature(); // save to disk FILE* cf = SnSDUtils::GetCurFile(); if (cf!=0) { #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif // ATWD4CH #ifdef DEBUG printf("writing temp. temp = %g at %u\r\n", gTemperature.GetTemperature(), gTemperature.GetTime()); #endif SnSDUtils::WriteTempTo(cf, gTemperature); } gCheckTemp = false; } void CheckPower(const bool isCommWin, const bool saveReading, const uint8_t devicesInUse) { #ifdef DEBUG printf("CheckPower\r\n"); #endif // read power GetAvePowerReading(); if (saveReading) { // save to disk FILE* cf = SnSDUtils::GetCurFile(); if (cf!=0) { #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif // ATWD4CH #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()) { #ifdef DEBUG printf("in low pwr. v1=%g, fromLP=%hu\r\n", gPower.GetAveV1(), gConf.GetBatVoltFromLowPwr()); #endif if (gPower.GetAveV1() > gConf.GetBatVoltFromLowPwr()) { #ifdef DEBUG printf("chaing to normal power!\r\n"); #endif gConf.ChangeToNormPower(); changed = true; } } else { #ifdef DEBUG printf("in normal pwr. v1=%g, toLP=%hu\r\n", gPower.GetAveV1(), gConf.GetBatVoltToLowPwr()); #endif if (gPower.GetAveV1() < gConf.GetBatVoltToLowPwr()) { #ifdef DEBUG printf("chaing to low power!\r\n"); #endif gConf.ChangeToLowPower(); changed = true; } } if (changed) { SetPower(isCommWin, devicesInUse); // 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 ResetCounters() { const uint32_t evtStartCurSeq = (SnSDUtils::GetCurSeqNum()) // no -1; start with seq=0 * gConf.GetEvtsPerFile(); // gEvent.ClearEvent(); gEvtNum = evtStartCurSeq; gPowNum = evtStartCurSeq; // memset(gTrgNum, 0, sizeof(uint32_t)*kNumTrgs); gNumThmTrigs = 0; gNumFrcTrigs = 0; gForcedTrig = false; // reset rate counters gThmDtSum = 0; gThmNumDt = 0; gEvtDtSum = 0; gEvtNumDt = 0; // reset heartbeat counters gLastHrtbt = 0; gHrtbtFired = false; gHrtbtNum = 0; // reset status data caches gStNewPower = false; gStNewEvent = false; gStNewHeartbeat = false; gStNewTemperature = false; #ifdef DEBUG printf("Reset: gEvtNum=%u, gPowNum=%u, evtStartCS=%u\r\n", gEvtNum, gPowNum, evtStartCurSeq); #endif } void CalcRate(const uint32_t numtrgs, const double tottime_ms, float& rate) { rate = 0; if (numtrgs>1) { if (tottime_ms>0.0) { rate = static_cast<float>(numtrgs) / (tottime_ms/1e3); } else { // lots of triggers in 0 time rate = 1e6; } } } 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 CalcRate(gThmNumDt, gThmDtSum, thmrate); CalcRate(gEvtNumDt, gEvtDtSum, evtrate); } void AddToRate(const double 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=%hu, cntpow=%d, pow=%u, evt=%u, seq=%hu\r\n", gConf.GetEvtsPerFile(), (int)gConf.IsCountingPowerReadings(), 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>=evtEndCurSeq); } } else { return false; } } #ifdef USE_RTOS void stopTicker(rtos::RtosTimer* tik) { if (tik!=0) { tik->stop(); } } #else void stopTicker(Ticker& tik) { tik.detach(); } #endif // USE_RTOS #ifdef USE_RTOS 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 // USE_RTOS void StopAllTickers() { stopTicker(gForceTicker); stopTicker(gHeartbeatTicker); stopTicker(gCommWinTicker); stopTicker(gPowerCheckTicker); stopTicker(gTempCheckTicker); } void ResetAllTickers() { #ifdef USE_RTOS const float ftp = resetTicker(gForceTicker, gConf.GetForceTrigPeriod(), kAbsMaxTimer); Thread::wait(131); // make it less likely for multiple triggers to fire too close together const float hbp = resetTicker(gHeartbeatTicker, gConf.GetHeartbeatPeriod(), kAbsMaxTimer); Thread::wait(173); // make it less likely for multiple triggers to fire too close together const float cwp = resetTicker(gCommWinTicker, gConf.GetCommWinPeriod(), kCommWinLongPrdTk); Thread::wait(169); // make it less likely for multiple triggers to fire too close together const float pcp = resetTicker(gPowerCheckTicker, gConf.GetVoltCheckPeriod(), kAbsMaxTimer); Thread::wait(143); // make it less likely for multiple triggers to fire too close together const float ctp = resetTicker(gTempCheckTicker, gConf.GetTempCheckPeriod(), 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); wait_ms(143); // make it less likely for multiple triggers to fire too close together const float ctp = resetTicker(gTempCheckTicker, gConf.GetTempCheckPeriod(), kAbsMaxTimer, &procTempCheck); #endif // USE_RTOS #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); printf("attach temp chk %g\r\n",ctp); #endif } /* void UponBrownout() { // signal brownout by all LEDs off led1 = led2 = led3 = led4 = 0; // note that debug printing here is pointless, // since power over USB will prevent brownout // close the current file #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(), gClkSet, false); SnSDUtils::CloseOutputFile(SnSDUtils::GetCurFile()); // change to low power settings gConf.ChangeToLowPower(); // actually power stuff down SetPower(gCommWinOpen); // goodnight Sleep(); } */ void StopRunning() { #if defined(DEBUG) || defined(SSNOTIFY) printf("stop running\r\n"); #endif StopAllTickers(); OpenCommWin(); while (true) { led3 = 1; led4=1; #ifdef USE_RTOS Thread::wait(500); #else wait(0.5); #endif // USE_RTOS led3 = 0; led4=0; #ifdef USE_RTOS Thread::wait(500); #else wait(0.5); #endif // USE_RTOS // don't kick the watchdog // if we do, the station is unrecoverable without physical access } } int InitSDCard() { #ifdef DEBUG printf("initializing SD card..\r\n"); #endif int ret = 1; // always fail if ignoring the SD card (1==fail) if (gConf.IsIgnoringSDcard()==false) { // initialize the SD card. this should prevent the issue with // seq 0 being overwritten upon power up or the SD card first // being insterted ret = sd.disk_initialize(); // may need to try a bunch of times to get it to init for (int i=0; i<25 && (ret!=0); ++i) { ret = sd.disk_initialize(); #ifdef DEBUG printf("called disk_initialize (ret=%d)\r\n",ret); #endif } } #ifdef DEBUG printf("init SD card %d..\r\n", ret); #endif return ret; } int main() { // a failsafe //Watchdog::kick(WDFAILSAFE); #ifdef DEBUG printf("Restart watchdog with time [%u] at [%u]\r\n", gConf.GetWatchdogPeriod(), time(0)); printf("Free memory = %d\r\n", FreeMem()); #endif Watchdog::kick(gConf.GetWatchdogPeriod()); gCpu.baud(CPUBAUD_SN); { #if defined(SSNOTIFY) || defined(DEBUG) printf("\n\n\n\n\nmain: start\r\n"); #endif led1=led2=led3=led4=0; #ifdef USE_RTOS led1=1; Thread::wait(200); led1=0; led2=1; Thread::wait(200); led2=0; led3=1; Thread::wait(200); led3=0; led4=1; Thread::wait(200); #else 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); #endif // USE_RTOS led4=0; } // signal startup before first comm win led2 = led1 = 1; // don't initialize yet, but give SnSDUtils a pointer to // the function that initializes it, so it can call the fcn later SnSDUtils::fgDoInit = &InitSDCard; // check in case we need to go to low power //wait(4); // TODO: the vADCs read high for first ~4-5sec CheckPower(false, false); #ifdef DEBUG printf("startup power: cards %d, amps %d, irid %d, afar %d\r\n", PIN_turn_on_system.read(), PIN_turn_on_amps.read(), PIN_iridSbd_power.read(), PIN_afar_power.read()); #endif /* // Note: the brownout isn't useful since it sees either 5V or nothing on our board // set up the brownout interrupt NVIC_SetVector(BOD_IRQn, (uint32_t)&UponBrownout); // Enable Brown Out Detect Interrupt NVIC_EnableIRQ(BOD_IRQn); */ #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 #ifdef DEBUG printf("making SnCommAfarTCP\r\n"); #endif gComms[comi++] = new SnCommAfarTCP(gConf); #else #ifdef DEBUG printf("making SnCommWinAfar\r\n"); #endif //gComms[comi++] = new SnCommAfarNetIf(gConf); gComms[comi++] = new SnCommWinAfar(gConf); #ifdef ENABLE_AFAR_TWITTER #ifdef DEBUG printf("making SnCommAfarNetIfTwitter\r\n"); #endif gTwit = new SnCommAfarNetIfTwitter(gConf); #endif // ENABLE_AFAR_TWITTER #endif // USE_ETH_INTERFACE #endif // ENABLE_AFAR_COMM #ifdef ENABLE_SBD_COMM #ifdef DEBUG printf("making SnCommWinSBD\r\n"); #endif gComms[comi++] = new SnCommWinSBD(&gSBDport); #endif // ENABLE_SBD_COMM #ifdef ENABLE_USB_COMM #ifdef DEBUG printf("makin SnCommWinUsb\r\n"); #endif gComms[comi++] = new SnCommWinUsb(&gCpu); #endif // ENABLE_USB_COMM #ifdef DEBUG printf("made comm objects\r\n"); #ifdef USE_MODSERIAL printf("using MODSERIAL\r\n"); #endif // USE_MODSERIAL #endif if (comi!=kNcomms) { error("comi=[%hhu] != kNcomms=[%hhu]\r\n", comi, kNcomms); // will die here with blue lights of death } #ifdef USE_RTOS gForceTicker = new rtos::RtosTimer(&procForceTrigger); gHeartbeatTicker = new rtos::RtosTimer(&procHeartbeat); gCommWinTicker = new rtos::RtosTimer(&procCommWin); gPowerCheckTicker = new rtos::RtosTimer(&procPowerCheck); gTempCheckTicker = new rtos::RtosTimer(&procTempCheck); #endif // USE_RTOS // 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 gForceTicker->stop(); #else gForceTicker.detach(); #endif // USE_RTOS gFirstEvt = true; #ifdef DEBUG printf("MAC=%012llX\r\n", (gConf.GetMacAddress())>>16); // 64 -> 48 bits printf("my ip = %s\r\n", gConf.GetMbedIP()); printf("my mask = %s\r\n", gConf.GetMbedMask()); printf("my gate = %s\r\n", gConf.GetMbedGate()); printf("remote server = %s : %hu\r\n", gConf.GetRemoteServer(), gConf.GetRemotePort()); for (uint8_t i=0; i<SnConfigFrame::kNumDatStreams; ++i) { printf("data stream %hhu (%s): connectTO=%hhu, listenTO=%hhu\r\n", i, SnConfigFrame::GetDataStreamNameOfIdx(i), gConf.GetCommWinConnectTOofIdx(i), gConf.GetCommWinListenTOofIdx(i)); } #endif // (probably) power down comms and power up cards,amps SetPower(false, SnConfigFrame::kIrid | SnConfigFrame::kAfar); // check power again to see if voltages drooped CheckPower(false, false); // // get config // #ifdef DEBUG printf("run mode\r\n"); printf("IsCountingPowerReadings=%d\r\n",(int)gConf.IsCountingPowerReadings()); printf("IsSingleSeqRunMode=%d\r\n",(int)gConf.IsSingleSeqRunMode()); printf("IsDualThresholdMode=%d\r\n",(int)gConf.IsDualThresholdMode()); printf("IsDifferentialTrigMode=%d\r\n",(int)gConf.IsDifferentialTrigMode()); printf("IsSBDonlyLowPwrMode=%d\r\n",(int)gConf.IsSBDonlyLowPwrMode()); printf("IsRunSeqListOneCommWinOnly=%d\r\n",(int)gConf.IsRunSeqListOneCommWinOnly()); printf("IsIgnoringSDcard=%d\r\n",(int)gConf.IsIgnoringSDcard()); printf("IsCommPowerSimple=%d\r\n",(int)gConf.IsCommPowerSimple()); printf("call OpenCommWin\r\n"); printf("Free memory = %d\r\n", FreeMem()); #endif led2 = led1 = 0; // back to "normal" for comm win OpenCommWin(true, 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 // read and cache the dCard power pin setting, // so we can use the cached value later AreCardsPowered(true); // TODO: should this be an if? register double etms=0; // time between written events // the main event loop. wait for triggers in SendClock while ( true ) { // in here, we wait for triggers from the MB-FPGA Watchdog::kick(); // don't reset! led1 = 1; // signal normal running (i.e. waiting) #ifdef DEBUG printf("calling wait trig\r\n"); printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); printf("readingout=%d\r\n",(int)gReadingOut); printf("Free memory = %d\r\n", FreeMem()); #endif if (gFirstEvt) { #ifdef DEBUG printf("WriteTrigWaitWinTime (start)\r\n"); #endif gClkSet.UpdateClock( gSinceClkSet ); SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(), gClkSet, true); gThmTrgTimer.reset(); gThmTrgTimer.start(); gAllTrgTimer.reset(); gAllTrgTimer.start(); gStTrgStartClk = gClkSet; #if CHIPBOARD==SST4CH // reset in case a trigger arrived before we were ready // this is mostly to ensure that the chip gets reset on soft // reboot, in case it got stopped prior to the reboot PIN_ResetChips = 1; PIN_ResetChips = 0; #endif } #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // allow data to come from DFPGA WaitTrigAndSendClock(); // wait for trigger and move data to MB. this returns immediately if cards are powered off PIN_lockRegisters = 1; // block registers during readout #else PIN_readingData = 0; // not reading yet WaitTrigAndSendClock(); // wait for trigger. this returns immediately if cards are powered off // PIN_readingData will be set high by SnEventFrame::ReadWaveformsSST #endif // ATWD4CH #ifdef EVT_TIME_PROFILE gProfiler.start(); int befSaveEvt=0, aftSaveEvt=0, befChkPow=0, aftChkPow=0, befNewSeq=0, aftNewSeq=0, endOfLoop=0; #endif // EVT_TIME_PROFILE if (gReadingOut) { led1 = 0; led4 = 1; // signal reading out const double ttms = gThmTrgTimer.read_us() / 1e3; // for rate calculation const double atms = gAllTrgTimer.read_us() / 1e3; // for throttle // if (gEvent.IsForcedTrg()==false) { if (gForcedTrig==false) { // don't reset if not a thermal trigger gThmTrgTimer.reset(); gThmTrgTimer.start(); } gAllTrgTimer.reset(); gAllTrgTimer.start(); // restart trigger timer etms += atms; // time between events Watchdog::kick(); // don't reset! // // got trigger. read registers to mbed and build the event // // TODO: no way to check for external trigger? if (gForcedTrig==false) { // ++(gTrgNum[kThmTrg]); ++gNumThmTrigs; AddToRate(ttms, true); } if ( gForcedTrig || gFirstEvt || (etms>=gConf.GetEvtThrtlPeriodMs()) ) { #ifdef EVT_TIME_PROFILE gProfiler.stop(); befSaveEvt=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE // want to keep this event. save it (and check if it passes L1) SaveEvent(etms); AddToRate(etms, false); etms=0; #ifdef EVT_TIME_PROFILE gProfiler.stop(); aftSaveEvt=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE } else { #if CHIPBOARD==SST4CH // reset in case a trigger arrived before we were ready PIN_ResetChips = 1; PIN_ResetChips = 0; #endif } // done with this event. // reset flags from the "old" event gForcedTrig = false; gAdcToMBflag = false; led1 = 1; led4 = 0; // end signal reading out } #ifdef DEBUG printf("past reading out\r\n"); #endif if (gHrtbtFired) { led1 = 1; led4 = 1; // signal saving transient gHrtbt.SetTime( gLastHrtbt ); // -1 so we start counting at 0 // counting inside proc so we have a record of the number of proc's // even if we are saving/triggering slower than they're firing gHrtbt.SetNum( (gHrtbtNum>0) ? (gHrtbtNum - 1) : 0 ); SaveHeartbeat(); gHrtbtFired=false; gStNewHeartbeat = true; led1 = 1; led4 = 0; // end signal saving transient } #ifdef EVT_TIME_PROFILE gProfiler.stop(); befChkPow=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE // check the power? if (gCheckPower) { #ifdef DEBUG printf("call check power\r\n"); #endif led1 = 1; led4 = 1; // signal saving transient CheckPower(false); gStPower = gPower; gStNewPower = true; led1 = 1; led4 = 0; // end signal saving transient } #ifdef EVT_TIME_PROFILE gProfiler.stop(); aftChkPow=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE if (gCheckTemp) { #ifdef DEBUG printf("call check temp\r\n"); #endif led1 = 1; led4 = 1; // signal saving transient CheckTemp(); gStTemperature = gTemperature; gStNewTemperature = true; led1 = 1; led4 = 0; // end signal saving transient } // open comm win? if (gOpenCommWin) { #ifdef DEBUG printf("gOpenComWin=%s, opening\r\n",gOpenCommWin?"true":"false"); printf("WriteTrigWaitWinTime (stop)\r\n"); #endif gClkSet.UpdateClock( gSinceClkSet ); SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(), gClkSet, false); gStTrgStopClk = gClkSet; led1 = 0; // signal not waiting OpenCommWin(); led1 = 1; // end signal not waiting gOpenCommWin=false; gFirstEvt = true; gAllTrgTimer.reset(); gThmTrgTimer.reset(); etms=0; } else { #ifdef DEBUG printf("gOpenCommWin=false, gCommWinChecks=%u, gNcommWinChecks=%u\r\n", gCommWinChecks, gNcommWinChecks); #endif } #ifdef EVT_TIME_PROFILE gProfiler.stop(); befNewSeq=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE // make new seq? if (IsSeqComplete()) { #ifdef DEBUG printf("seq complete. sngseq=%d\r\n",gConf.IsSingleSeqRunMode()); printf("WriteTrigWaitWinTime (stop)\r\n"); #endif led1 = 1; led2 = 1; led4 = 1; // signal saving file gClkSet.UpdateClock( gSinceClkSet ); SnSDUtils::WriteTrigWaitWinTime(SnSDUtils::GetCurFile(), gClkSet, false); gStTrgStopClk = gClkSet; MakeOutputFile(gConf.IsSingleSeqRunMode()); gFirstEvt = true; gThmTrgTimer.reset(); gAllTrgTimer.reset(); etms=0; led1 = 1; led2 = 0; led4 = 0; // end signal saving file } #ifdef EVT_TIME_PROFILE gProfiler.stop(); aftNewSeq=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE #ifdef EVT_TIME_PROFILE gProfiler.stop(); endOfLoop=gProfiler.read_us(); gProfiler.start(); printf("befSaveEvt=%d, aftSaveEvt=%d, " "befChkPow=%d, aftChkPow=%d, befNewSeq=%d, aftNewSeq=%d, endOfLoop=%d\r\n", befSaveEvt, aftSaveEvt, befChkPow, aftChkPow, befNewSeq, aftNewSeq, endOfLoop); #endif // EVT_TIME_PROFILE /* // 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); } // end while (true) } // // save a heartbeat tag // void SaveHeartbeat() { #ifdef DEBUG printf("save heartbeat #%u, time %u\r\n", gHrtbt.GetNum(), gHrtbt.GetTime()); #endif // save to SD #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif SnSDUtils::WriteHeartbeatTo(SnSDUtils::GetCurFile(), gHrtbt); } // // save the event // void SaveEvent(const int32_t etms) { // write the event #ifdef DEBUG // check that the event is still the same as gLastEvent /* bool esame = gEvent.GetMbedTime() == gLastEvent.GetMbedTime(); esame &= gEvent.GetEvtNum() == gLastEvent.GetEvtNum(); esame &= gEvent.GetDTms() == gLastEvent.GetDTms(); esame &= gEvent.GetTrgNum() == gLastEvent.GetTrgNum(); esame &= gEvent.GetTrgBits() == gLastEvent.GetTrgBits(); esame &= gEvent.GetCRC() == gLastEvent.GetCRC(); for (uint16_t i=0; i<kTotSamps; ++i) { esame &= (gEvent.GetData())[i] == (gLastEvent.GetData())[i]; } #if CHIPBOARD!=ATWD4CH for (uint16_t i=0; i<kNstopBytes; ++i) { esame &= (gEvent.GetStop())[i] == (gLastEvent.GetStop())[i]; } printf("EEEEEEEE event==lastEvt = %s\r\n", (esame?"true":"false")); #endif */ #endif // ok, now we can overwrite the old gEvent data // reset event gEvent.ClearEvent(true, true); // read data & calc CRC #ifdef EVT_TIME_PROFILE int befReadWv=0, aftReadWv=0, befWriteEvt=0, aftWriteEvt=0; gProfiler.stop(); befReadWv=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE #if CHIPBOARD==ATWD4CH // get the data to the MBED gEvent.ReadWaveformsATWD(PIN_spi, PIN_selCardHiBit, PIN_selCardLoBit); #else gEvent.ReadWaveformsSST(PIN_spi, PIN_readingData); // reset in case a trigger arrived before we were ready PIN_ResetChips = 1; // wait_us(1); PIN_ResetChips = 0; #endif //ATWD4CH #ifdef EVT_TIME_PROFILE gProfiler.stop(); aftReadWv=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE gEvent.SetCurMbedTime(); Watchdog::kick(); // don't reset! #ifdef DEBUG printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); #endif #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // done reading, unlock so we can talk to the SD card #else // (this is redundant; it's already set low by SnEventFrame) PIN_readingData = 0; // done reading, unlock so we can talk to the SD card #endif // ATWD4CH #ifdef DEBUG printf("waveform read out. save event (%u)\r\n", gEvtNum); #endif // set the event number & dt gEvent.SetEvtNum(gEvtNum); gEvent.SetDTms(etms); // set trigger bits if (gForcedTrig) { gEvent.SetTrgBit(kForced); // gEvent.SetTrgNum(gTrgNum[kFrcTrg]); gEvent.SetTrgNum(gNumFrcTrigs); } else { gEvent.SetTrgBit(kThermal); // gEvent.SetTrgNum(gTrgNum[kThmTrg]); gEvent.SetTrgNum(gNumThmTrigs); } if (gAdcToMBflag) { gEvent.SetTrgBit(kAdcToMBflag); } // this is in the config too, but doesn't hurt to flip the bit // in the event if (gConf.IsL1TrigApplied()) { gEvent.SetTrgBit(kL1TrgApplied); } // ---- // L1 check(s) go here! bool L1okToSave = true; #ifdef DEBUG Timer l1timer; l1timer.start(); printf("L1 single freq supp ratio = %hhu (%g)\r\n", gConf.GetSingleFreqSuppRatioRaw(), gConf.GetSingleFreqSuppRatio()); #endif // TODO: move the FFT calculation out here so that // other L1's could use it too. haven't done this already // in order to save RAM and not cache the whole thing when // we only have one L1 cut. // check L1 single frequency suppression cut if ( gConf.IsSingleFreqSuppEnabled() ) { const EL1TrigStatus passL1SingleFreqSupp = SnL1SingleFreqSupp::ProcessEvent(gEvent, gChanFFT, gConf.GetSingleFreqSuppRatio()); #ifdef DEBUG l1timer.stop(); printf("L1 single freq supp took [%d] us\r\n", l1timer.read_us()); printf("passL1SingleFreqSupp=%s\r\n", passL1SingleFreqSupp==kL1Pass ? "pass" : passL1SingleFreqSupp==kL1Fail ? "fail" : "other"); #endif if (passL1SingleFreqSupp==kL1Pass) { gEvent.SetTrgBit(kSingleFreqSupp); } else if ( (passL1SingleFreqSupp==kL1Fail) && gConf.IsL1TrigApplied() ) { L1okToSave = false; } // else if kL1UnableToProcess, the bit won't get set // but the event can/will be saved } // NO MORE L1 checks below here! (or the scaledown won't work) // ----- #ifdef EVT_TIME_PROFILE gProfiler.stop(); befWriteEvt=gProfiler.read_us(); gProfiler.start(); #endif // EVT_TIME_PROFILE // save to SD #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif // scale down to override L1 trigger failures if ( (L1okToSave==false) && (gConf.GetL1Scaledown()!=0) ) { ++gL1ScaledownCount; if ( gL1ScaledownCount == gConf.GetL1Scaledown() ) { gL1ScaledownCount = 0; L1okToSave = true; #ifdef DEBUG printf("))) L1 scaledown!\r\n"); #endif } } #ifdef DEBUG printf("L1 scaledown count = %hhu, scaledown=%hhu, L1okToSave=%s\r\n", gL1ScaledownCount, gConf.GetL1Scaledown(), L1okToSave ? "true" : "false"); printf("event trigger bits = "); SnBitUtils::printBits(gEvent.GetTrgBits(), true); #endif // always save forced triggers if (L1okToSave || gForcedTrig) { SnSDUtils::WriteEventTo(SnSDUtils::GetCurFile(), gGenBuf, gEvent, gConf); // a good event gStNewEvent = true; // send it? if ( gConf.IsCommWindowEachEvent() ) { #ifdef DEBUG printf("COMM EACH EVENT => gOpenCommWin = true\r\n"); #endif gOpenCommWin = true; } } #ifdef EVT_TIME_PROFILE gProfiler.stop(); aftWriteEvt=gProfiler.read_us(); gProfiler.start(); printf("befReadWv=%d, aftReadWv=%d, befWriteEvt=%d, aftWriteEvt=%d\r\n", befReadWv, aftReadWv, befWriteEvt, aftWriteEvt); #endif // EVT_TIME_PROFILE // make a copy in case we need to send it with the status // (copy it because we are going to clear this event while // waiting for the next trigger) // gEvent.CopyTo(gLastEvent); // increment event number ++gEvtNum; #ifdef DEBUG printf("next gEvtNum=%u\r\n",gEvtNum); #endif } void MakeOutputFile(const bool stopRunning) { #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif #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(SnConfigFrame::GetMacAddress(), gConf.GetRun(), gConf.GetFirstSeq(), gConf.IsSendingFilesRunSeqList()); // reset event, timers, trigger counters ResetCounters(); if (cf!=0) { #ifdef USE_RTOS Thread::wait(200); #else wait_ms(200); #endif 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 } bool PowerDownCommPeriph(const SnConfigFrame::EDatPackBit type) { #ifdef DEBUG printf("PowerDownCommPeriph: type=%d\r\n",(int)type); #endif SnCommWin** cw = gComms; for (uint8_t i=0; i<kNcomms; ++i, ++cw) { if ((*cw)==0) { continue; } else if ((*cw)->GetCommType()==type) { #ifdef DEBUG printf("calling PowerDown\r\n"); #endif return (*cw)->PowerDown(gConf.GetTimeoutTime(time(0), gConf.GetCommWinConnectTO(type))); } } return false; } // // power stuff // bool IsCurrentlyPowered(const SnConfigFrame::EPowerModeBit p, DigitalOut& pin) { // check if the current pin value is equal to // what it should be if the peripheral is on return gConf.GetPowPinSetting(p, true) == pin.read(); } void ChangeCardPower(const bool isCommWin, const bool isOn) { // change cards power const SnConfigFrame::EPowerModeBit pbit = (isCommWin) ? SnConfigFrame::kCardComWin : SnConfigFrame::kCardDatTak; const int value = gConf.GetPowPinSetting(pbit, isOn); #ifdef DEBUG printf("setting cards pin power to %d (comm=%d)\r\n", value, static_cast<int>(isCommWin)); #endif PIN_turn_on_system = value; #ifdef USE_RTOS Thread::wait(10); #else wait_ms(10); #endif } void ChangeAmpsPower(const bool isCommWin, const bool isOn) { // change amps power const SnConfigFrame::EPowerModeBit pbit = (isCommWin) ? SnConfigFrame::kAmpsComWin : SnConfigFrame::kAmpsDatTak; const int value = gConf.GetPowPinSetting(pbit, isOn); #ifdef DEBUG printf("setting amps pin power to %d (comm=%d)\r\n", value, static_cast<int>(isCommWin)); #endif PIN_turn_on_amps = value; #ifdef USE_RTOS Thread::wait(10); #else wait_ms(10); #endif } void ChangeIridPower(const bool isCommWin, const bool isOn) { // change iridium power setting // if going from ON to OFF, call the special // power down procedure, so as not to lose // the non-volatile memory settings const SnConfigFrame::EPowerModeBit ibit = (isCommWin) ? SnConfigFrame::kIridComWin : SnConfigFrame::kIridDatTak; const SnConfigFrame::EPowerModeBit abit = (isCommWin) ? SnConfigFrame::kAfarComWin : SnConfigFrame::kAfarDatTak; // these checks are complicated because the iridium might // be powered off the Afar (12V) relay, // rather than the iridium (5V) relay const bool iridFromOn = (kIridPwrFromAfar) ? IsCurrentlyPowered(abit, PIN_afar_power) : IsCurrentlyPowered(ibit, PIN_iridSbd_power); if ( iridFromOn && (isOn==false) ) { #ifdef DEBUG printf("calling PowerDown for Iridium\r\n"); #endif PowerDownCommPeriph(SnConfigFrame::kIrid); } const int value = (kIridPwrFromAfar) ? gConf.GetPowPinSetting(ibit, false) // leave the iridium relay off. use afar relay. : gConf.GetPowPinSetting(ibit, isOn); #ifdef DEBUG printf("setting iridium pin power to %d (comm=%d)\r\n", value, static_cast<int>(isCommWin)); #endif PIN_iridSbd_power = value; #ifdef USE_RTOS Thread::wait(10); #else wait_ms(10); #endif } void ChangeAfarPower(const bool isCommWin, const bool isOn) { // change the AFAR relay power setting // also power up or down the ethernet PHY port // as appropriate // the procedure is complicated by the fact that // the iridium may be powered off the Afar (12V) relay, // in which case we need to turn this relay on if // *either* Afar or iridium want power #ifdef DEBUG 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 const SnConfigFrame::EPowerModeBit abit = (isCommWin) ? SnConfigFrame::kAfarComWin : SnConfigFrame::kAfarDatTak; const bool afarFromOn = IsCurrentlyPowered(abit, PIN_afar_power); // change ethernet PHY port power #ifdef DEBUG printf("afar pin=%d, afarFromOn=%d, afarToOn=%d\r\n", PIN_afar_power.read(), static_cast<int>(afarFromOn), static_cast<int>(isOn)); #endif if (isOn) { #ifdef DEBUG printf("PHY cowin powering up\r\n"); #endif PHY_PowerUp(); #ifdef USE_RTOS Thread::wait(1000); #else wait(1); #endif #ifdef DEBUG printf("PHY cowin powered up\r\n"); #endif } else { // change afar power // power down periph if going from on to off // change afar power if (afarFromOn) { PowerDownCommPeriph(SnConfigFrame::kAfar); } #ifdef DEBUG printf("PHY cowin powering down\r\n"); #endif PHY_PowerDown(); #ifdef USE_RTOS Thread::wait(1000); #else wait(1); #endif #ifdef DEBUG printf("PHY cowin powered down\r\n"); #endif } #ifdef DEBUG printf("PHY done\r\n"); #endif #ifdef USE_RTOS Thread::wait(100); #else wait_ms(100); #endif // change afar power const int value = gConf.GetPowPinSetting(abit, isOn); PIN_afar_power = value; #ifdef USE_RTOS Thread::wait(1500); #else wait(1.5); #endif #ifdef DEBUG printf("aft: pconp=%u (%08x), pcenet=%u (%08x)\r\n", LPC_SC->PCONP, LPC_SC->PCONP, LPC1768_PCONP_PCENET, LPC1768_PCONP_PCENET); printf("pcenet aft power: status=%d\r\n",Peripheral_GetStatus(LPC1768_PCONP_PCENET)); #endif } bool IsPowerAllowedFor(const bool isCommWin, const uint8_t devicesInUse, const SnConfigFrame::EDatPackBit b) { if (isCommWin && (gConf.IsCommPowerSimple()==false)) { return ( (devicesInUse & b)!=0 ); } return true; } void SetPower(const bool isCommWin, const uint8_t devicesInUse) { // devicesInUse could really just be a second set of "power mode" bits // where the bit being on means "I want to change power for this device" // but then.. how to handle the possibility that the bit word contains, // for example, both bits AfarDatTak and AfarComWin being on? // so instead, we keep the "isCommWin" boolean which forces the separation // and deviceInUse is only applied when isCommWin==true // // multiple devices can be specified by, e.g., kIrid | kAfar #ifdef DEBUG printf("set power. isCommWin=%s\r\n",(isCommWin)?"true":"false"); printf("WD reset = %d\r\n",(int)Watchdog::didWatchdogReset()); printf("power word (%hhu): ",gConf.GetPowerMode()); SnBitUtils::printBits(gConf.GetPowerMode(),true); printf("IsPoweredFor CardDatTak = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kCardDatTak)); printf("IsPoweredFor AmpsDatTak = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kAmpsDatTak)); printf("IsPoweredFor IridDatTak = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kIridDatTak)); printf("IsPoweredFor AfarDatTak = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kAfarDatTak)); printf("IsPoweredFor CardComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kCardComWin)); printf("IsPoweredFor AmpsComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kAmpsComWin)); printf("IsPoweredFor IridComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kIridComWin)); printf("IsPoweredFor AfarComWin = %d\r\n",(int)gConf.IsPoweredFor(SnConfigFrame::kAfarComWin)); printf("devicesInUse = %hhu\r\n", (uint8_t)devicesInUse); printf("IsCommPowerSimple = %s\r\n", (gConf.IsCommPowerSimple() ? "true" : "false")); #endif const SnConfigFrame::EPowerModeBit cardpb = (isCommWin) ? SnConfigFrame::kCardComWin : SnConfigFrame::kCardDatTak; const SnConfigFrame::EPowerModeBit ampspb = (isCommWin) ? SnConfigFrame::kAmpsComWin : SnConfigFrame::kAmpsDatTak; const SnConfigFrame::EPowerModeBit iridpb = (isCommWin) ? SnConfigFrame::kIridComWin : SnConfigFrame::kIridDatTak; const SnConfigFrame::EPowerModeBit afarpb = (isCommWin) ? SnConfigFrame::kAfarComWin : SnConfigFrame::kAfarDatTak; // // FIRST turn the things off that should be off. // this prevents short periods of high power usage // const bool cardToOn = gConf.IsPoweredFor(cardpb); const bool ampsToOn = gConf.IsPoweredFor(ampspb); // these are complicated because iridium might // be powered off of the afar line // also ignore the devices in use if we're not in a comm window const bool iridToOn = (kIridPwrFromAfar) ? (gConf.IsPoweredFor(afarpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kIrid)) : (gConf.IsPoweredFor(iridpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kIrid)); const bool afarToOn = (kIridPwrFromAfar) ? ( (gConf.IsPoweredFor(afarpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kAfar)) ||(gConf.IsPoweredFor(iridpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kIrid)) ) : (gConf.IsPoweredFor(afarpb) && IsPowerAllowedFor(isCommWin, devicesInUse, SnConfigFrame::kAfar)); if (cardToOn==false) { #ifdef DEBUG printf("power down cards\r\n"); #endif ChangeCardPower(isCommWin, cardToOn); } if (ampsToOn==false) { #ifdef DEBUG printf("power down amps\r\n"); printf("ampspb=%d, is powered for =%d\r\n", (int)ampspb, (int)(gConf.IsPoweredFor(ampspb))); printf("is powered amps dat tak = %d, amps com win = %d\r\n", (int)(gConf.IsPoweredFor(SnConfigFrame::kAmpsDatTak)), (int)(gConf.IsPoweredFor(SnConfigFrame::kAmpsComWin))); #endif ChangeAmpsPower(isCommWin, ampsToOn); } if (iridToOn==false) { #ifdef DEBUG printf("power down irid\r\n"); #endif ChangeIridPower(isCommWin, iridToOn); } if (afarToOn==false) { #ifdef DEBUG printf("power down afar\r\n"); #endif ChangeAfarPower(isCommWin, afarToOn); } // // THEN turn on things that want to go on // if (cardToOn) { #ifdef DEBUG printf("power ON cards\r\n"); #endif ChangeCardPower(isCommWin, cardToOn); } if (ampsToOn) { #ifdef DEBUG printf("power ON amps\r\n"); #endif ChangeAmpsPower(isCommWin, ampsToOn); } if (iridToOn) { #ifdef DEBUG printf("power ON iridium\r\n"); #endif ChangeIridPower(isCommWin, iridToOn); } if (afarToOn) { #ifdef DEBUG printf("power ON afar\r\n"); #endif ChangeAfarPower(isCommWin, afarToOn); } #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()); #endif } // // set configuration // void SetConfigAndMakeOutputFile() { #ifdef DEBUG printf("SetConfigAndMakeOutputFile\r\n"); #endif // restart watchdog #ifdef DEBUG printf("Restart watchdog with time [%u]\r\n", gConf.GetWatchdogPeriod()); #endif Watchdog::kick(gConf.GetWatchdogPeriod()); // block (thermal) triggers during configuration PIN_enableThermTrig = 0; #if CHIPBOARD==ATWD4CH PIN_ADC_CS = 1; PIN_DoNotRestartAllClocks = 1; #endif PIN_forceTrigger = 0; PIN_heartbeat = 0; #ifdef USE_RTOS Thread::wait(20); #else wait_ms(20); #endif 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 (with ATWD4CH) PIN_spi.frequency(1000000); PIN_MajLogHiBit=1; PIN_MajLogLoBit=1; PIN_enableThermTrig=0; #if CHIPBOARD==ATWD4CH uint16_t hi, lo; PIN_PLA_cs=1; #ifdef USE_RTOS Thread::wait(4000); #else wait(4); #endif 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(); } #ifdef USE_RTOS Thread::wait(3000); #else wait(3); #endif PIN_PLA_cs=0; #ifdef USE_RTOS Thread::wait(3000); #else wait(3); #endif // 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(); } #else // SST // set and/or & differential pins // set DACs via I2C uint16_t dv=0; uint8_t dn=0; uint8_t cmdAndDac[3]; for (uint8_t ch=0; ch<kNchans; ++ch) { for (uint8_t dc=0; dc<kNchanDacs; ++dc) { // for (uint16_t dc=kNchanDacs-1; dc>=0; --dc) { // first all the highs, then the lows // for (int16_t ch=kNchans-1; ch>=0; --ch) { // chans in reverse order bool dok = false; for (uint8_t tries = 0; (tries<kMaxDacSetTries) && (dok==false); ++tries) { #ifdef DEBUG printf("start i2c for dc=%hhu, ch=%hhu, try=%hhu, dok=%s\r\n", dc, ch, tries, (dok ? "true" : "false")); printf("address 0x%hhx (%hhd) ", kAllLTC2657, kAllLTC2657); SnBitUtils::printBits(kAllLTC2657, true); #endif // build data to send // blame the engineers for this bizzare mapping from // chan, threshold -> DAC number dn = (kTotDacs-1)-(dc*kNchans)-ch; if (dn>7) { // invalid code for LTC2657 dac chip error("chan/dac combination too big for 3 bits!"); } dn |= (kUpdateDacCmd<<4); // prefix with update DAC value command #ifdef DEBUG printf("dn=%hhu ", dn); SnBitUtils::printBits(dn, true); #endif dv = (gConf.GetDac(ch, dc)) << 4; // put 0's at the end (12 bits of num then 4 zero bits) #ifdef DEBUG printf("dv=%hu\r\n",dv); printf("ch=%hhu, dc=%hhu, dac=%hu\r\n",ch,dc,gConf.GetDac(ch,dc)); #endif // mbed i2c.write seems to send it "backwards" from a (low endian) bit // point of view.. i guess it's forwards from an intuitive pov? cmdAndDac[0] = dn; cmdAndDac[1] = (dv & 0xFF00u) >> 8; // 8 MSBs of 12 bit num first cmdAndDac[2] = (dv & 0x00FFu); // 4 LSBs of 12 bit num followed by 4 zeros #ifdef DEBUG printf("cmdAndDac[0]="); SnBitUtils::printBits(cmdAndDac[2],true); printf("cmdAndDac[1]="); SnBitUtils::printBits(cmdAndDac[1],true); printf("cmdAndDac[2]="); SnBitUtils::printBits(cmdAndDac[0],true); #endif // try to send it // TODO: if no ACK, is just re-trying the whole thing good enough? // TODO: assign correct slave address for the DAC chip (this is a global address) dok = PIN_i2c.write(kAllLTC2657, reinterpret_cast<char*>(cmdAndDac), 3*sizeof(uint8_t))==0; } // end try loop } } #endif // CHIPBOARD #ifdef DEBUG printf("dacs set\r\n"); #endif #ifdef USE_RTOS Thread::wait(20); #else wait_ms(20); #endif } else { #ifdef DEBUG printf("cards off. skipping PLA and DAC setting\r\n"); #endif } #if CHIPBOARD==SST4CH // set the SST triggering run mode PIN_dualOrSingleThresholds = gConf.IsDualThresholdMode(); PIN_differentialTrigSignal = gConf.IsDifferentialTrigMode(); #endif // Majority Logic Trigger selection (# of cards) SnBitUtils::SetChanNumBits(gConf.GetNumCardsMajLog() - 1u, PIN_MajLogHiBit, PIN_MajLogLoBit); // Enable thermal trigger? PIN_enableThermTrig = gConf.IsThermTrigEnabled(); #if CHIPBOARD==SST4CH InitTempProbe(); #endif 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 #ifdef USE_RTOS Thread::wait(200); #else wait_ms(200); #endif 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 #ifdef DEBUG printf("gFirstEvt=%s\r\n",gFirstEvt?"true":"false"); #endif if (AreCardsPowered(false)) { PIN_spi.format( 16, 1 ); // back to trigger mode PIN_spi.frequency( 10000000 ); // Max is 12.5 MHz if (gFirstEvt==false) { #if CHIPBOARD==ATWD4CH PIN_DoNotRestartAllClocks = 0; wait_us(1); PIN_DoNotRestartAllClocks = 1; #endif } 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()) #if CHIPBOARD==ATWD4CH while ( PIN_a_sf_clk == 1 ) { // wait for trigger #else while ( PIN_dataReady==0 ) { // wait for data in mb fpga #endif if (gOpenCommWin || gCheckPower || gCheckTemp) { #ifdef DEBUG printf("break com=%d, pow=%d, tmp=%d\r\n", gOpenCommWin,gCheckPower,gCheckTemp); #endif return; // break out to open comms or check power } } gReadingOut = true; // disallow new forced triggers // we can't be interrupted before data arrives at the MB FPGA //StopAllTickers(); //wait_us(5); #if CHIPBOARD==ATWD4CH // ATWD // // 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( uint16_t i = 0; i < kNsamps; ++i ) { while (PIN_a_sf_clk==1) {} while (PIN_a_sf_clk==0) {} PIN_ADC_CS = 0; PIN_spi.write( 0x00 ); PIN_ADC_CS = 1; } gAdcToMBtimer.stop(); #ifdef DEBUG printf("total time = %d us\r\n", gAdcToMBtimer.read_us()); #endif if ( kAdcToMBtimeCut < gAdcToMBtimer.read_us() ) { // gEvent.SetTrgBit(kAdcToMBflag); gAdcToMBflag = true; } gAdcToMBtimer.reset(); #else // For SST, data is already in the mb FPGA, so no need to do anything here #endif } else { // cards have no power. don't try reading out gReadingOut=false; // set gFirstEvt to false even if cards are powered off. // otherwise, if cards ARE powered off, it will always be // true and the "start trigger" clock will be written continuously gFirstEvt = false; } } bool IsPinPowered(const SnCommWin* cw) { bool havePower = false; switch (cw->GetCommType()) { case SnConfigFrame::kIrid: havePower = gConf.IsPoweredFor(SnConfigFrame::kIridComWin) && ( (kIridPwrFromAfar) ? 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; }; return havePower; } SnCommWin::ECommWinResult OpenCommWin(const bool forceReconfig, const bool isStartupWin) { // loop through each comm mode: // a) try to connect // b) if connected, listen for config // c) if config requests data, send it led2 = 1; gLastCommWin = time(0); SnCommWin::ECommWinResult res = SnCommWin::kUndefFail; // get the trigger rates float thmrate=0, evtrate=0; GetRates(thmrate, evtrate); #ifdef DEBUG printf("config=%s\r\n", gConf.GetLabel()); printf("thmrate=%g, evtrate=%g\r\n",thmrate,evtrate); printf("Free memory = %d\r\n", FreeMem()); #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 if (isStartupWin==false) { #if CHIPBOARD==ATWD4CH PIN_lockRegisters = 0; // unlock so we can talk to the SD card #else PIN_readingData = 0; // unlock so we can talk to the SD card #endif #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 // don't power up comms yet (only as needed for use) SetPower(true, 0); // time to recount files for the status update // for the startup win, don't access SD card in case we // rebooted due to a problem with the SD card SnStatusFrame::fgRecalcFiles = !isStartupWin; #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) bool doTwitter = false; #endif #ifdef DEBUG printf("start loop over comms\r\n"); #endif bool needToConnect=true; // still need to talk to the outside bool sendStat[kNcomms]; // if need to send status over this peripheral bool needClos[kNcomms]; // if need to call CloseConn on this peripheral for (uint8_t i=0; i<kNcomms; ++i) { sendStat[i]=true; needClos[i]=true; } bool* ss = sendStat; bool* nc = needClos; SnCommWin** cw = gComms; for (uint8_t i=0; needToConnect && ((time(0)-gLastCommWin)<gConf.GetCommWinDuration()); ++i, ++cw, ++ss, ++nc) { Watchdog::kick(); // don't reset! if (i==kNcomms) { i=0; cw = gComms; ss = sendStat; nc = needClos; } // skip if no comm object if ((*cw)==0) { continue; } const SnConfigFrame::EDatPackBit ctype = (*cw)->GetCommType(); // power up for this device if (gConf.IsCommPowerSimple()==false) { SetPower(true, ctype); } // 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 const bool havePower=IsPinPowered(*cw); if (havePower==false) { continue; } // always apply safety nets to connection and listen so // that we don't accidently shut down comms (i.e. with // connectTO or listnTO being 0) gConf.ApplyConnectListenSafetyNets(); const uint32_t conto = (gConf.GetCommWinDuration() < gConf.GetCommWinConnectTO(ctype)) ? gConf.GetCommWinDuration() : gConf.GetCommWinConnectTO(ctype); const uint32_t listo = (gConf.GetCommWinDuration() < gConf.GetCommWinListenTO(ctype)) ? gConf.GetCommWinDuration() : gConf.GetCommWinListenTO(ctype); // // try to connect to the outside if we haven't yet // // update power reading in case we want to send it in status GetAvePowerReading(); // update temperature in case we want to send it in status if (isStartupWin) { #if CHIPBOARD==SST4CH InitTempProbe(); #endif } UpdateTemperature(); // open window and (mabye) send status update #ifdef DEBUG printf("Free memory = %d\r\n", FreeMem()); printf("calling OpenWindow. ss=%d. ctype=%hhu (%s)\r\n", (int)(*ss),(uint8_t)ctype,SnConfigFrame::GetDataStreamName(ctype)); printf("conto=%u, listo=%u, dur=%u, connTO=%u, lisTO=%u\r\n", conto,listo,gConf.GetCommWinDuration(), gConf.GetCommWinConnectTO(ctype), gConf.GetCommWinListenTO(ctype)); printf("stopAt=%u, current=%d, lastComWin=%d, dt~%u\r\n", gConf.GetTimeoutTime(gLastCommWin,conto), time(0), gLastCommWin, gConf.GetTimeoutTime(gLastCommWin,conto)-time(0)); #endif // // open the connection and send the status update (if the // status has not yet been sent over this peripheral) // const SnCommWin::ECommWinResult conres = (*cw)->OpenWindow( *ss, gConf, gPower, gEvent, SnSDUtils::GetCurSeqNum(), thmrate, evtrate, gPowerOnTime, gTemperature, gGenBuf, gConf.GetTimeoutTime(gLastCommWin, conto)); #ifdef DEBUG printf("conres = %d\r\n",static_cast<int>(conres)); #endif if (conres>=SnCommWin::kConnected) { Watchdog::kick(); // don't reset! // connected. listen for config *ss = false; // don't send status next time *nc = true; // will need to close this connection // clear watchdog reset bit now that we've told someone Watchdog::clearResetFlag(); #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) if (ctype==SnConfigFrame::kAfar) { // if we connected by Afar doTwitter = true; } #endif #ifdef DEBUG printf("get conf gtt=%u\r\n",gConf.GetTimeoutTime(gLastCommWin, listo)); #endif // copy old config gConfCopy = gConf; // // ask for a new config // const SnCommWin::ECommWinResult cfgres = (*cw)->GetConfig( gConf, gConf.GetTimeoutTime(gLastCommWin, listo), gGenBuf, gBufSize); #ifdef DEBUG printf("cfgres = %d\r\n",static_cast<int>(cfgres)); #endif 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 const uint32_t winto = gConf.GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration()); //const uint32_t gtt = gConf.IsObeyingTimeout() ? winto : 0; // // send status data -- do this after getting the config! // (avoid a situation where sending all this data causes a timeout, // thereby preventing a new config from being accepted) // res = (*cw)->SendStatusData(gConf, gConfCopy, gStTrgStartClk, gStTrgStopClk, gStPower, gEvent, gStTemperature, gHrtbt, gStNewPower, gStNewEvent, gStNewHeartbeat, gStNewTemperature, gGenBuf, winto); #ifdef DEBUG printf("SendStatusData res=%d\r\n", static_cast<int32_t>(res)); #endif // // check if there are any requests before sending data // if (gConf.IsWaitingHndShkBeforeSendData()) { // send handshake request (*cw)->SendHndshkReq(gGenBuf, winto); // wait for response uint8_t hndshk(0); uint32_t hndshkLen(0); res = (*cw)->WaitHandshake(gConf, winto, gGenBuf, gBufSize, hndshk, &hndshkLen); #ifdef DEBUG printf("WaitHandshake res = %d\r\n",static_cast<int>(res)); #endif // handle response if (SnCommWin::kOkWithMsg==res) { res = (*cw)->HandleHandshake(SnSDUtils::GetCurFile(), SnSDUtils::GetCurFileName(), gConf, gEvent, gPower, gGenBuf, gBufSize, // gConf, gLastEvent, gPower, gGenBuf, gBufSize, winto, hndshk, hndshkLen); #ifdef DEBUG printf("HandleHandshake res = %d\r\n",static_cast<int>(res)); #endif } } // if handshake before data // // send data if need be (files, some events, etc) // if (gConf.GetCommSendData()!=0) { #ifdef DEBUG printf("sending data, winto=%u. lcw=%u, dur=%u, obey=%s\r\n", winto, gLastCommWin, gConf.GetCommWinDuration(), gConf.IsObeyingTimeout() ? "true" : "false"); #endif res = (*cw)->SendData(gConf, // gLastEvent, gPower, gGenBuf, gBufSize, gEvent, gPower, gGenBuf, gBufSize, winto); #ifdef DEBUG printf("SendData res = %d\r\n",static_cast<int>(res)); #endif } else { // don't send anything res = cfgres; } // if send data #ifdef DEBUG printf("Got config!\r\n"); #endif Watchdog::kick(); // don't reset! // need to close this connection *nc = true; // stop trying to connect to outside // don't break immediately, so that we can close conn and // maybe tweet (pff..) needToConnect = false; } // if config recvd ok with message // // stupid legacy twitter crap. // // after normal Afar connection closed, try to tweet #if defined(ENABLE_AFAR_TWITTER) && defined(ENABLE_AFAR_COMM) if (ctype==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, // gLastEvent, gPower, 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)); } } } // end tweet block #endif } else { // OpenWindow did not connect (*cw)->CloseConn(gConf.GetTimeoutTime(gLastCommWin, listo)); *nc = false; #ifdef DEBUG printf("no connect close conn. i=%d, nc=%s\r\n", (int32_t)i, (*nc) ? "true" : "false"); #endif } // if connected Watchdog::kick(); // don't reset! if (*nc) { // need to close this connection #ifdef DEBUG printf("close conn extra time. i=%d, nc=%s\r\n", (int32_t)i, (*nc) ? "true" : "false"); #endif const uint32_t extraDiscTime = gLastCommWin + gConf.GetCommWinConnectTO((*cw)->GetCommType()); (*cw)->CloseConn( gConf.GetTimeoutTime(extraDiscTime, gConf.GetCommWinDuration())); *nc = false; } Watchdog::kick(); // don't reset! } // end loop over comms // check Iridium time, send Iridium signal strength, and close the connection(s) cw = gComms; nc = needClos; for (uint8_t i=0; i<kNcomms; ++i, ++cw, ++nc) { if ((*cw)==0) { continue; } const SnConfigFrame::EDatPackBit ctype = (*cw)->GetCommType(); // check Iridium time if (ctype==SnConfigFrame::kIrid) { // power up for this device if (gConf.IsCommPowerSimple()==false) { SetPower(true, ctype); } const bool havePower=IsPinPowered(*cw); if (havePower==false) { continue; } #ifdef DEBUG printf("try to set iridium time\r\n"); #endif // set the clock before closing connection const uint32_t totime = gConf.GetTimeoutTime(gLastCommWin, gConf.GetCommWinDuration()); #ifdef DEBUG printf("totime=%u, ctime=%u\r\n",totime,time(0)); #endif const bool con = (*cw)->Connect(totime); *nc = true; if (con) { uint32_t prvTime(0), setTime(0); const bool gottime = (*cw)->TrySetSysTimeUnix( totime, prvTime, setTime); if (gottime) { gClkSet.SetClocks( prvTime, setTime, time(0), gSinceClkSet.read_us() ); gSinceClkSet.reset(); gSinceClkSet.start(); #ifdef DEBUG // printf("sig str: totime=%u, ctime=%u\r\n",totime,time(0)); printf("sig str: totime=%u, ctime=%u\r\n",totime,gClkSet.GetCurTime()); #endif // got time; now send signal strength (*cw)->SendSignalStrength( gGenBuf, gSigStr, totime ); } // if got the iridium system time } // if connected (again, possibly) } // if iridium if (*nc) { // power up for this device if (gConf.IsCommPowerSimple()==false) { SetPower(true, ctype); } const bool havePower=IsPinPowered(*cw); if (havePower==false) { continue; } #ifdef DEBUG printf("last loop close conn. i=%d, nc=%s\r\n", (int32_t)i, (*nc) ? "true" : "false"); #endif const uint32_t extraDiscTime = gLastCommWin + gConf.GetCommWinConnectTO((*cw)->GetCommType()); (*cw)->CloseConn(gConf.GetTimeoutTime(extraDiscTime, gConf.GetCommWinDuration())); *nc = false; } } // end loop: check time, close conns /* // close connections cw = gComms; for (uint8_t i=0; i<kNcomms; ++i, ++cw) { if ((*cw)==0) { continue; } else { } } */ } // 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); } } */ // check if we missed too many consecutive connections if (res<=SnCommWin::kAllFails) { ++gConsecCommFails; #ifdef DEBUG printf("res=%d, gConsecCommFails=%hu, kMaxConsecCommFails=%hu\r\n", static_cast<int>(res), gConsecCommFails,kMaxConsecCommFails); #endif if (gConsecCommFails>kMaxConsecCommFails) { #ifdef DEBUG printf("rebooting\r\n"); #endif // goodbye cruel world, it's over. walk on by... mbed_reset(); } } else { gConsecCommFails=0; } // (probably) power down comms and power up cards,amps SetPower(false, SnConfigFrame::kIrid | SnConfigFrame::kAfar); // reset config with system powered (for DAC/PLA setting) #ifdef DEBUG printf("calling SetConfigAndMakeOutputFile\r\n"); #endif if (gConf.IsRunSeqListOneCommWinOnly()) { SnSDUtils::ClearRunSeqList(gConf.IsSendingFilesRunSeqList()); } SetConfigAndMakeOutputFile(); // check power in case we should be in low power mode // but don't save this reading to the file // (there's already one near the beginning) CheckPower(false, false); #ifdef DEBUG printf("closing comm win at %d\r\n",(int32_t)time(0)); printf("Free memory = %d\r\n", FreeMem()); #endif led2 = 0; gCommWinOpen = false; return res; }