diff --git a/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/.cproject b/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/.cproject index fb30581d6..fca10f49c 100644 --- a/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/.cproject +++ b/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/.cproject @@ -18,8 +18,8 @@ - - @@ -277,4 +277,5 @@ + diff --git a/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/FswPacket.hpp b/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/FswPacket.hpp index 4df0a2e8f..269f8f198 100644 --- a/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/FswPacket.hpp +++ b/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/FswPacket.hpp @@ -84,12 +84,13 @@ struct FswFileHeader { uint8_t totalBlocks; uint8_t blockNumber; // This is 1-indexed, 0-index is optional and contains file-specific metadata FileLength_t length; // This is the size of the following data **not including this header** -}; +} __attribute__((packed)); struct FswFileMetadata { // Block 0 of files uint16_t callbackId; uint32_t timestamp; -}; +} __attribute__((packed)); + struct FswFile { struct FswFileHeader header; diff --git a/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/Version.h b/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/Version.h index 2af266191..c113dfad7 100644 --- a/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/Version.h +++ b/Apps/FlightSoftware/PrimaryFlightController/FlightMCU/Include/Version.h @@ -10,7 +10,7 @@ *****************************************************************************/ static const unsigned VERSION_MAJOR = 8; // Version: ++ when drafting a new Release Candidate (for a new upload opportunity) -static const unsigned VERSION_MINOR = 0; // Subversion: ++ when a new major feature has been added / made to work +static const unsigned VERSION_MINOR = 1; // Subversion: ++ when a new major feature has been added / made to work static const unsigned VERSION_REVISION = 0; // Patch: ++ when you make a change and want to reflect that. #endif // _VERSION_H_ diff --git a/Apps/FlightSoftware/Watchdog/.cproject b/Apps/FlightSoftware/Watchdog/.cproject index 7b1df5eff..cc0091e6e 100644 --- a/Apps/FlightSoftware/Watchdog/.cproject +++ b/Apps/FlightSoftware/Watchdog/.cproject @@ -281,8 +281,8 @@ + + + + + + + + + + + + + + + + + + + + + + diff --git a/Apps/FlightSoftware/Watchdog/.gitignore b/Apps/FlightSoftware/Watchdog/.gitignore index 637ca8fab..ab997e9da 100644 --- a/Apps/FlightSoftware/Watchdog/.gitignore +++ b/Apps/FlightSoftware/Watchdog/.gitignore @@ -8,3 +8,4 @@ doc/ /Debug__opt_for_speed__4/ /Debug_with_flag/ /Debug_Radio_Flashing/ +/Debug_Radio_Herc_Flashing/ diff --git a/Apps/FlightSoftware/Watchdog/include/flags.h b/Apps/FlightSoftware/Watchdog/include/flags.h index 6669b76f0..bac7377fe 100644 --- a/Apps/FlightSoftware/Watchdog/include/flags.h +++ b/Apps/FlightSoftware/Watchdog/include/flags.h @@ -81,13 +81,13 @@ extern "C" #define DEFAULT_PWM_LIMIT 9999 // deprecated #define DEFAULT_HEATER_SETPOINT 3325 // deprecated #define DEFAULT_HEATER_WINDOW 60 // deprecated -// 3670 is the -5 deg C thermistor voltage ADC reading - heater transitions to ON when T ADC < this value: -#define DEFAULT_HEATER_ON_VAL 2781 -// 3670 is the 0 deg C thermistor voltage ADC reading - heater transitions to OFF when T ADC > this value: -#define DEFAULT_HEATER_OFF_VAL 2291 +// 2540 is the 0 deg C thermistor voltage ADC reading - heater transitions to ON when T ADC < this value: +#define DEFAULT_HEATER_ON_VAL 2540 +// 2042 is the 10 deg C thermistor voltage ADC reading - heater transitions to OFF when T ADC > this value: +#define DEFAULT_HEATER_OFF_VAL 2040 #define DEFAULT_HEATING_CONTROL_ENABLED TRUE #define DEFAULT_HEATER_DUTY_CYCLE_PERIOD 10000 -#define DEFAULT_HEATER_DUTY_CYCLE 8500 +#define DEFAULT_HEATER_DUTY_CYCLE 9998 #define GENERIC_BIT_INDEX_TO_TYPE_MASK(type, index) (((type)1) << ((type)(index))) #define GENERIC_BIT_INDEX_TO_UINT8_MASK(index) GENERIC_BIT_INDEX_TO_TYPE_MASK(uint8_t, index) diff --git a/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateEnteringService.cpp b/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateEnteringService.cpp index d772c7e10..aac50955a 100644 --- a/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateEnteringService.cpp +++ b/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateEnteringService.cpp @@ -2,6 +2,7 @@ #include +#include "comms/debug_comms.h" #include "drivers/bsp.h" namespace iris @@ -43,6 +44,9 @@ namespace iris { *(theContext.m_persistentInMission) = false; + DPRINTF("Defaulting MONITOR_HERCULES to OFF in SERVICE."); + theContext.m_watchdogOpts &= ~WDOPT_MONITOR_HERCULES; // don't monitor Hercules for aliveness by default in service + // Enable the falling edge interrupt for WD_INT (should be done after unlocking LOCKLPM5 per slau367p section 12.3.2) enableWdIntFallingEdgeInterrupt(); diff --git a/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateInit.cpp b/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateInit.cpp index e19bb8db3..4b6e935b8 100644 --- a/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateInit.cpp +++ b/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateInit.cpp @@ -95,6 +95,13 @@ namespace iris DebugComms__tryPrintfToLanderNonblocking("[WARNING] WD SW is in Radio-Programming Mode. This should be changed before flight.\n"); #endif +#ifdef HERC_PROGRAMMING_MODE + // [CWC-03/13/2023] Warn that this is the WRONG version of the SW for Flight and should only be used for hercules programming. + // Essentially this is a special version of the SW that disable hercules monitioring by default in mission (instead of enables) so + // hercules can be programmed. In flight, though, we want Hercules monitoring to be on by default. + DebugComms__tryPrintfToLanderNonblocking("[WARNING] WD SW is in Hercules-Programming Mode. This should be changed before flight.\n"); +#endif + /* set up watchdog */ watchdog_init(&(theContext.m_watchdogFlags), Time__getPointerToCentisecondCount(), diff --git a/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateMission.cpp b/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateMission.cpp index 47a424ccd..00eecd1fe 100644 --- a/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateMission.cpp +++ b/Apps/FlightSoftware/Watchdog/src/stateMachine/RoverStateMission.cpp @@ -212,6 +212,17 @@ namespace iris disableHeater(); } +#ifdef HERC_PROGRAMMING_MODE + // [CWC-03/13/2023] Warn that this is the WRONG version of the SW for Flight and should only be used for hercules programming. + // Essentially this is a special version of the SW that disable hercules monitioring by default in mission (instead of enables) so + // hercules can be programmed. In flight, though, we want Hercules monitoring to be on by default. + DPRINTF("Defaulting MONITOR_HERCULES to OFF in MISSION for programming."); + theContext.m_watchdogOpts &= ~WDOPT_MONITOR_HERCULES; +#else + DPRINTF("Defaulting MONITOR_HERCULES to ON in MISSION."); + theContext.m_watchdogOpts |= WDOPT_MONITOR_HERCULES; // default to monitoring Hercules for aliveness +#endif + return getState(); } diff --git a/Apps/FlightSoftware/Watchdog/src/watchdog.c b/Apps/FlightSoftware/Watchdog/src/watchdog.c index fb4a0106a..3b333a0a3 100644 --- a/Apps/FlightSoftware/Watchdog/src/watchdog.c +++ b/Apps/FlightSoftware/Watchdog/src/watchdog.c @@ -169,6 +169,14 @@ int watchdog_monitor(HerculesComms__State *hState, DEBUG_LOG_NULL_CHECK_RETURN(writeIOExpander, "Parameter is NULL", -1); DEBUG_LOG_NULL_CHECK_RETURN(details, "Parameter is NULL", -1); + // Quick and dirty parameters for tuning Hercules Monitoring: + // How many consequtive kicks has hercules missed since being reset: + static uint8_t herc_conseq_missed_kicks_since_reset = 0; + // How many consequtive missed kicks until a reset (testing has shown it has to be at least 2): + // -- setting this too low won't give Hercules time to reboot after a crash and reset before + // being reset again... + static const uint8_t HERC_CONSEQ_MISSED_KICK_THRESHOLD = 3; + /* temporarily disable interrupts */ __disable_interrupt(); @@ -206,6 +214,7 @@ int watchdog_monitor(HerculesComms__State *hState, *watchdogFlags ^= WDFLAG_UNRESET_HERCULES; *writeIOExpander = TRUE; SET_RABI_IN_UINT(details->m_resetActionBits, RABI__HERCULES_UNRESET); + DPRINTF("Unreset Hercules."); } /* unreset motor 1 */ @@ -276,29 +285,42 @@ int watchdog_monitor(HerculesComms__State *hState, if (*watchdogFlags & WDFLAG_HERCULES_KICK) { *watchdogFlags ^= WDFLAG_HERCULES_KICK; + herc_conseq_missed_kicks_since_reset = 0; + // Let Ground know Hercules is still alive + // (if Hercules was rebooted while our comms were only over Wifi, + // we wouldn't know when it would be good to send SWITCH TO WIFI MODE). + DPRINTF("Hercules Alive."); } else { if (*watchdogOpts & WDOPT_MONITOR_HERCULES) { - // reset the hercules - setHerculesReset(); - - SET_RABI_IN_UINT(details->m_resetActionBits, RABI__HERCULES_WATCHDOG_RESET); - - // Set the flag so that the next time this function triggers, the Hercules will be un-reset - *watchdogFlags |= WDFLAG_UNRESET_HERCULES; - - // if the issue was due to a comms breakdown, reset the comms state - if (NULL != hState) - { - HerculesComms__Status hcStatus = HerculesComms__resetState(hState); - - //!< @todo Replace with returning watchdog error code once that is implemented. - DEBUG_ASSERT_EQUAL(HERCULES_COMMS__STATUS__SUCCESS, hcStatus); + // Only inc. counter if Herc is being monitored. + herc_conseq_missed_kicks_since_reset += 1; + DPRINTF("Hercules Unresponsive."); + // Only reset if counter too big: + if(herc_conseq_missed_kicks_since_reset >= HERC_CONSEQ_MISSED_KICK_THRESHOLD){ + // reset the hercules + DPRINTF("No Hercules Kick. Resetting Hercules . . ."); + herc_conseq_missed_kicks_since_reset = 0; + setHerculesReset(); + + // queue up hercules unreset + *watchdogFlags |= WDFLAG_UNRESET_HERCULES; + SET_RABI_IN_UINT(details->m_resetActionBits, RABI__HERCULES_WATCHDOG_RESET); + + // if the issue was due to a comms breakdown, reset the comms state + if (NULL != hState) + { + DPRINTF("\t Resetting Hercules Comms . . ."); + HerculesComms__Status hcStatus = HerculesComms__resetState(hState); + + //!< @todo Replace with returning watchdog error code once that is implemented. + DEBUG_ASSERT_EQUAL(HERCULES_COMMS__STATUS__SUCCESS, hcStatus); + } + + *writeIOExpander = TRUE; } - - *writeIOExpander = TRUE; } else { diff --git a/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.cpp b/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.cpp index 64cec923a..5aabec4fc 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.cpp +++ b/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.cpp @@ -71,7 +71,7 @@ namespace CubeRover { { m_numComponentImgsReq++; tlmWrite_Cam_ComponentImagesRequested(m_numComponentImgsReq); - triggerImageCapture(CameraNum, CallbackId); + takeImage(CameraNum, CallbackId); } // ---------------------------------------------------------------------- @@ -98,7 +98,7 @@ namespace CubeRover { { m_numGroundImgsReq++; tlmWrite_Cam_CommandImagesRequested(m_numGroundImgsReq); - triggerImageCapture(camera_num, callback_id); + takeImage(camera_num, callback_id); this->cmdResponse_out(opCode,cmdSeq,Fw::COMMAND_OK); } @@ -199,66 +199,149 @@ namespace CubeRover { this->cmdResponse_out(opCode,cmdSeq,Fw::COMMAND_OK); } - void CameraComponentImpl::downsampleLine() { - for(uint32_t x = 0; x < IMAGE_WIDTH/DOWNSAMPLING; x++) { - m_imageLineBuffer[x] = m_imageLineBuffer[x*DOWNSAMPLING]; - } - } - - void CameraComponentImpl::selectCamera(int cameraSelect) { - // ASSERT camera == 0 or 1 - gioSetBit(linPORT, 1, cameraSelect & 0x01); - - // add small delays to make sure camera is selection is done - for(int delay=0; delay<500; delay++) asm(" NOP"); - } - - // TODO: Implement dual queue image capture to allow for two threads to downlink an - // image at once (ie navigation and science photo) - void CameraComponentImpl::triggerImageCapture(uint8_t camera, uint16_t callbackId) { - uint16_t spiTxCmd = 0xFF; - spiDAT1_t fpgaDataConfig; - - S25fl512l::MemAlloc alloc; - alloc.startAddress = 0; // Uhhh. Should use S25fl512l alloc method - alloc.reservedSize = 0; - - fpgaDataConfig.CS_HOLD = false; - fpgaDataConfig.DFSEL = SPI_FMT_0; - fpgaDataConfig.WDEL = false; - fpgaDataConfig.CSNR = 0; - - selectCamera(static_cast(camera)); - - gioSetBit(spiPORT1, 0, 0); // set CS LOW - spiTransmitData(spiREG1, &fpgaDataConfig, 1, &spiTxCmd); // send data - gioSetBit(spiPORT1, 0, 1); // set CS HIGH - - tlmWrite_Cam_LatestCallbackId(callbackId); - while(gioGetBit(gioPORTB, 1)); // Wait until image capture complete FIXME: This could loop forever :( - uint32_t createTime = static_cast(getTime().get_time_ms()); - - // TODO: Operator should be able to specify DOWNSAMPLING (but for testing smaller images are faster - for(int i = 0; i < IMAGE_HEIGHT; i+=DOWNSAMPLING) { -#ifdef __USE_DUMMY_IMAGE__ - getLineDummyImage(i, m_imageLineBuffer); + // ---------------------------------------------------------------------- + // User Methods + // ---------------------------------------------------------------------- + + // TAKE IMAGE + void CameraComponentImpl::takeImage(uint8_t camera, uint16_t callbackId) + { + // Set the camera and callback IDs + m_cameraSelect = camera; + m_lastCallbackId = callbackId; + tlmWrite_Cam_LatestCallbackId(callbackId); + +#ifdef DUMMY_IMG_GRID + // Create and send Dummy Image + generateDummyImage(); #else - m_fpgaFlash.readDataFromFlash(&alloc, 0, m_imageLineBuffer, sizeof(m_imageLineBuffer)); - alloc.startAddress = 6 * PAGE_SIZE * i; // jump to next available block + // Take Real Image! + + // set bit to control camera + gioSetBit(linPORT, 1, m_cameraSelect & 0x01); + + eraseFpgaFlash(); + + // add small delays to make sure camera is selection is done + for(int delay=0; delay<500; delay++) asm(" NOP"); + + uint32_t createTime = static_cast(getTime().get_time_ms()); + + // capture image + triggerImageCapture(); + while(gioGetBit(gioPORTB, 1)); + + // send image from flash + sendImgFromFlash(createTime); #endif - downsampleLine(); - downlinkImage(m_imageLineBuffer, sizeof(m_imageLineBuffer), callbackId, createTime); - } - m_imagesSent++; - tlmWrite_Cam_ImagesSent(m_imagesSent); - } - - void CameraComponentImpl::downlinkImage(uint8_t *image, int size, uint16_t callbackId, uint32_t createTime) { - Fw::Buffer fwBuffer(0, 0, reinterpret_cast(image), size); - downlinkImage_out(0, callbackId, createTime, fwBuffer); - m_bytesSent += static_cast(size); - tlmWrite_Cam_BytesSent(m_bytesSent); + } + + + // CREATE AND SEND DUMMY IMAGE + void CameraComponentImpl::generateDummyImage(void) + { + int grid_x_spacing = DUMMY_IMAGE_WIDTH / DUMMY_IMG_GRID_n; + int grid_y_spacing = DUMMY_IMAGE_HEIGHT / DUMMY_IMG_GRID_n; + +#ifdef VIA_FLASH + // Prep Flash before writing each line + S25fl512l::MemAlloc alloc; + alloc.startAddress = 0; + alloc.reservedSize = sizeof(m_imageLineBuffer); + + eraseFpgaFlash(); +#endif + + uint32_t createTime = static_cast(getTime().get_time_ms()); + + for (int y = 0; y < DUMMY_IMAGE_HEIGHT; y++) { + for (int x = 0; x < DUMMY_IMAGE_WIDTH; x++) { + // if camera == 0 then all black, else black and white grid, in theory... + m_imageLineBuffer[x] = 255 * (((x / grid_x_spacing) + (y / grid_y_spacing)) % 2); + // Make it a gradient in both x and y for debugging: + if(m_imageLineBuffer[x] == 0x00){ + m_imageLineBuffer[x] += 255 * x / DUMMY_IMAGE_WIDTH / 3; + m_imageLineBuffer[x] += 255 * y / DUMMY_IMAGE_HEIGHT / 3; + } else { + m_imageLineBuffer[x] -= 255 * x / DUMMY_IMAGE_WIDTH / 3; + m_imageLineBuffer[x] -= 255 * y / DUMMY_IMAGE_HEIGHT / 3; + } + } +#ifdef VIA_FLASH + // write each line to flash + m_fpgaFlash.writeDataToFlash(&alloc, 0, m_imageLineBuffer, sizeof(m_imageLineBuffer)); + alloc.startAddress += PAGE_SIZE * 6; + } + // then send from flash + sendImgFromFlash(createTime); +#else + // send each line as it is created + downlinkImage(m_imageLineBuffer, sizeof(m_imageLineBuffer), m_lastCallbackId, createTime); + } +#endif + + // Finished sending Dummy Image + m_imagesSent++; + tlmWrite_Cam_ImagesSent(m_imagesSent); + } + + +// TRIGGER IMAGE CAPTURE ON CAMERA +void CameraComponentImpl::triggerImageCapture() +{ + uint16_t spiTxCmd = 0xFF; + spiDAT1_t g_fpgaDataConfig; + + g_fpgaDataConfig.CS_HOLD = false; + g_fpgaDataConfig.DFSEL = SPI_FMT_0; + g_fpgaDataConfig.WDEL = false; + g_fpgaDataConfig.CSNR = 0; + + gioSetBit(spiPORT1, 0, 0); // set CS LOW + + // send data + spiTransmitData(spiREG1, &g_fpgaDataConfig, 1, &spiTxCmd); + + gioSetBit(spiPORT1, 0, 1); // set CS HIGH +} + + + // ERASE FLASH + void CameraComponentImpl::eraseFpgaFlash(void){ + for(int i=0; i< 40; i++){ + m_fpgaFlash.sectorErase(i); } - + } + + + // SEND IMAGE FROM FLASH + void CameraComponentImpl::sendImgFromFlash(uint32_t createTime) + { + S25fl512l::MemAlloc alloc; + alloc.startAddress = 0; + alloc.reservedSize = 0; + + for(int i=0;i(image), size); + downlinkImage_out(0, callbackId, createTime, fwBuffer); + m_bytesSent += static_cast(size); + tlmWrite_Cam_BytesSent(m_bytesSent); + } + + } // end namespace CubeRover diff --git a/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.hpp b/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.hpp index 47ba3c951..387bea163 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.hpp +++ b/Apps/FlightSoftware/fprime/CubeRover/Camera/Camera.hpp @@ -1,6 +1,6 @@ // ====================================================================== // \title CameraComponentImpl.hpp -// \author justin +// \author Raewyn // \brief hpp file for Camera component implementation class // // \copyright @@ -17,12 +17,23 @@ #include "S25fl512l.hpp" +// --- SYSTEM IMAGE PARAMS --- #define IMAGE_WIDTH 2592 #define IMAGE_HEIGHT 1944 -#define DOWNSAMPLING 2 -#define DOWNSAMPLED_IMG_WIDTH (IMAGE_WIDTH / DOWNSAMPLING) -#define DOWNSAMPLE_IMG_HEIGHT (IMAGE_HEIGHT / DOWNSAMPLING) +// --- DUMMY IMAGE PARAMS --- + +//#define DUMMY_IMG_GRID // Dummy image is grid of NxN squares +#define DUMMY_IMG_GRID_n 5 // Dummy image is grid of NxN squares +#define VIA_FLASH // Read & Write dummy image w/ FPGA Flash + +#define DUMMY_IMAGE_WIDTH IMAGE_WIDTH +#define DUMMY_IMAGE_HEIGHT IMAGE_HEIGHT + +// RAD TODO - isn't downsampling a user-defined parameter? +//#define DOWNSAMPLING 1 +//#define DOWNSAMPLED_IMG_WIDTH (IMAGE_WIDTH / DOWNSAMPLING) +//#define DOWNSAMPLE_IMG_HEIGHT (IMAGE_HEIGHT / DOWNSAMPLING) namespace CubeRover { @@ -181,20 +192,25 @@ namespace CubeRover { ); - // User methods - - void downsampleLine(); - void selectCamera(int camera); - void triggerImageCapture(uint8_t camera, uint16_t callbackId); - void downlinkImage(uint8_t *image, int size, uint16_t callbackId, uint32_t createTime); - - S25fl512l m_fpgaFlash; - uint8_t m_imageLineBuffer[IMAGE_WIDTH]; - U32 m_numComponentImgsReq; - U32 m_numGroundImgsReq; - U32 m_imagesSent; - U32 m_bytesSent; + // ---------------------------------------------------------------------- + // User Methods + // ---------------------------------------------------------------------- + void takeImage(uint8_t camera, uint16_t callbackId); + void generateDummyImage(void); + void triggerImageCapture(void); + void eraseFpgaFlash(void); + void sendImgFromFlash(uint32_t createTime); + void downlinkImage(uint8_t *image, int size, uint16_t callbackId, uint32_t createTime); + + S25fl512l m_fpgaFlash; + uint8_t m_imageLineBuffer[IMAGE_WIDTH]; + U32 m_numComponentImgsReq; + U32 m_numGroundImgsReq; + U32 m_imagesSent; + U32 m_bytesSent; + uint16_t m_lastCallbackId; + uint8_t m_cameraSelect; }; } // end namespace CubeRover diff --git a/Apps/FlightSoftware/fprime/CubeRover/Camera/CameraComponentAi.xml b/Apps/FlightSoftware/fprime/CubeRover/Camera/CameraComponentAi.xml index ef1058ec3..b4f05d040 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/Camera/CameraComponentAi.xml +++ b/Apps/FlightSoftware/fprime/CubeRover/Camera/CameraComponentAi.xml @@ -1,5 +1,6 @@ CubeRover/CubeRoverPorts/FileDownlink/FileDownlinkPortAi.xml + Fw/Time/TimePortAi.xml CubeRover/CubeRoverPorts/CameraTakePicture/CameraTakePicturePortAi.xml Manages the CubeRover cameras diff --git a/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.cpp b/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.cpp index 51edcc581..654348748 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.cpp +++ b/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.cpp @@ -11,9 +11,12 @@ // ====================================================================== #include +#include // ! TODO: FIXME Hacky patch connection to steal NM data #include "Fw/Types/BasicTypes.hpp" #include +extern CubeRover::NetworkManagerComponentImpl networkManager; // ! TODO: FIXME Hacky patch connection to steal NM data + namespace CubeRover { @@ -172,6 +175,7 @@ namespace CubeRover { struct FswPacket::FswFile *obj = reinterpret_cast(downlinkBuffer); obj->header.magic = FSW_FILE_MAGIC; + obj->header.hashedId = hashedId; obj->header.totalBlocks = 1; obj->header.blockNumber = 1; obj->header.length = static_cast(dataSize); @@ -179,6 +183,14 @@ namespace CubeRover downlinkFileMetadata(hashedId, 1, static_cast(callbackId), static_cast(createTime)); downlinkBufferWrite(downlinkBuffer, static_cast(singleFileObjectSize), DownlinkFile); m_appBytesDownlinked += singleFileObjectSize; + // ! TODO: FIXME + // !Forcibly halt the idle thread until Wf121TxTask sends the packet (tx count goes up): + // ! (do this to avoid maxing out the radio Tx queue): + flushTlmDownlinkBuffer(); // FLUSH BUFFER TO GET PACKET OUT + int startUdpTxCount = networkManager.m_pRadioDriver->m_networkInterface.m_protectedRadioStatus.getUdpTxPacketCount(); + while(startUdpTxCount == networkManager.m_pRadioDriver->m_networkInterface.m_protectedRadioStatus.getUdpTxPacketCount() && networkManager.m_pRadioDriver->m_networkInterface.udpTxQueueRoom() < 1){ + vTaskDelay(10 / portTICK_PERIOD_MS); // Check back in 10ms + } } else { // Send file fragments @@ -207,6 +219,13 @@ namespace CubeRover log_DIAGNOSTIC_GI_DownlinkedItem(m_downlinkSeq, DownlinkFile); downlink(downlinkBuffer, datagramLength); data += blockLength; + // ! TODO: FIXME + // !Forcibly halt the idle thread until Wf121TxTask sends the packet (tx count goes up): + // ! (do this to avoid maxing out the radio Tx queue): + int startUdpTxCount = networkManager.m_pRadioDriver->m_networkInterface.m_protectedRadioStatus.getUdpTxPacketCount(); + while(startUdpTxCount == networkManager.m_pRadioDriver->m_networkInterface.m_protectedRadioStatus.getUdpTxPacketCount() && networkManager.m_pRadioDriver->m_networkInterface.udpTxQueueRoom() < 1){ + vTaskDelay(10 / portTICK_PERIOD_MS); // Check back in 10ms + } } else { // Final Fragment is written to the member buffer to downlink with other objects diff --git a/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.hpp b/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.hpp index 955ee0ec8..bb4d31758 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.hpp +++ b/Apps/FlightSoftware/fprime/CubeRover/GroundInterface/GroundInterface.hpp @@ -14,6 +14,7 @@ #define GroundInterface_HPP #include "CubeRover/GroundInterface/GroundInterfaceComponentAc.hpp" +#include "CubeRover/NetworkManager/NetworkManager.hpp" // ! TODO: FIXME Hacky patch connection to steal NM data #include namespace CubeRover { diff --git a/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.cpp b/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.cpp index 7b479f7e1..14f4104fb 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.cpp +++ b/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.cpp @@ -27,6 +27,7 @@ #include #include #include +#include extern CubeRover::WatchDogInterfaceComponentImpl watchDogInterface; @@ -178,11 +179,29 @@ namespace CubeRover const NATIVE_INT_TYPE portNum, Fw::Buffer &fwBuffer) { + if(portNum == 1 && m_pRadioDriver->m_networkInterface.udpTxQueueRoom() <= 2){ + // Don't let WDI send anything if we're currently swamped + return; + } + + static Os::Mutex sloppyResourceProtectionMutex; // quick and dirty. keeps multiple tasks from doing this at once (i.e. GI and WDI) + sloppyResourceProtectionMutex.lock(); // Grab the data from the FW Buffer: uint8_t *buffer = reinterpret_cast(fwBuffer.getdata()); + if( + (fwBuffer.getsize() >= 8 && (memcmp(buffer, "DEBUGRTT", 8) == 0)) + || (fwBuffer.getsize() >= 8 && (memcmp(buffer, "DEBUGRDL", 8) == 0)) + ){ + // Don't let RTT or RDL messages be sent over wifi (too many of them): + sloppyResourceProtectionMutex.unLock(); + return; + } + + // Copy it into the outbound payload: m_udpPayloadWorkingBuffer.copyIn(fwBuffer.getsize(), buffer); + sloppyResourceProtectionMutex.unLock(); // unlock before potentially getting stuck in Queue wait. // Queue up the Payload for downlink: m_pRadioDriver->m_networkInterface.sendUdpPayload(&m_udpPayloadWorkingBuffer); diff --git a/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.hpp b/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.hpp index 03ade2059..c91940d3f 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.hpp +++ b/Apps/FlightSoftware/fprime/CubeRover/NetworkManager/NetworkManager.hpp @@ -224,11 +224,12 @@ namespace CubeRover ); // User defined methods, members, and structs - +public: // Pointer to the RadioDriver being used (we add this level of indirection // and don't just use `CORE_RADIO_DRIVER` in case we want to change what's // used in the future): Wf121::RadioDriver *m_pRadioDriver; +PRIVATE: // Single common working buffer used for handling RX'd or TX'ing UDP Payloads: // (NOT for long term storage of data / passing data out of NetworkManager): Wf121::UdpPayload m_udpPayloadWorkingBuffer; diff --git a/Apps/FlightSoftware/fprime/CubeRover/Top/CubeRoverTopologyAppAi.xml b/Apps/FlightSoftware/fprime/CubeRover/Top/CubeRoverTopologyAppAi.xml index b87fa6cb2..783276539 100644 --- a/Apps/FlightSoftware/fprime/CubeRover/Top/CubeRoverTopologyAppAi.xml +++ b/Apps/FlightSoftware/fprime/CubeRover/Top/CubeRoverTopologyAppAi.xml @@ -212,6 +212,11 @@ + + + + +