Skip to content

Commit

Permalink
add greencube protocol support
Browse files Browse the repository at this point in the history
  • Loading branch information
baskiton committed May 28, 2024
1 parent 3c12276 commit 979dba7
Show file tree
Hide file tree
Showing 4 changed files with 234 additions and 2 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ and wait for result.
#### Protocols
The following protocols are currently supported:
* `GEOSCAN` - [Geoscan platform](https://download.geoscan.aero/site-files/%D0%9F%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB%20%D0%BF%D0%B5%D1%80%D0%B5%D0%B4%D0%B0%D1%87%D0%B8%20%D1%82%D0%B5%D0%BB%D0%B5%D0%BC%D0%B5%D1%82%D1%80%D0%B8%D0%B8.pdf)
* `GreenCube` - [GreenCube](https://www.s5lab.space/index.php/decoding-ledsat-2/)
* `USP` - [Unified SPUTNIX protocol](https://sputnix.ru/tpl/docs/amateurs/%D0%9E%D0%BF%D0%B8%D1%81%D0%B0%D0%BD%D0%B8%D0%B5%20%D0%BF%D1%80%D0%BE%D1%82%D0%BE%D0%BA%D0%BE%D0%BB%D0%B0%20USP%20v1.04.pdf)
* `AX.25`
* `CSP` - [Cubesat Space Protocol](https://github.com/libcsp/libcsp)
Expand Down
2 changes: 2 additions & 0 deletions SatsDecoder/systems/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
from SatsDecoder.systems.ax25 import *
from SatsDecoder.systems.csp import *
from SatsDecoder.systems.geoscan import *
from SatsDecoder.systems.greencube import *
from SatsDecoder.systems.lucky7 import *
from SatsDecoder.systems.roseycubesat import *
from SatsDecoder.systems.sharjahsat import *
Expand All @@ -22,6 +23,7 @@
PROTOCOLS = {}
for i in (
'geoscan',
'greencube',
'usp',
'ax25',
'csp',
Expand Down
223 changes: 223 additions & 0 deletions SatsDecoder/systems/greencube.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
# Copyright (c) 2024. Alexander Baskikh
# # MIT License (MIT), http://opensource.org/licenses/MIT # Full license can be found in the LICENSE-MIT file
# # SPDX-License-Identifier: MIT

import construct

from SatsDecoder.systems import csp, common

__all__ = 'GreenCubeProtocol',

proto_name = 'greencube'

"""
https://www.s5lab.space/index.php/decoding-ledsat-2/
"""


val_x10 = common.LinearAdapter(10, construct.Int16sb)
val_x100 = common.LinearAdapter(100, construct.Int16sb)
val_x1000000 = common.LinearAdapter(1000000, construct.Int32sb)

tlm_id_enums_v1 = {
'Current telemetry': 0x3610,
'Stored telemetry': 0x3611,
'Beacon': 0x3612,
}

greencube_tlm = construct.Struct(
'_name' / construct.Computed('greencube_tlm'),
'name' / construct.Computed('Telemetry'),

'id' / construct.Hex(construct.Enum(construct.Int16ub, **tlm_id_enums_v1)), # U, 2, Telemetry Identifier
'time_ms' / construct.Int16ub, # U, 2, Millisecond part of the unix time, ms
'Time' / common.UNIXTimestampAdapter(construct.Int32ub), # U, 4, On-board unix time, s
'proctime' / construct.Int16ub, # U, 2, Time taken to process the telemetry, ms
'eps_vboost_0' / construct.Int16ub, # U, 2, Voltage of X axis solar panels, mV
'eps_vboost_1' / construct.Int16ub, # U, 2, Voltage of Y axis solar panels, mV
'eps_cboost_0' / construct.Int16ub, # U, 2, Current of X axis solar panels, mA
'eps_cboost_1' / construct.Int16ub, # U, 2, Current of Y axis solar panels, mA
'eps_bootcause' / construct.Hex(construct.Int8ub), # U, 1, EPS bootcause
'eps_temp_0' / construct.Int8sb, # S, 1, Temperature of X axis MPPT, °C
'eps_temp_1' / construct.Int8sb, # S, 1, Temperature of Y axis MPPT, °C
'eps_temp_2' / construct.Int8sb, # S, 1, Temperature of EPS board, °C
'eps_temp_3' / construct.Int8sb, # S, 1, Temperature of battery pack #1, °C
'eps_temp_4' / construct.Int8sb, # S, 1, Temperature of battery pack #2, °C
'eps_temp_5' / construct.Int8sb, # S, 1, Temperature of battery pack #3, °C
'eps_cursun' / construct.Int16ub, # U, 2, Total current from the solar panels, mA
'eps_cursys' / construct.Int16ub, # U, 2, Total current absorbed by the system, mA
'eps_vbatt' / construct.Int16ub, # U, 2, Battery voltage, mV
'eps_outputs' / construct.Hex(construct.Int8ub), # U, 1, Status of EPS outputs
'radio_temp_pa' / construct.Int8sb, # S, 1, Temperature of transceiver PA, °C
'radio_tx_count' / construct.Int16ub, # U, 2, Transceiver total TX count
'radio_rx_count' / construct.Int16ub, # U, 2, Transceiver total RX count
'radio_last_rssi' / construct.Int16sb, # S, 2, Last radio-contact RSSI, dBm
'obc_bootcounter' / construct.Int16ub, # U, 2, OBC bootcounter
'radio_bootcounter' / construct.Int16ub, # U, 2, Radio bootcounter
'eps_bootcounter' / construct.Int16ub, # U, 2, EPS bootcounter
'payload_rx_count' / construct.Int8ub, # U, 1, Packets from the payload
'payload_tx_count' / construct.Int8ub, # U, 1, Packets to the payload
'software_status' / construct.Hex(construct.Int8ub), # U, 1, Software status flag
'heater_status' / construct.Hex(construct.Int8ub), # U, 1, Heater status flag
'obc_temp_0' / construct.Int8ub, # U, 1, OBC temperature, °C
'obc_gyro_0' / val_x100, # S, 2, Gyroscope X, x100, °/s
'obc_gyro_1' / val_x100, # S, 2, Gyroscope Y, x100, °/s
'obc_gyro_2' / val_x100, # S, 2, Gyroscope Z, x100, °/s
'obc_mag_0' / val_x10, # S, 2, Magnetometer X, x10, mG
'obc_mag_1' / val_x10, # S, 2, Magnetometer Y, x10, mG
'obc_mag_2' / val_x10, # S, 2, Magnetometer Z, x10, mG
'pan_spt_0' / construct.Int8sb, # S, 1, Temperature of +X solar panel, °C
'pan_spt_1' / construct.Int8sb, # S, 1, Temperature of +Y solar panel, °C
'pan_spt_2' / construct.Int8sb, # S, 1, Temperature of -X solar panel, °C
'pan_spt_3' / construct.Int8sb, # S, 1, Temperature of -Y solar panel, °C
'pan_css_0' / construct.Int16ub, # U, 2, Coarse Sun sensor +X, mV
'pan_css_1' / construct.Int16ub, # U, 2, Coarse Sun sensor +Y, mV
'pan_css_2' / construct.Int16ub, # U, 2, Coarse Sun sensor +Z, mV
'pan_css_3' / construct.Int16ub, # U, 2, Coarse Sun sensor -X, mV
'gps_status_flag' / construct.Hex(construct.Int8ub), # U, 1, GPS status flag
'gps_fix_time' / construct.Int32ub, # U, 4, GPS fix time
'gps_lat' / val_x1000000, # I, 4, GPS Latitude, x1000000
'gps_lon' / val_x1000000, # I, 4, GPS Longitude, x1000000
'gps_alt' / val_x1000000, # I, 4, GPS Altitude, x1000000, km
'sband_tx_cnt' / construct.Int16ub, # U, 2, S-Band TX Count
'antenna_status' / construct.Hex(construct.Int16ub), # U, 2, Antenna status flag
'acs_state' / construct.Hex(construct.Int8ub), # U, 1, ACS state flag
'acs_param' / construct.Hex(construct.Int8ub), # U, 1, ACS parameters flag
)

greencube_msg = construct.Struct(
'_name' / construct.Computed('greencube_msg'),
'name' / construct.Computed('Message'),

'msg' / construct.GreedyString('utf-8'),
)

GREENCUBE_NAMED_ID = 0x1D03
ids_map = {
GREENCUBE_NAMED_ID: greencube_msg,
}

greencube_default_packet = construct.Struct(
'_name' / construct.Computed('greencube_default_packet'),

'id' / construct.Hex(construct.Int16ub),
'data' / construct.Switch(construct.this.id, ids_map, default=construct.GreedyBytes),
)

GREENCUBE_TLM_DPORT = 8
packets_map = {
GREENCUBE_TLM_DPORT: greencube_tlm,
}

greencube = construct.Struct(
'packet' / construct.Switch(construct.this._params.csp_hdr.dest_port, packets_map, default=greencube_default_packet),
)


class GreenCubeProtocol(common.Protocol):
NAME = 'GreenCube'
columns = 'from', 'to', 'id'
c_width = 40, 40, 40

tlm_table = {
'greencube_tlm': {
'table': (
('name', 'Name'),
('id', 'Telemetry Identifier'),
('time_ms', 'Millisecond part of the unix time, ms'),
('Time', 'On-board unix time'),
('proctime', 'Time taken to process the telemetry, ms'),
('eps_vboost_0', 'Voltage of X axis solar panels, mV'),
('eps_vboost_1', 'Voltage of Y axis solar panels, mV'),
('eps_cboost_0', 'Current of X axis solar panels, mA'),
('eps_cboost_1', 'Current of Y axis solar panels, mA'),
('eps_bootcause', 'EPS bootcause'),
('eps_temp_0', 'Temperature of X axis MPPT, °C'),
('eps_temp_1', 'Temperature of Y axis MPPT, °C'),
('eps_temp_2', 'Temperature of EPS board, °C'),
('eps_temp_3', 'Temperature of battery pack #1, °C'),
('eps_temp_4', 'Temperature of battery pack #2, °C'),
('eps_temp_5', 'Temperature of battery pack #3, °C'),
('eps_cursun', 'Total current from the solar panels, mA'),
('eps_cursys', 'Total current absorbed by the system, mA'),
('eps_vbatt', 'Battery voltage, mV'),
('eps_outputs', 'Status of EPS outputs'),
('radio_temp_pa', 'Temperature of transceiver PA, °C'),
('radio_tx_count', 'Transceiver total TX count'),
('radio_rx_count', 'Transceiver total RX count'),
('radio_last_rssi', 'Last radio-contact RSSI, dBm'),
('obc_bootcounter', 'OBC bootcounter'),
('radio_bootcounter', 'Radio bootcounter'),
('eps_bootcounter', 'EPS bootcounter'),
('payload_rx_count', 'Packets from the payload'),
('payload_tx_count', 'Packets to the payload'),
('software_status', 'Software status flag'),
('heater_status', 'Heater status flag'),
('obc_temp_0', 'OBC temperature, °C'),
('obc_gyro_0', 'Gyroscope X, °/s'),
('obc_gyro_1', 'Gyroscope Y, °/s'),
('obc_gyro_2', 'Gyroscope Z, °/s'),
('obc_mag_0', 'Magnetometer X, mG'),
('obc_mag_1', 'Magnetometer Y, mG'),
('obc_mag_2', 'Magnetometer Z, mG'),
('pan_spt_0', 'Temperature of +X solar panel, °C'),
('pan_spt_1', 'Temperature of +Y solar panel, °C'),
('pan_spt_2', 'Temperature of -X solar panel, °C'),
('pan_spt_3', 'Temperature of -Y solar panel, °C'),
('pan_css_0', 'Coarse Sun sensor +X, mV'),
('pan_css_1', 'Coarse Sun sensor +Y, mV'),
('pan_css_2', 'Coarse Sun sensor +Z, mV'),
('pan_css_3', 'Coarse Sun sensor -X, mV'),
('gps_status_flag', 'GPS status flag'),
('gps_fix_time', 'GPS fix time'),
('gps_lat', 'GPS Latitude'),
('gps_lon', 'GPS Longitude'),
('gps_alt', 'GPS Altitude, km'),
('sband_tx_cnt', 'S-Band TX Count'),
('antenna_status', 'Antenna status flag'),
('acs_state', 'ACS state flag'),
('acs_param', 'ACS parameters flag'),
),
},
'greencube_msg': {
'table': (
('name', 'Name'),
('msg', 'Message'),
),
},
'greencube_default_packet': {
'table': (
('id', 'ID'),
('data', 'Data'),
),
},
}

def recognize(self, bb):
csp_packet = csp.csp.parse(bb)
raw_greencube = csp_packet.data
if not (csp_packet.hdr and raw_greencube):
return

csp_packet.data = s = greencube.parse(raw_greencube, csp_hdr=csp_packet.hdr)
args = [
'raw',
self.NAME,
f'{csp_packet.hdr.src}-{csp_packet.hdr.src_port}',
f'{csp_packet.hdr.dest}-{csp_packet.hdr.dest_port}',
hasattr(s.packet, 'id') and f'{s.packet.id:02X}' or None,
raw_greencube,
]

if csp_packet.hdr.dest_port in packets_map:
args[0] = 'tlm'
args[-1] = csp_packet, s.packet
yield tuple(args)

elif s.packet.id in ids_map:
args[0] = 'tlm'
args[-1] = csp_packet, s.packet.data
yield tuple(args)

else:
yield tuple(args)
10 changes: 8 additions & 2 deletions SatsDecoder/systems/wtc_simba.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
'_name' / construct.Computed('simba_tlm'),
'name' / construct.Computed('Telemetry'),

'tid' / construct.Hex(construct.Int16ub), # 2, Telemetry Identifier
'id' / construct.Hex(construct.Int16ub), # 2, Telemetry Identifier
'time_ms' / construct.Int16ub, # 2, Millisecond part of the unix time, ms
'Time' / common.UNIXTimestampAdapter(construct.Int32ub), # 4, On-board unix time, s
'proceed_ms' / construct.Int16ub, # 2, Time taken to process the telemetry, ms
Expand Down Expand Up @@ -204,7 +204,7 @@ class WtcSimbaProtocol(common.Protocol):
'simba_tlm': {
'table': (
('name', 'Name'),
('tid', 'Telemetry Identifier'),
('id', 'Telemetry Identifier'),
('time_ms', 'Millisecond part of the unix time, ms'),
('Time', 'On-board unix time, s'),
('proceed_ms', 'Time taken to process the telemetry, ms'),
Expand Down Expand Up @@ -272,6 +272,12 @@ class WtcSimbaProtocol(common.Protocol):
('val', 'Value'),
),
},
'default_packet': {
'table': (
('id', 'ID'),
('data', 'Data'),
),
},
}

def __init__(self, outdir):
Expand Down

0 comments on commit 979dba7

Please sign in to comment.