diff --git a/db/correlation_unit.db b/db/correlation_unit.db index c9457d7..771ae09 100644 --- a/db/correlation_unit.db +++ b/db/correlation_unit.db @@ -13,9 +13,17 @@ record(bo, "$(INSTR)$(NAME):Enable") field(DESC, "Electronics Status") field(DTYP, "asynInt32") field(OUT, "@asyn($(PORT),0,$(TIMEOUT=1)) EN_EL") - field(VAL, 1) field(ZNAM, "OFF") field(ONAM, "ON") field(PINI, 1) +} + +record(bi, "$(INSTR)$(NAME):Enable_RBV") +{ + field(DESC, "Electronics Status") + field(DTYP, "asynInt32") + field(INP, "@asyn($(PORT),0,$(TIMEOUT=1)) EN_EL_RBV") + field(ZNAM, "OFF") + field(ONAM, "ON") field(SCAN, ".5 second") } diff --git a/src/asynStreamGeneratorDriver.cpp b/src/asynStreamGeneratorDriver.cpp index 20461df..4ecaaba 100644 --- a/src/asynStreamGeneratorDriver.cpp +++ b/src/asynStreamGeneratorDriver.cpp @@ -162,7 +162,9 @@ asynStreamGeneratorDriver::asynStreamGeneratorDriver( asynStatus status = asynSuccess; status = createInt32Param(status, P_EnableElectronicsString, - &P_EnableElectronics); + &P_EnableElectronics, 1); + status = createInt32Param(status, P_EnableElectronicsRBVString, + &P_EnableElectronicsRBV); status = createInt32Param(status, P_StatusString, &P_Status, STATUS_IDLE); status = createInt32Param(status, P_ResetString, &P_Reset); status = createInt32Param(status, P_StopString, &P_Stop); @@ -395,10 +397,10 @@ asynStatus asynStreamGeneratorDriver::writeInt32(asynUser *pasynUser, // TODO should check everything... if (function == P_CountPreset) { if (!currentStatus) { - // slightly longer than the status update frequency - // i.e. "$(INSTR)$(NAME):RAW-STATUS" SCAN seconds - // to ensure that the counts have all had a chance - // to update their values before starting a count + // slightly longer than the status update frequency + // i.e. "$(INSTR)$(NAME):RAW-STATUS" SCAN seconds + // to ensure that the counts have all had a chance + // to update their values before starting a count epicsThreadSleep(0.12); // seconds setIntegerParam(function, value); setIntegerParam(P_Status, STATUS_COUNTING); @@ -407,10 +409,10 @@ asynStatus asynStreamGeneratorDriver::writeInt32(asynUser *pasynUser, } } else if (function == P_TimePreset) { if (!currentStatus) { - // slightly longer than the status update frequency - // i.e. "$(INSTR)$(NAME):RAW-STATUS" SCAN seconds - // to ensure that the counts have all had a chance - // to update their values before starting a count + // slightly longer than the status update frequency + // i.e. "$(INSTR)$(NAME):RAW-STATUS" SCAN seconds + // to ensure that the counts have all had a chance + // to update their values before starting a count epicsThreadSleep(0.12); // seconds setIntegerParam(function, value); setIntegerParam(P_Status, STATUS_COUNTING); @@ -456,7 +458,7 @@ asynStatus asynStreamGeneratorDriver::writeInt32(asynUser *pasynUser, } } else { setIntegerParam(function, value); - //status = (asynStatus)callParamCallbacks(); + // status = (asynStatus)callParamCallbacks(); } if (status) @@ -492,16 +494,32 @@ void asynStreamGeneratorDriver::receiveUDP() { if (received) { const uint16_t bufferLength = ((uint16_t *)buffer)[0]; - const std::size_t headerLength = 42; + const bool isCmdBuffer = ((uint16_t *)buffer)[1] && 0x8000; + const std::size_t minDataBufferHeaderLength = 42; + const std::size_t minCmdBufferHeaderLength = 20; - if (received >= headerLength && received == bufferLength * 2) { + if (received >= minDataBufferHeaderLength && + received == bufferLength * 2 && !isCmdBuffer) { epicsRingBytesPut(this->udpQueue, (char *)buffer, bufferSize); + } else if (received >= minCmdBufferHeaderLength && isCmdBuffer) { + + const CommandId cmd = + static_cast(((uint16_t *)buffer)[4]); + + if (cmd == CommandId::start) { + setIntegerParam(this->P_EnableElectronicsRBV, 1); + } else if (cmd == CommandId::stop) { + setIntegerParam(this->P_EnableElectronicsRBV, 0); + } + } else { asynPrint(pasynUserSelf, ASYN_TRACE_ERROR, - "%s:%s: invalid UDP packet\n", driverName, - functionName); + "%s:%s: invalid UDP packet of length %" PRIu64 + " (cmd_id %d)\n", + driverName, functionName, received, + ((uint16_t *)buffer)[4]); } } } @@ -704,12 +722,12 @@ void asynStreamGeneratorDriver::processEvents() { // wait for mininmum packet frequency or enough packets to ensure we // could potentially have at least 1 packet per mcpdid - // IMPORTANT: if you start counts faster than this poll period (so - // either the time or number of events incoming below), you will - // find that it doesn't have time to switch back to idle within - // this loop and so will just keep counting. If you need counts - // that are started more often than the below currently 250ms - // then that value will need to be adjusted. + // IMPORTANT: if you start counts faster than this poll period (so + // either the time or number of events incoming below), you will + // find that it doesn't have time to switch back to idle within + // this loop and so will just keep counting. If you need counts + // that are started more often than the below currently 250ms + // then that value will need to be adjusted. while (queuedEvents < bufferedEvents && epicsTimeDiffInNS(¤tTime, &lastProcess) < 250'000'000ll) { epicsThreadSleep(0.0001); // seconds @@ -758,7 +776,6 @@ void asynStreamGeneratorDriver::processEvents() { for (std::size_t i = 0; i < this->num_channels; ++i) { counts[i] = 0; } - } if (currStatus == STATUS_COUNTING) { diff --git a/src/asynStreamGeneratorDriver.h b/src/asynStreamGeneratorDriver.h index bd7be9d..7bf3df5 100644 --- a/src/asynStreamGeneratorDriver.h +++ b/src/asynStreamGeneratorDriver.h @@ -19,16 +19,16 @@ enum class CommandId : std::uint16_t { cont = 3 }; +// TODO these headers are actually the same, but with different bodies. struct __attribute__((__packed__)) CommandHeader { uint16_t BufferLength; uint16_t BufferType; uint16_t HeaderLength; uint16_t BufferNumber; uint16_t Command; - uint16_t McpdIdStatus; - uint16_t TimeStampLo; - uint16_t TimeStampMid; - uint16_t TimeStampHigh; + uint16_t Status : 8; + uint16_t McpdID : 8; + uint16_t TimeStamp[3]; uint16_t Checksum; uint16_t Finalizer; @@ -37,12 +37,13 @@ struct __attribute__((__packed__)) CommandHeader { BufferNumber(0), Command( static_cast::type>(commandId)), - McpdIdStatus(0), TimeStampLo(0), TimeStampMid(0), TimeStampHigh(0), - Checksum(0), Finalizer(0xffff) { + Status(0), McpdID(0), TimeStamp{0, 0, 0}, Checksum(0), + Finalizer(0xffff) { - Checksum = BufferLength ^ BufferType ^ HeaderLength ^ BufferNumber ^ - Command ^ McpdIdStatus ^ TimeStampLo ^ TimeStampMid ^ - TimeStampHigh; + uint16_t checksum = 0x0000; + for (std::size_t i = 0; i < BufferLength; ++i) + checksum ^= ((uint16_t *)this)[i]; + Checksum = checksum; } }; @@ -121,6 +122,7 @@ struct __attribute__((__packed__)) NormalisedEvent { */ constexpr static char P_EnableElectronicsString[]{"EN_EL"}; +constexpr static char P_EnableElectronicsRBVString[]{"EN_EL_RBV"}; constexpr static char P_StatusString[]{"STATUS"}; constexpr static char P_ResetString[]{"RESET"}; @@ -168,6 +170,7 @@ class asynStreamGeneratorDriver : public asynPortDriver { protected: // Parameter Identifying IDs int P_EnableElectronics; + int P_EnableElectronicsRBV; int P_Status; int P_Reset; int P_Stop;