-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
0 parents
commit 6e40cba
Showing
23 changed files
with
3,840 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
node_modules | ||
faker_satellite/file_lib/**.* | ||
faker_satellite/for_downlink/**.* | ||
run/downlinked_files/for_downlink/**.* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
# Demo Gateway in NodeJS | ||
A Gateway is the translation layer between Major Tom's Mission Control and your Satellite. This repo contains an example Gateway in JavaScript, and can be run locally. | ||
|
||
## Background | ||
Gateways are asynchronous by nature -- the primary interface is a bi-directional websocket. Actions taken by the operator are sent from Major Tom to your Gateway as messages. The underlying library then executes methods based on the type of message. NodeJS is uniquely suited to handle a Gateway's asynchronous behavior using its trademark Event and Stream paradigms. | ||
|
||
## Gateway Package | ||
This demo gateway uses the [Major Tom Gateway Package](https://npmjs.com/package/majortom-gateway) from npm. If you are looking to use this gateway as an example to write your own, you'll use that package to handle messages to and from Major Tom. | ||
|
||
|
||
## Local Setup | ||
1. Make sure you have git and [NodeJS & npm](https://nodejs.org) installed | ||
2. Clone this repo with git | ||
3. In a terminal window, navigate into the demo folder and install the project dependencies from npm | ||
```sh | ||
$ cd mt-demo-js | ||
$ npm install | ||
``` | ||
|
||
## Major Tom Setup | ||
Before running this app locally, you'll need to make a Gateway in Major Tom! Once you've received your login credentials for Major Tom, make a new mission, and you'll be prompted to add a Gateway to that mission. | ||
|
||
Once you add the Gateway, you'll need the **Authentication Token** to connect the demo gateway. You can find it on the Gateway Page: | ||
 | ||
|
||
## Connect the Gateway | ||
1. You'll need to edit the file found at `mt-demo-js/connect/connection.json` in the following way: | ||
```json | ||
{ | ||
"gatewayToken": "<YOUR-GATEWAY-TOKEN>", | ||
"host": "app.majortom.cloud" // Or your Major Tom url host location | ||
} | ||
``` | ||
2. From a terminal window in the `mt-demo-js` directory, start the app using the start script: | ||
```sh | ||
$ npm run start | ||
``` | ||
3. You should see the intro text in the window, and then a JSON message from Major Tom: | ||
```sh | ||
{"type":"hello","hello":{"mission":"YOUR-MISSION-NAME"}} | ||
``` | ||
4. You'll also see a log message showing that the example sat has sent Major Tom a copy of its command definitions. This will serve to automatically create the satellite in Major Tom if it doesn't exist yet, and set it up with the commands it recognizes. | ||
|
||
### Note on Major Tom Deployment Environments | ||
If you have Basic Authentication enabled on your deployment (usually true if you're accessing it over anything other than `app.majortom.cloud`), you'll need to enter those credentials in `mt-demo-js/connect/connection.json` to connect. | ||
|
||
Enter basicauth login credentials for your Major Tom deployment (if it’s active) in the form `"basicAuth": "<username>:<password>@"`, for example: `"basicAuth": "kubos:password123@"`. | ||
|
||
If you are running the on-prem version of Major Tom, you'll need to include the field `"http": true` in `mt-demo-js/connect/connection.json`, as we currently do not support https for on prem. | ||
|
||
## What does this Demo do? | ||
Now that you've connected the gateway, it will automatically create a new satellite (as noted above) and load command definitions for it. | ||
|
||
You can now issue those commands to the satellite through the connected Gateway, which accomplish a wide variety of simulated tasks. Open each command and read its description to understand what it does! | ||
|
||
To find these commands, go to Major Tom under the mission you originally created and look up JS Oddity in the Satellites Menu: | ||
|
||
 | ||
|
||
Clicking on it will take you to its commanding page, and you can fire away! | ||
|
||
## What's next? | ||
### Set up your Mission Dashboard | ||
The Mission Dashboard allows you to monitor and control everything on the Mission. Add cards and play with their settings to see what you can do! | ||
|
||
### Integrate Your System | ||
Now that you understand how the integration works, try augmenting the Demo Gateway to actually communicate with your hardware and software! Then you can begin controlling and monitoring your own spacecraft. If you want to get a better sense of how easy it is to build a Gateway in NodeJS, start by looking at the source code in `mt-demo-js/index.js`! |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
{ | ||
"type": "command_definitions_update", | ||
"command_definitions": { | ||
"system": "JS Oddity", | ||
"definitions": { | ||
"ping": { | ||
"display_name": "1-ping", | ||
"description": "A simple ping. The Gateway should contact the satellite to return a pong.", | ||
"fields": [] | ||
}, | ||
"telemetry": { | ||
"display_name": "2-start telemetry beacon", | ||
"description": "Commands the spacecraft to beacon Health and Status Telemetry for 3 minutes. After executing this command, you can see the telemetry by navigating to the System Telemetry tab or the Analytics Page.", | ||
"fields": [] | ||
}, | ||
"update_file_list": { | ||
"display_name": "3-update file list", | ||
"description": "Gets the latest list of downloadable files from the spacecraft.", | ||
"fields": [] | ||
}, | ||
"uplink_file": { | ||
"display_name": "4-uplink file", | ||
"description": "Uplink a file from your computer to the spacecraft.", | ||
"fields": [ | ||
{ "name": "gateway_download_path", "type": "string" } | ||
] | ||
}, | ||
"downlink_file": { | ||
"display_name": "5-downlink file", | ||
"description": "Downlink an image from the Spacecraft.", | ||
"fields": [ | ||
{ "name": "filename", "type": "string" } | ||
] | ||
}, | ||
"connect": { | ||
"display_name": "6-establish rf lock", | ||
"description": "Points antennas and starts broadcasting carrier signal to establish RF lock with the spacecraft.", | ||
"fields": [] | ||
}, | ||
"safemode": { | ||
"display_name": "7-safemode command", | ||
"description": "Commands the spacecraft into safemode for 3 minutes, shutting down telemetry and all non-essential systems.", | ||
"fields": [] | ||
} | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
{ | ||
"gatewayToken": "", | ||
"host": "app.majortom.cloud" | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
const broadcastCarrierSignal = ({ updateFn }) => new Promise((resolve) => { | ||
const AWAITING_ACK = 'awaiting satellite ack'; | ||
const statusPhases = [ | ||
'checking for sideband traffic', | ||
'broadcasting callsign and net clear', | ||
'initiating carrier frequency', | ||
AWAITING_ACK, | ||
]; | ||
const maxWait = 6000; | ||
const intervalWait = 1000; | ||
let waited = 0; | ||
let idx = 0; | ||
|
||
const bcastInt = setInterval(() => { | ||
if (waited >= maxWait) { | ||
clearInterval(bcastInt); | ||
updateFn(100, 'awaiting satellite ack'); | ||
resolve(); | ||
} else { | ||
updateFn((idx + 1) * 10, statusPhases[idx] || AWAITING_ACK); | ||
idx += 1; | ||
waited += intervalWait; | ||
} | ||
}, intervalWait); | ||
}); | ||
|
||
module.exports = broadcastCarrierSignal; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
const getRandomInt = require("./utils/getRandomInt"); | ||
|
||
const orientAntenna = ({ updateFn }) => new Promise((resolve) => { | ||
const totalToRotate = getRandomInt(0, 268); | ||
let done = 0; | ||
|
||
const rotInterval = setInterval(() => { | ||
if (done >= totalToRotate) { | ||
clearInterval(rotInterval); | ||
updateFn(totalToRotate, 0); | ||
resolve(); | ||
} else { | ||
done += 3; | ||
updateFn(done, totalToRotate - done); | ||
} | ||
}, 200); | ||
}); | ||
|
||
module.exports = orientAntenna; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
/** | ||
* @callback UpdateFunction | ||
* @param {Number} percentComplete The percentage of the task that is completed | ||
* @param {String} phaseLabel A string identifying the phase of the task | ||
* @returns | ||
*/ | ||
|
||
/** | ||
* | ||
* @param {Object} param0 params | ||
* @param {UpdateFunction} param0.updateFn Will be called as the task updates | ||
* @returns {Promise} | ||
*/ | ||
const prepGroundHardware = ({ updateFn }) => new Promise((resolve, reject) => { | ||
const statusPhases = [ | ||
'actuator power cycle', | ||
'gimballing hardware', | ||
'hardware clearance check', | ||
'radio power cycle', | ||
'digesting tle', | ||
'computing pass angles', | ||
'translating pass trajectory', | ||
'calibrating radio oscillator', | ||
'refining radio frequency', | ||
'finishing pass prep', | ||
]; | ||
let i = 0; | ||
|
||
const calcInterval = setInterval(() => { | ||
if (i >= statusPhases.length) { | ||
clearInterval(calcInterval); | ||
updateFn(100, 'done'); | ||
resolve(); | ||
} else { | ||
updateFn(Math.floor((i / (statusPhases.length - 1)) * 100) , statusPhases[i]); | ||
i += 1; | ||
} | ||
}, 1700); | ||
}); | ||
|
||
module.exports = prepGroundHardware; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
const syncCarrierSignalWithSat = ({ updateFn, satellite }) => new Promise((resolve, reject) => { | ||
const maxAttempts = 10; | ||
const checksumWords = [ | ||
'ALBUM', | ||
'BANTU', | ||
'COMET', | ||
'DOETH', | ||
'EARTH', | ||
'FORCE', | ||
'GALAX', | ||
'HEXAD', | ||
'INGOT', | ||
'JUMBO', | ||
]; | ||
let didReceiveAck = false; | ||
let attempts = 0; | ||
let pingInterval; | ||
let checkWord; | ||
|
||
const carrierPingListener = ({ type, word }) => { | ||
if (!didReceiveAck) { | ||
updateFn('acked_by_system'); | ||
didReceiveAck = true; | ||
} | ||
|
||
if (type === 'checksum_pong') { | ||
updateFn('downlinking_from_system', attempts, maxAttempts); | ||
|
||
if (word === checkWord) { | ||
clearInterval(pingInterval); | ||
satellite.off('message', carrierPingListener); | ||
resolve(`${word}${checkWord}`); | ||
} | ||
} | ||
}; | ||
|
||
updateFn('uplinking_to_system'); | ||
checkWord = checksumWords[attempts]; | ||
attempts += 1; | ||
satellite.on('message', carrierPingListener); | ||
satellite.send({ type: 'checksum_ping', word: checkWord }); | ||
updateFn('transmitted_to_system'); | ||
|
||
pingInterval = setInterval(() => { | ||
if (attempts >= maxAttempts) { | ||
clearInterval(pingInterval); | ||
satellite.off('message', carrierPingListener); | ||
|
||
reject(new Error( | ||
didReceiveAck | ||
? 'Contact made with satellite but could not sync carriers' | ||
: `No contact with satellite after ${maxAttempts} seconds` | ||
)); | ||
} else { | ||
checkWord = checksumWords[attempts]; | ||
attempts += 1; | ||
satellite.send({ type: 'checksum_ping', word: checkWord }); | ||
} | ||
}, 1000); | ||
}); | ||
|
||
module.exports = syncCarrierSignalWithSat; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
module.exports = (min, max) => { | ||
min = Math.ceil(min); | ||
max = Math.floor(max); | ||
|
||
return Math.floor(Math.random() * (max - min + 1) + min); | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,9 @@ | ||
const validateChecksum = ({ updateFn }) => new Promise(resolve => { | ||
updateFn('calculating checksum'); | ||
setTimeout(() => { | ||
updateFn('resolved check value'); | ||
resolve(`VALID::${(Math.random() * Date.now()).toFixed(4)}`); | ||
}, 1500); | ||
}); | ||
|
||
module.exports = validateChecksum; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
This is a test | ||
of the file uplink system | ||
-- Sincerely, Dmitry |
Oops, something went wrong.