Home Reference Source Repository

src/icarus/station.js

import {EventEmitter} from 'events'

import Serial, {listPorts} from '../serial'
import getDB from '../lib/db'
import createLogger from '../lib/log'
import Backend from './backend'
import Classifier from './classifier'
import {parser, dataHandler} from './data-handler'

// T-Minus Transceiver information
/**
 * T-Minus Transceiver Vendor ID
 * @const
 */
const tMinusVid = '0x03eb'

/**
 * T-Minus Transceiver Product ID
 * @const
 */
const tMinusPid = '0x2404'

/**
 * Handles everything a Station should.
 * Brings Serial, data parsing, database saving and the backend connection together.
 */
export default class Station extends EventEmitter {
	/**
	 * Sets up all relevant class instances (Serial, parsers...) and events listeners.
	 * @param {String} name Station name.
	 */
	constructor(name) {
		super()

		/**
		 * Name/ID of the station
		 * @type {String}
		 */
		this.name = name

		/**
		 * Database instance, internal to the station.
		 * @type {PouchDB}
		 */
		this.db = getDB(`data-${name}`)

		/**
		 * Log database instance, internal to the station.
		 * @type {PouchDB}
		 */
		this.logDB = getDB(`log-${name}`)

		/**
		 * Logger instance.
		 * @type {Bunyan}
		 */
		this._log = createLogger(this.name, this.logDB)

		/**
		 * {@link Serial} instance with the {@link parser} attached.
		 * @type {Serial}
		 */
		this.serial = new Serial(this._log.child({childId: 'serial'}), parser())

		/**
		 * {@link Classifier} instance.
		 * @type {Classifier}
		 */
		this.classifier = new Classifier(this._log.child({childId: 'classifier'}))

		/**
		 * {@link Backend} connector instance.
		 * @type {Backend}
		 */
		this.backend = new Backend(
			this.name,
			this._log.child({childId: 'backendLink'}),
			this.db,
			this.logDB
		)

		// Handle incoming packets
		this.serial.on('data', this::dataHandler)

		// The transceiver needs a bit of a kick sometimes
		this.serial.on('stateChange', state => {
			if (state === 'open') {
				// Send something!
				this.serial._port.write('hi there')
			}
		})

		this._log.info('station.construct end')
	}

	/**
	 * Returns a list of available serialports and tries to find which ones
	 * are the T-Minus transceiver (sets [portInfo].recommend to true) and sorts
	 * them with recommended ones first.
	 * @return {Promise<Array>} List of serialports.
	 */
	getAvailablePorts() {
		this._log.info('station.getAvailablePorts')
		return listPorts()
			.then(list => {
				list = list.map(port => {
					if (port.vendorId === tMinusVid && port.productId === tMinusPid) {
						port.recommend = true
					}
					return port
				})

				list = list.sort((p1, p2) => {
					// Recommended come first
					if (p1.recommend && !p2.recommend) {
						return -1
					}
					if (p2.recommend && !p1.recommend) {
						return 1
					}

					// Otherwise, default to alphabetical sorting
					return p1.comName.localeCompare(p2.comName)
				})

				this._log.debug('Available ports', {ports: list})
				return list
			})
	}

	/**
	 * Cleanup function to be run before exiting.
	 * Closes the serialport and runs {@link Backend#cleanup}.
	 * @return {Promise} Promise that completes when all is clean.
	 */
	cleanup() {
		this._log.info('station.cleanup')
		return this.serial.close()
			.then(this.backend.cleanup())
	}
}