Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Iridium #103

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 11 additions & 2 deletions MainControlLoop/lib/StateFieldRegistry/registry.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,9 @@ def __init__(self):
Defines all the StateFields present in the state registry
"""
self.registry = {
# DUMP / BEACON TELEMETRY
# region DUMP / BEACON TELEMETRY

# EPS DATA
StateField.TIME: 0.0,
StateField.IIDIODE_OUT: 0.0,
StateField.VIDIODE_OUT: 0.0,
Expand Down Expand Up @@ -38,14 +40,21 @@ def __init__(self):
StateField.PDM_7_STAT: -1,
StateField.PDM_8_STAT: -1,

# IRIDIUM DATA
StateField.GEOLOCATION: '',
StateField.IRIDIUM_SIGNAL: '',

# endregion

# INTERVALS
StateField.APRS_BEACON_INTERVAL: -1,
StateField.IRIDIUM_BEACON_INTERVAL: -1,
StateField.IRIDIUM_DUMP_INTERVAL: -1,

# TIME RECORDINGS
StateField.APRS_LAST_MESSAGE_TIME: 0.0,
StateField.IRIDIUM_LAST_MESSAGE_TIME: 0.0,
StateField.APRS_LAST_BEACON_TIME: 0.0,
StateField.IRIDIUM_LAST_DUMP_TIME: 0.0,
StateField.LAST_ARCHIVE_TIME: 0.0,
StateField.BOOT_TIME: -1,

Expand Down
28 changes: 24 additions & 4 deletions MainControlLoop/lib/StateFieldRegistry/state_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,9 @@

class StateField(Enum):

# DUMP / BEACON TELEMETRY
# region DUMP / BEACON TELEMETRY

# EPS DATA
TIME = 'TIME'
IIDIODE_OUT = 'IIDIODE_OUT'
VIDIODE_OUT = 'VIDIODE_OUT'
Expand Down Expand Up @@ -31,14 +33,21 @@ class StateField(Enum):
PDM_7_STAT = "PDM_7_STAT"
PDM_8_STAT = "PDM_8_STAT"

# IRIDIUM DATA
GEOLOCATION = "GEOLOCATION"
IRIDIUM_SIGNAL = "IRIDIUM_SIGNAL"

# end region

# TIME INTERVALS
APRS_BEACON_INTERVAL = 'APRS_BEACON_INTERVAL'
IRIDIUM_BEACON_INTERVAL = 'IRIDIUM_BEACON_INTERVAL'
IRIDIUM_DUMP_INTERVAL = 'IRIDIUM_BEACON_INTERVAL'

# TIME RECORDINGS
APRS_LAST_MESSAGE_TIME = 'APRS_LAST_MESSAGE_TIME'
IRIDIUM_LAST_MESSAGE_TIME = 'IRIDIUM_LAST_MESSAGE_TIME'
APRS_LAST_BEACON_TIME = 'APRS_LAST_BEACON_TIME'
IRIDIUM_LAST_DUMP_TIME = "IRIDIUM_LAST_DUMP_TIME"
LAST_ARCHIVE_TIME = 'LAST_ARCHIVE_TIME'
BOOT_TIME = 'BOOT_TIME'

Expand All @@ -56,7 +65,9 @@ class ErrorFlag(Enum):


StateFieldTypeCheck = {
# DUMP / BEACON TELEMETRY
# region DUMP / BEACON TELEMETRY

# EPS DATA
StateField.TIME: float,
StateField.IIDIODE_OUT: float,
StateField.VIDIODE_OUT: float,
Expand All @@ -83,15 +94,22 @@ class ErrorFlag(Enum):
StateField.PDM_6_STAT: int,
StateField.PDM_7_STAT: int,
StateField.PDM_8_STAT: int,

# IRIDIUM DATA
StateField.GEOLOCATION: str,
StateField.IRIDIUM_SIGNAL: int,

# endregion

# INTERVALS
StateField.APRS_BEACON_INTERVAL: int,
StateField.IRIDIUM_BEACON_INTERVAL: int,
StateField.IRIDIUM_DUMP_INTERVAL: int,

# TIME RECORDINGS
StateField.APRS_LAST_MESSAGE_TIME: float,
StateField.IRIDIUM_LAST_MESSAGE_TIME: float,
StateField.APRS_LAST_BEACON_TIME: float,
StateField.IRIDIUM_LAST_DUMP_TIME: float,
StateField.LAST_ARCHIVE_TIME: float,
StateField.BOOT_TIME: float,

Expand All @@ -101,6 +119,8 @@ class ErrorFlag(Enum):
StateField.ANTENNA_DEPLOY_ATTEMPTED: bool
}

# FIXME: the following should be removed before production

for state_field in StateField:
if state_field not in StateFieldTypeCheck:
raise NotImplementedError(f"{state_field}'s type has not been declared in StateFieldTypeCheck dictionary.")
57 changes: 39 additions & 18 deletions MainControlLoop/lib/drivers/Iridium.py
Original file line number Diff line number Diff line change
@@ -1,37 +1,36 @@
from enum import Enum
from time import sleep
from serial import Serial

from MainControlLoop.lib.devices.device import Device


class Commands(Enum):
TEST_IRIDIUM = 'AT'
class IridiumCommand(Enum):
# Used Commands
# FIXME: test these commands once patch antenna is working
GEOLOCATION = 'AT-MSGEO'
SOFT_RESET = 'ATZn'
SIGNAL = 'AT+CSQ'

# FIXME: delete the following region before production
# region unused commands

TEST_IRIDIUM = 'AT'
ACTIVE_CONFIG = 'AT+V'
CHECK_REGISTRATION = 'AT+SBDREG?'
PHONE_MODEL = 'AT+CGMM'
PHONE_REVISION = 'AT+CGMR'
PHONE_IMEI = 'AT+CSGN'
CHECK_NETWORK = 'AT-MSSTM'
CHECK_NETWORK = 'AT-MSSTM' # FIXME: Iridium documentation says this is for system time?
SHUT_DOWN = 'AT*F'
SIGNAL_QUAL = 'AT+CSQ'

# FIXME: cannot be tested until patch antenna is working
# following commands probably need to be retested once patch antenna is fixed

SEND_SMS = 'AT+CMGS='
SIGNAL = 'AT+CSQ'
SBD_RING_ALERT_ON = 'AT+SBDMTA=1'
SBD_RING_ALERT_OFF = 'AT+SBDMTA=0'
BATTERY_CHECK = 'AT+CBC=?'
CALL_STATUS = 'AT+CLCC=?'
SOFT_RESET = 'ATZn'


class ResponseCode(Enum):
OK = [b'O', b'K']
ERROR = [b'E', b'R', b'R', b'O', b'R']
# endregion


class Iridium(Device):
Expand Down Expand Up @@ -73,18 +72,40 @@ def functional(self) -> bool:
except:
return False

def write(self, command: str) -> bool:
def write(self, message: str) -> bool:
"""
Write a command to the serial port.
:param command: (str) Command to write
Write a message to the serial port.
:param message: (str) Message to write
:return: (bool) if the serial write worked
"""

if not self.functional():
return False

command = command + "\r\n"
message = message + "\r\n"
try:
self.serial.write(message.encode("UTF-8"))
except:
return False

return True

def write_command(self, command: IridiumCommand) -> bool:
"""
Writes one of the Iridium commands to the serial port
:param command: (IridiumCommand) Command to write
:return: (bool) if the serial write worked
"""

if type(command) != IridiumCommand:
return False

if not self.functional():
return False

command_str = command.value + "\r\n"
try:
self.serial.write(command.encode("UTF-8"))
self.serial.write(command_str.encode("UTF-8"))
except:
return False

Expand Down
4 changes: 3 additions & 1 deletion MainControlLoop/main_control_loop.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ def __init__(self):

def execute(self):
# READ BLOCK
commands = ['', '', ''] # APRS, Iridium, System
commands = ['', ''] # APRS, Iridium
self.pi_monitor.read()
commands[0] = self.aprs.read()
commands[1] = self.iridium.read()
Expand All @@ -29,7 +29,9 @@ def execute(self):
self.archiver.control()
self.pi_monitor.control(commands)
self.aprs.control(commands)
self.iridium.control()

# ACTUATE BLOCK
self.pi_monitor.actuate()
self.aprs.actuate()
self.iridium.actuate()
10 changes: 5 additions & 5 deletions MainControlLoop/tasks/DownLinkProducer/down_link_producer.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,17 +43,17 @@ def create_dump(state_field_registry: StateFieldRegistry) -> [str]:
StateField.PDM_8_STAT
]

dumpList = [dump_header]
dump_list = [dump_header]

for element in elements:
value = state_field_registry.get(element)
dump_addition = f"{value};"
if len(dumpList[-1] + dump_addition) > max_length:
if len(dump_list[-1] + dump_addition) > max_length:
# Add the message number, len() - 1 because indexing by 0
dumpList.append(dump_header + f"{len(dumpList) - 1};")
dumpList[-1] += dump_addition
dump_list.append(dump_header + f"{len(dump_list) - 1};")
dump_list[-1] += dump_addition

return dumpList
return dump_list

@staticmethod
def create_beacon(state_field_registry: StateFieldRegistry) -> str:
Expand Down
4 changes: 4 additions & 0 deletions MainControlLoop/tasks/Iridium/actuate/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
from .dump import IridiumDumpActuateTask
from .geolocation import IridiumGeolocationActuateTask
from .reset import IridiumResetActuateTask
from .signal import IridiumSignalStrengthActuateTask
37 changes: 37 additions & 0 deletions MainControlLoop/tasks/Iridium/actuate/dump.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from MainControlLoop.lib.drivers.Iridium import Iridium
from MainControlLoop.lib.StateFieldRegistry import StateFieldRegistry, ErrorFlag


class IridiumDumpActuateTask:
def __init__(self, iridium: Iridium, state_field_registry: StateFieldRegistry):
self.iridium: Iridium = iridium
self.state_field_registry: StateFieldRegistry = state_field_registry
self.run = False
self.dump: list = []

def set_dump(self, messages: list):
if not isinstance(messages, list):
return

for message in messages:
if not isinstance(message, str):
return

self.dump = messages

def execute(self):
if not self.run:
return

self.run = False
if len(self.dump) == 0:
return

for portion in self.dump:
success = self.iridium.write(portion)
if not success:
self.state_field_registry.raise_flag(ErrorFlag.IRIDIUM_FAILURE)
self.dump = []
return

self.dump = []
19 changes: 19 additions & 0 deletions MainControlLoop/tasks/Iridium/actuate/geolocation.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from MainControlLoop.lib.drivers.Iridium import Iridium, IridiumCommand
from MainControlLoop.lib.StateFieldRegistry import StateFieldRegistry, ErrorFlag


class IridiumGeolocationActuateTask:
def __init__(self, iridium: Iridium, state_field_registry: StateFieldRegistry):
self.iridium: Iridium = iridium
self.state_field_registry: StateFieldRegistry = state_field_registry
self.run = False

def execute(self):
if not self.run:
return

self.run = False

success = self.iridium.write_command(IridiumCommand.GEOLOCATION)
if not success:
self.state_field_registry.raise_flag(ErrorFlag.IRIDIUM_FAILURE)
19 changes: 19 additions & 0 deletions MainControlLoop/tasks/Iridium/actuate/reset.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from MainControlLoop.lib.drivers.Iridium import Iridium, IridiumCommand
from MainControlLoop.lib.StateFieldRegistry import StateFieldRegistry, ErrorFlag


class IridiumResetActuateTask:
def __init__(self, iridium: Iridium, state_field_registry: StateFieldRegistry):
self.iridium: Iridium = iridium
self.state_field_registry: StateFieldRegistry = state_field_registry
self.run = False

def execute(self):
if not self.run:
return

self.run = False

success = self.iridium.write_command(IridiumCommand.SOFT_RESET)
if not success:
self.state_field_registry.raise_flag(ErrorFlag.IRIDIUM_FAILURE)
19 changes: 19 additions & 0 deletions MainControlLoop/tasks/Iridium/actuate/signal.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
from MainControlLoop.lib.drivers.Iridium import Iridium, IridiumCommand
from MainControlLoop.lib.StateFieldRegistry import StateFieldRegistry, ErrorFlag


class IridiumSignalStrengthActuateTask:
def __init__(self, iridium: Iridium, state_field_registry: StateFieldRegistry):
self.iridium: Iridium = iridium
self.state_field_registry: StateFieldRegistry = state_field_registry
self.run = False

def execute(self):
if not self.run:
return

self.run = False

success = self.iridium.write_command(IridiumCommand.SIGNAL)
if not success:
self.state_field_registry.raise_flag(ErrorFlag.IRIDIUM_FAILURE)
37 changes: 37 additions & 0 deletions MainControlLoop/tasks/Iridium/actuate_task.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
from MainControlLoop.lib.drivers import Iridium
from MainControlLoop.lib.StateFieldRegistry import StateFieldRegistry

from MainControlLoop.tasks.Iridium.actuate import IridiumDumpActuateTask
from MainControlLoop.tasks.Iridium.actuate import IridiumGeolocationActuateTask
from MainControlLoop.tasks.Iridium.actuate import IridiumResetActuateTask
from MainControlLoop.tasks.Iridium.actuate import IridiumSignalStrengthActuateTask


class IridiumActuateTask:

def __init__(self, iridium: Iridium, state_field_registry: StateFieldRegistry):
self.dump_actuate_task = IridiumDumpActuateTask(iridium, state_field_registry)
self.geolocation_actuate_task = IridiumGeolocationActuateTask(iridium, state_field_registry)
self.reset_actuate_task = IridiumResetActuateTask(iridium, state_field_registry)
self.signal_strength_actuate_task = IridiumSignalStrengthActuateTask(iridium, state_field_registry)

def set_dump(self, dump):
self.dump_actuate_task.set_dump(dump)

def enable_dump(self):
self.dump_actuate_task.run = True

def enable_geolocation(self):
self.geolocation_actuate_task.run = True

def enable_reset(self):
self.reset_actuate_task.run = True

def enable_signal_strength(self):
self.signal_strength_actuate_task.run = True

def execute(self):
self.reset_actuate_task.execute()
self.dump_actuate_task.execute()
self.geolocation_actuate_task.execute()
self.signal_strength_actuate_task.execute()
Loading