Skip to content
Merged
118 changes: 66 additions & 52 deletions src/ControlTasks/RadioControlTask.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,11 @@ RadioControlTask::RadioControlTask()
void RadioControlTask::init()
{
if (!sfr::radio::initialized) {
switch (sfr::radio::start_progress) {
case 0:
if (sfr::radio::start_progress == 0) {
#ifdef VERBOSE
Serial.print(F("Radio: Initializing ... "));
Serial.println(F("Radio: Initializing ... "));
#endif
// initialize SX1278 with default settings
// Initialize SX1278 with default settings
code = radio.begin(constants::radio::freq, constants::radio::bw, constants::radio::sf, constants::radio::cr,
constants::radio::sw, constants::radio::pwr, constants::radio::pl, constants::radio::gn);
if (code == RADIOLIB_ERR_NONE) {
Expand All @@ -23,12 +22,13 @@ void RadioControlTask::init()
Serial.println(code);
#endif
}
break;
case 1:
}

if (sfr::radio::start_progress == 1) {
#ifdef VERBOSE
Serial.print(F("Radio: Setting CRC parameter ... "));
Serial.println(F("Radio: Setting CRC parameter ... "));
#endif
// set CRC parameter to true so it matches the CRC parameter on the TinyGS side
// Set CRC parameter to true so it matches the CRC parameter on the TinyGS side
code = radio.setCRC(true);
if (code == RADIOLIB_ERR_NONE) {
sfr::radio::start_progress++;
Expand All @@ -38,39 +38,51 @@ void RadioControlTask::init()
Serial.println(code);
#endif
}
break;
case 2:

if (sfr::radio::start_progress == 2) {
#ifdef VERBOSE
Serial.print(F("Radio: Setting forceLDRO parameter ... "));
Serial.println(F("Radio: Setting forceLDRO parameter ... "));
#endif
// set forceLDRO parameter to true so it matches the forceLDRO parameter on the TinyGS side
code = radio.forceLDRO(true);
if (code == RADIOLIB_ERR_NONE) {
sfr::radio::start_progress++;
} else {
// Set forceLDRO parameter to true so it matches the forceLDRO parameter on the TinyGS side
code = radio.forceLDRO(true);
if (code == RADIOLIB_ERR_NONE) {
sfr::radio::initialized = true;
} else {
#ifdef VERBOSE
Serial.print(F("failed, code "));
Serial.println(code);
Serial.print(F("failed, code "));
Serial.println(code);
#endif
}
}
break;
case 3: // completed initialization
sfr::radio::initialized = true;
break;
}
}
}

bool RadioControlTask::transmit(uint8_t *packet, uint8_t size)
{
// Blink LED during transmit
if (millis() - sfr::gps::boot_time > constants::led::led_on_time) {
digitalWrite(constants::led::led_pin, HIGH);
}

#ifdef VERBOSE
uint32_t start = millis();
#endif
code = radio.transmit(packet, size);
#ifdef VERBOSE
uint32_t time = millis() - start;
#endif

if (millis() - sfr::gps::boot_time > constants::led::led_on_time) {
digitalWrite(constants::led::led_pin, LOW);
}
#ifdef VERBOSE
Serial.print(F("Time to transmit (ms): "));
Serial.println(time);
#endif

if (code == RADIOLIB_ERR_NONE) {
// the packet was successfully transmitted
// The packet was successfully transmitted
#ifdef VERBOSE
Serial.println(F("success!"));
Serial.print(F("[SX1278] Datarate:\t"));
Expand All @@ -81,10 +93,10 @@ bool RadioControlTask::transmit(uint8_t *packet, uint8_t size)
} else {
#ifdef VERBOSE
if (code == RADIOLIB_ERR_TX_TIMEOUT) {
// timeout occurred while transmitting packet
// Timeout occurred while transmitting packet
Serial.println(F("timeout!"));
} else {
// some other error occurred
// Some other error occurred
Serial.print(F("failed, code "));
Serial.println(code);
}
Expand All @@ -104,23 +116,13 @@ bool RadioControlTask::receive()
// packet was successfully received
Serial.println(F("success!"));

// print the data of the packet
Serial.print(F("[SX1278] Data:\t\t\t"));

// print the RSSI (Received Signal Strength Indicator)
// of the last received packet
Serial.print(F("[SX1278] RSSI:\t\t\t"));
Serial.print(radio.getRSSI());
Serial.println(F(" dBm"));

// print the SNR (Signal-to-Noise Ratio)
// of the last received packet
Serial.print(F("[SX1278] SNR:\t\t\t"));
Serial.print(radio.getSNR());
Serial.println(F(" dB"));

// print frequency error
// of the last received packet
Serial.print(F("[SX1278] Frequency error:\t"));
Serial.print(radio.getFrequencyError());
Serial.println(F(" Hz"));
Expand All @@ -129,13 +131,13 @@ bool RadioControlTask::receive()
} else {
#ifdef VERBOSE
if (code == RADIOLIB_ERR_RX_TIMEOUT) {
// timeout occurred while waiting for a packet
// Timeout occurred while waiting for a packet
Serial.println(F("timeout!"));
} else if (code == RADIOLIB_ERR_CRC_MISMATCH) {
// packet was received, but is malformed
// Packet was received, but is malformed
Serial.println(F("CRC error!"));
} else {
// some other error occurred
// Some other error occurred
Serial.print(F("failed, code "));
Serial.println(code);
}
Expand All @@ -146,14 +148,25 @@ bool RadioControlTask::receive()

void RadioControlTask::execute()
{
// implements the state machine described in: https://github.com/Alpha-CubeSat/oop-chipsat-code/wiki
// Implement the state machine described in https://github.com/Alpha-CubeSat/oop-chipsat-code/wiki
switch (sfr::radio::mode) {
case radio_mode_type::init: {
#ifdef VERBOSE
Serial.println(F("Radio: Init State"));
#endif
init();
if (sfr::radio::initialized) {
sfr::radio::mode = radio_mode_type::aliveSignal;
}
break;
}
case radio_mode_type::aliveSignal: {
#ifdef VERBOSE
Serial.println(F("Radio: Alive Signal State"));
#endif
normalReportDownlink();
sfr::radio::alive_signal_dlinks++;
if (sfr::radio::alive_signal_dlinks == constants::radio::max_alive_signal_dlinks) {
sfr::radio::mode = radio_mode_type::downlink;
sfr::radio::listen_period_start = millis();
downlinkSettings();
Expand All @@ -164,24 +177,24 @@ void RadioControlTask::execute()
#ifdef VERBOSE
Serial.println(F("Radio: Downlink State"));
#endif
// downlink when slot reached
// Downlink when slot reached
if (!sfr::radio::downlinked_in_slot && millis() - sfr::radio::downlink_window_start >= constants::radio::transmit_slot_length * sfr::radio::downlink_slot) {
executeDownlink();
sfr::radio::downlinked_in_slot = true;
}

// go into listen mode if listen period reached
// Go into listen mode if listen period reached
if (millis() - sfr::radio::listen_period_start >= constants::radio::listen_period) {
sfr::radio::mode = radio_mode_type::listen;

#ifdef VERBOSE
Serial.println(F("Radio: Listen Flag Downlink"));
#endif
// downlink with listen flag = true
// Downlink with listen flag = true
normalReportDownlink();
sfr::radio::command_wait_start = millis();
}
// reset window and choose slot for next downlink
// Reset window and choose slot for next downlink
else if (millis() - sfr::radio::downlink_window_start >= sfr::radio::downlink_window_length) {
downlinkSettings();
}
Expand All @@ -191,7 +204,7 @@ void RadioControlTask::execute()
#ifdef VERBOSE
Serial.println(F("Radio: Listen State"));
#endif
// built in timeout is 100 LoRa symbols
// Built in timeout is 100 LoRa symbols
bool receive_success = receive();
if (receive_success) {
processUplink();
Expand Down Expand Up @@ -225,7 +238,7 @@ bool RadioControlTask::executeDownlink()
if (millis() - sfr::radio::last_callsign_time < constants::radio::callsign_interval) {
return normalReportDownlink();
} else {
uint8_t dlink[] = {'K', 'D', '2', 'W', 'T', 'Q'};
uint8_t dlink[] = {'K', 'C', '3', 'V', 'A', 'T', 'K', 'D', '2', 'W', 'T', 'Q', 'K', 'E', '2', 'A', 'T', 'R'};
sfr::radio::last_callsign_time = millis();
#ifdef VERBOSE
Serial.println(F("Callsign Report"));
Expand All @@ -237,17 +250,18 @@ bool RadioControlTask::executeDownlink()

bool RadioControlTask::normalReportDownlink()
{
// see https://github.com/Alpha-CubeSat/oop-chipsat-code/wiki/2.-Telemetry for more info
// See https://github.com/Alpha-CubeSat/oop-chipsat-code/wiki/2.-Telemetry for more info
uint16_t lat = sfr::gps::latitude * 100;
uint16_t lon = sfr::gps::longitude * 100;
uint16_t alt = sfr::gps::altitude / 10;

uint8_t flags = 0;
flags |= constants::radio::id << 6;
flags |= sfr::gps::valid_msg << 5; // gps valid
flags |= sfr::imu::initialized << 4; // imu valid
flags |= sfr::gps::on << 3; // boot mode flag
flags |= (sfr::radio::mode == radio_mode_type::listen) << 2; // listen flag
flags |= constants::radio::id << 6; // chipsat ID #
flags |= sfr::gps::valid_location << 5; // gps position valid
flags |= sfr::gps::valid_altitude << 4; // gps altiude valid
flags |= sfr::imu::initialized << 3; // imu valid
flags |= sfr::gps::on << 2; // boot mode flag
flags |= (sfr::radio::mode == radio_mode_type::listen) << 1; // listen flag

uint8_t dlink[] = {
(uint8_t)lat, (uint8_t)(lat >> 8),
Expand Down Expand Up @@ -286,7 +300,7 @@ uint8_t RadioControlTask::map_range(float value, int min_val, int max_val)

void RadioControlTask::processUplink()
{
// see https://github.com/Alpha-CubeSat/oop-chipsat-code/wiki/3.-Commands for more info
// See https://github.com/Alpha-CubeSat/oop-chipsat-code/wiki/3.-Commands for more info
switch (received[0]) {
case constants::opcodes::no_op: // No-Op
#ifdef VERBOSE
Expand Down
6 changes: 3 additions & 3 deletions src/ControlTasks/RadioControlTask.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ class RadioControlTask
void init();

/**
* Resets the transmit window start time and picks a new slot
* @brief Resets the transmit window start time and picks a new slot
*/
void downlinkSettings();

/**
* @brief Wrapper around RadioLib's transmit() to provide metadata (TODO: Redundant?)
* @brief Wrapper around RadioLib's transmit() to provide metadata
*/
bool transmit(uint8_t *packet, uint8_t size);

/**
* @brief Attempts to receive a 3 byte command (TODO: Redundant?)
* @brief Attempts to receive a 3 byte command
*/
bool receive();

Expand Down
10 changes: 9 additions & 1 deletion src/MainControlLoop.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -61,16 +61,24 @@ void MainControlLoop::execute()
Serial.print(F("GPS Altitude (m): "));
Serial.println(sfr::gps::altitude);

Serial.print("Downlink Slot: ");
Serial.print(F("Downlink Slot: "));
Serial.println(sfr::radio::downlink_slot);

Serial.print(F("Alive Time: "));
Serial.println(millis() - sfr::gps::boot_time);

#endif

temp_monitor.execute();
imu_monitor.execute();
gps_monitor.execute();
radio_control_task.execute();

// Turn off LED 5 seconds after boot
if (millis() - sfr::gps::boot_time > constants::led::led_on_time) {
digitalWrite(constants::led::led_pin, LOW);
}

wdt_reset();

#ifdef VERBOSE
Expand Down
1 change: 1 addition & 0 deletions src/Modes/radio_mode_type.enum
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
enum class radio_mode_type : unsigned char
{
init = 0,
aliveSignal,
downlink,
listen
};
Expand Down
10 changes: 6 additions & 4 deletions src/Monitors/GPSMonitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ void GPSMonitor::init()
digitalWrite(constants::gps::reset_pin, LOW);
sfr::gps::on = true;

// writes NMEA output message type to SRAM and Flash
// Writes NMEA output message type to SRAM and Flash
uint8_t SetNMEA[] = {
0xA0, 0xA1, 0x00, 0x03, 0x09, 0x01, 0x01, 0x09, 0x0D, 0x0A};

Expand All @@ -19,6 +19,7 @@ void GPSMonitor::init()

void GPSMonitor::execute()
{
// Turn on GPS after boot mode is over (10 seconds)
if (!sfr::gps::on) {
if (millis() - sfr::gps::boot_time > constants::gps::boot_time) {
init();
Expand All @@ -33,10 +34,8 @@ void GPSMonitor::execute()
gps.encode(ss.read());
serial_reads++;
}
// while (*gpsStream) {
// gps.encode(*gpsStream++);
// }

// Read GPS values if they are valid
if (gps.location.isUpdated() && gps.location.isValid()) {
sfr::gps::latitude = gps.location.lat();
sfr::gps::longitude = gps.location.lng();
Expand All @@ -50,6 +49,9 @@ void GPSMonitor::execute()
sfr::gps::utc_time = gps.time.value();
}

sfr::gps::valid_location = gps.location.isValid();
sfr::gps::valid_altitude = gps.altitude.isValid();

#ifdef VERBOSE
Serial.print(F("Chars="));
Serial.print(gps.charsProcessed());
Expand Down
7 changes: 1 addition & 6 deletions src/Monitors/GPSMonitor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,9 @@ class GPSMonitor
SoftwareSerial ss = SoftwareSerial(constants::gps::rx_pin, constants::gps::tx_pin);

/**
* Begins the software serial instance and configures the GPS receiver
* @brief Begins the software serial instance and configures the GPS receiver
*/
void init();

// TODO: Test edge cases for lat, lon, alt
const char *gpsStream = "$GPGGA,045104.000,3014.1985,N,09749.2873,W,1,09,1.2,211.6,M,-22.5,M,,0000*62\r\n"
"$GPGGA,045201.000,3014.3864,N,09748.9411,W,1,10,1.2,200.8,M,-22.5,M,,0000*6C\r\n"
"$GPGG@,045252.000,3014.4273,S,09749.0628,W,1,09,1.3,206.9,M,-22.5,M,,0000*6F\r\n";
};

#endif
Loading
Loading