COSMOS - UWCubeSat/DubSat1 GitHub Wiki
Dubsat1 and COSMOS
Dubsat1 uses COSMOS to monitor backchannel telemetry, run tests, and read CAN packets. This shows how to read and write backchannel telemetry as well as process commands.
This does not cover how to read CAN packets with COSMOS or how to write test scripts.
Prerequisites
- Ability to deploy code to a MSP430
- Code Composer Studio
- MSP430 compiler
Installation
First install COSMOS.
Install Ruby version 2.4.6-1 (Only versions prior to 2.5 work with the libraries in DS1Ops). The 'Ruby' file from this installation then needs to replace the 'Ruby' file in the COSMOS installation. The Path needs to be edited from the original installation location to the new location at COSMOS\Vendor\Ruby\bin
Clone DS1Ops, our repo for DubSat1 integration and operations.
At the command line, navigate to our project at DS1Ops/COSMOS/flatsat
and use bundle install
to ensure you have everything you need to run our COSMOS configuration. This may first require installing bundler (gem install bundler
) or adding COSMOS to your environment variables.
Connecting to HS1 Groundstation
To connect to the current network, first connect to the Lab's network (ask someone in the lab for the password) and start the launcher in DS1Ops/COSMOS/flatsat
Open the Telemetry and Command Server tab and COSMOS should connect to the network
Reading telemetry
This section describes how to read backchannel telemetry from a demo target called TEMPLATE, but should work with any module that already has COSMOS integration.
Git checkout the "template" branch of the DS1Ops repository.
Connect a MSP430 launchpad to your computer. COSMOS will need to know what COM port the MSP430 uses. On Windows, use Device Manager to find the MSP430's Application COM port. Then, open the target's command and telemetry server configuration file, DS1Ops/COSMOS/flatsat/config/targets/TEMPLATE/cmd_tlm_server.txt
, and update the two instances of COM##
to the port you found.
Also find the system config file at DS1Ops\COSMOS\flatsat\config\system
and edit the file to only declare TEMPLATE and SYSTEM as targets by replacing AUTO_DECLARE_TARGETS
with DECLARE_TARGET TEMPLATE
and DECLARE_TARGET SYSTEM
.
Deploy and run the project Dubsat1/src/devmods/cosmos_client_test2
to the launchpad. It should start producing telemetry which you can confirm by observing the serial traffic using a tool like PuTTY, though you would only see binary data.
Run COSMOS using ruby Launcher
(or Launcher.bat
on Windows) from the project directory. Select "OK" and click "Command and Telemetry Server". If your cmd_tlm_server.txt
file is correct and the launchpad is connected, the TEMPLATE_INT interface should read "connected". Press the "Cancel Connect" button on the other interfaces so they stop producing error messages.
Select the "Tlm Packets" tab to verify packets are coming in. Click the "View in Packet Viewer" button on TEMPLATE's HEALTH packet to look at the internal temperature of the MSP430, labeled INTTEMP.
Creating a new target
Each MSP430 on the satellite will have both a corresponding module under ssmods
in our Dubsat1 repo and a target in our DS1Ops repo. A target is required to send telemetry and process commands.
First check if your module's target already exists in DS1Ops/COSMOS/flatsat/config/targets
. If not, copy and paste the "TEMPLATE" folder and rename it to have the module's name (as it appears in the ssmods
folder). Then, do a find-and-replace from "TEMPLATE" to the module's name for every file in the folder (and its sub-folders). In cmd_tlm/shared_cmd.txt
, change expmod
from 0 to the module ID as it appears in systeminfo.h
.
You should now be able to launch COSMOS again and see your target in the list of interfaces.
Adding telemetry
Telemetry is separated into segments of related data. Each segment has an ID which is unique to the target. Valid IDs range from 2 to 127, inclusive (IDs 0, 1, and 128 are reserved). Create and maintain a list of telemetry IDs for each segment in your module.
Sending in C
Create a telemetry segment by defining a C struct with a BcTlmHeader followed by the data fields to send. For example:
#include "core/utils.h"
TLM_SEGMENT {
BcTlmHeader header; // All COSMOS TLM packets must have this
float alpha;
float beta;
uint8_t status;
} my_telem;
The header is used to give COSMOS some metadata about the packet, like the ID. Populate the header once before sending using bcbinPopulateHeader(BcTlmHeader *header, uint8_t opcode, uint8_t fulllen)
:
my_telem myTelemSeg;
bcbinPopulateHeader(&myTelemSeg.header, TLM_ID_MY_TELEM, sizeof(myTelemSeg));
Finally, set the fields of the telemetry segment and send it over the backchannel using bcbinSendPacket(uint8_t * buff, uint8_t szBuff)
:
// set your data
myTelemSeg.alpha = 123.0;
myTelemSeg.beta = 456.0;
myTelemSeg.status = MY_TELEM_STATUS_ENABLED;
// send the segment
bcbinSendPacket((uint8_t *) &myTelemSeg, sizeof(myTelemSeg));
Parsing with COSMOS
Now that you're sending telemetry, COSMOS must be configured to parse it.
Edit cmd_tlm/ss_tlm.txt
using COSMOS' "Config Editor" utility or your favorite text editor. Follow COSMOS' guide and detailed documentation to add the telemetry configuration, not including the header field of the C struct. Then add <%= render "../../SYSTEM/cmd_tlm/_shared_tlm_header.txt", locals: {id: 2} %>
to the top of the telemetry segment, replacing 2
with its telemetry ID. COSMOS will replace this line with contents of _shared_tlm_header.txt
, which includes some of the header of the C struct. Following the my_telem
example:
TELEMETRY TEMPLATE MY_TELEM BIG_ENDIAN "Sample telemetry"
# This must ALWAYS be the first entry in any telemetry packet
<%= render "../../SYSTEM/cmd_tlm/_shared_tlm_header.txt", locals: {id: 2} %>
APPEND_ITEM ALPHA 32 FLOAT "Alpha angle" LITTLE_ENDIAN
UNITS degrees deg
APPEND_ITEM BETA 32 FLOAT "Beta angle" LITTLE_ENDIAN
UNITS degrees deg
APPEND_ITEM STATUS 8 UINT "Enable/disable status" LITTLE_ENDIAN
STATE DISABLED 0
STATE ENABLED 1
You should now be able to see the new telemetry segment in the COSMOS Command and Telemetry Server.
Adding Commands
Commands have IDs called opcodes which are unique to their target. Opcodes range from 1 to 127, inclusive (0 is reserved).
COSMOS command configuration
Adding commands to COSMOS is similar to adding telemetry.
Edit ss_cmd.txt
and add a command. Prepend the command's body with <%= render "../../SYSTEM/cmd_tlm/_shared_cmd_header.txt", locals: { eid: 10, opc: 1 } %>
. Set the value of opc
to the opcode of this command but leave eid
as 10.
Here is an example from the template:
COMMAND TEMPLATE MY_CMD LITTLE_ENDIAN "Enable/disable a pretend sensor"
# This must ALWAYS be the first entry in any command packet
<%= render "../../SYSTEM/cmd_tlm/_shared_cmd_header.txt", locals: { eid: 10, opc: 1 } %>
APPEND_PARAMETER ENABLE 8 UINT 0 1 0 "Enable setting"
STATE FALSE 0
STATE TRUE 1
Processing commands in C
Now that the command can be sent from COSMOS, it must be processed in the module code.
Create a matching C struct for the command. Headers are unnecessary this time.
CMD_SEGMENT {
uint8_t enable;
} my_cmd_segment;
Make sure a debug action callback is being registered somewhere before the main loop of the module:
// register an action callback so we can take commands over the backchannel
debugRegisterEntity(My_Entity, NULL, NULL, handleDebugActionCallback);
Then handle the command in the debug action callback. The first byte of cmdstr
will be the opcode and the rest is the payload. For example:
uint8_t handleDebugActionCallback(DebugMode mode, uint8_t * cmdstr)
{
if (mode == Mode_BinaryStreaming)
{
my_cmd_segment *myCmdSegment;
uint8_t opcode = cmdstr[0];
switch(opcode)
{
case OPCODE_MY_CMD:
// cast the payload to our command segment
myCmdSegment = (my_cmd_segment *) (cmdstr + 1);
// TODO do something based on the command segment
case OPCODE_COMMONCMD:
break;
default:
break;
}
}
return 1;
}