Skip to content

Commit

Permalink
feat: partial support for mt related commands AB#117
Browse files Browse the repository at this point in the history
  • Loading branch information
brendon-stephens committed Oct 12, 2022
1 parent 9f538ca commit b71ec40
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 34 deletions.
117 changes: 88 additions & 29 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import { TypedEmitter } from 'tiny-typed-emitter'
import { ReadlineParser } from '@serialport/parser-readline'
import { InterByteTimeoutParser } from '@serialport/parser-inter-byte-timeout'

import { delay, randomInterval } from './utils'
import { calculateChecksum, delay, randomInterval, trimBuffer } from './utils'

const MILLISECOND = 1
const SECOND = MILLISECOND * 1000
Expand Down Expand Up @@ -168,12 +168,19 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
}

/** The current buffer for Mobile Terminated (MT) messages */
#mtBuffer: string
#mtBuffer: Buffer

get mtBuffer () {
return this.#mtBuffer
}

/** The remote queue of Mobile Terminated (MT) messages */
#mtQueue: Buffer[]

get mtQueue () {
return this.#mtQueue
}

/* The sequence number for Mobile Terminated (MT) messages */
#mtSequenceNo = 0

Expand Down Expand Up @@ -292,8 +299,9 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {

this.#port.pipe(this.#readlineParser)

this.#mtQueue = []
this.#moBuffer = Buffer.alloc(340)
this.#mtBuffer = '' // TODO: COnvert to buffer
this.#mtBuffer = Buffer.alloc(270)
this.#binaryBuffer = null
this.#binaryBufferLength = 0
this.#binaryBufferTimeout = null
Expand Down Expand Up @@ -373,6 +381,13 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
}
}

#writeBinary (data: Buffer): void {
this.#logger.info(`>> ${data.toString('hex')}`)
if (!this.quietMode) {
this.#port.write(data)
}
}

#toggleBinaryMode = (binaryBufferLength?: number): void => {
if (this.#binaryBufferTimeout !== null) clearTimeout(this.#binaryBufferTimeout)

Expand Down Expand Up @@ -417,19 +432,7 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
const buffer = this.#binaryBuffer.subarray(0, this.#binaryBuffer.length - 2)
const checksum = this.#binaryBuffer.subarray(this.#binaryBuffer.length - 2, this.#binaryBuffer.length)

let sum = 0
for (let i = 0; i < buffer.length; i++) sum += buffer[i]

const calculatedChecksum = Buffer.alloc(2)

// set the least significant byte of the message summation
calculatedChecksum[1] = sum & 0xff

// drop the least significant byte
sum >>= 8

// set the (second) least significant byte of the message summation
calculatedChecksum[0] = sum & 0xff
const calculatedChecksum = calculateChecksum(buffer)

this.#logger.debug(`Client provided checksum was '${checksum.toString('hex')}', calculated checksum was '${calculatedChecksum.toString('hex')}'`)

Expand Down Expand Up @@ -716,7 +719,7 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {

/** Ring Indication Status */
case 'AT+CRIS':
this.#write(`+CRIS:${this.ringAlertActive ? '1' : '0'}`)
this.#write(`+CRIS:000,${this.ringAlertActive ? '001' : '000'}`)
this.#write('OK')
break

Expand Down Expand Up @@ -752,17 +755,39 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
break

/** Short Burst Data: Write a Text Message to the Module */
// TODO: Note only supports the "AT+SBDWT=<text message>" form.
case 'AT+SBDWT=':
// TODO: Support for this command
if (detail.length > 340) {
this.#logger.warn('SBD message size is not correct. The maximum mobile originated SBD message length is 340 bytes.')
this.#write('ERROR')
break
}

this.#moBuffer = Buffer.from(detail)
this.#write('OK')

break

/** Short Burst Data: Read a Text Message from the Module */
case 'AT+SBDRT':
this.#write('+SBDRT:')
this.#write(this.#mtBuffer)
this.#write(this.#mtBuffer.toString())
this.#write('OK')
break

/** Short Burst Data: Read Binary Data from the Module */
case 'AT+SBDRB': {
const buffer = trimBuffer(this.mtBuffer)
const checksum = calculateChecksum(buffer)

const length = Buffer.alloc(2)
length.writeUInt16BE(buffer.length)

this.#writeBinary(Buffer.concat([length, buffer, checksum]))
// this.#write(`${length}${buffer.toString('hex')}${checksum.toString('hex')}`)
break
}

/** Short Burst Data: Write Binary Data to the ISU */
case 'AT+SBDWB=': {
let length = 0
Expand Down Expand Up @@ -818,17 +843,12 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
rbDateFormat = rbDateFormat
.substring(0, rbDateFormat.length - 4) // drop milliseconds

let index = 0
for (let i = this.moBuffer.length - 1; i >= 0; i--) {
if (this.moBuffer[i] === 0x00) continue
index = i
break
}
const trimmedBuffer = trimBuffer(this.#moBuffer)

this.#logger.debug('Emitting sbd-message event with message details')
const claims = {
momsn: this.#moSequenceNo,
data: this.moBuffer.slice(0, index + 1).toString('hex'),
data: trimmedBuffer.toString('hex'),
serial: 206899,
iridium_latitude: 50.2563,
iridium_longitude: 82.2532,
Expand All @@ -855,7 +875,25 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
})
}

this.#write(`+SBDIX: ${success ? 0 : 32}, ${this.#moSequenceNo}, ${success ? 0 : 2}, ${this.#mtSequenceNo}, 0, 0`)
let mtStatus = success ? 0 : 2
let mtLength = 0
if (success && this.mtQueue.length > 0) {
this.#logger.debug('Moving the next available MT message from the queue into the buffer')
this.#mtBuffer = this.mtQueue.pop()
this.#mtSequenceNo++

const trimmedMtBuffer = trimBuffer(this.mtBuffer)

mtStatus = 1
mtLength = trimmedMtBuffer.length
}

if (success) {
// TODO: Need to confirm with specification when this is disabled.
this.#ringAlertActive = false
}

this.#write(`+SBDIX: ${success ? 0 : 32}, ${this.#moSequenceNo}, ${mtStatus}, ${this.#mtSequenceNo}, ${mtLength}, ${this.mtQueue.length}`)
this.#write('OK')

break
Expand Down Expand Up @@ -903,12 +941,12 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
this.#write('OK')
break
case 'AT+SBDD1':
this.#mtBuffer = ''
this.#mtBuffer.fill(0)
this.#write('OK')
break
case 'AT+SBDD2':
this.#moBuffer.fill(0)
this.#mtBuffer = ''
this.#mtBuffer.fill(0)
this.#write('OK')
break

Expand Down Expand Up @@ -982,4 +1020,25 @@ export class IridiumEmulator extends TypedEmitter<IridiumEmulatorInterface> {
_this.#updateSignalQuality()
}, waitTime)
}

/**
* Adds message to the "remote" MT queue. Simulating the
* Iridium ground station.
*/
addRemoteMTMessage = (buffer: Buffer): void => {
if (!buffer || buffer.length > 270) {
throw RangeError(`Expected buffer length to be <= 270 but was ${buffer.length ?? 0}`)
}

this.mtQueue.push(buffer)

this.#logger.debug(`New message added to MT queue. Current queue length is ${this.mtQueue.length}`)

if (this.#ringAlertsEnabled && !this.#ringAlertActive) {
this.#logger.debug('Actived ring alert')

this.#ringAlertActive = true
this.#write('SBDRING')
}
}
}
55 changes: 50 additions & 5 deletions src/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import usx from 'unishox2.siara.cc'
* @param str
* @returns {Buffer} the compress string as binary
*/
function compress (str: string) {
export function compress (str: string) {
const uint8arr = new Uint8Array(str.length + 10)
const length = usx.unishox2_compress_simple(str, str.length, uint8arr)
return Buffer.from(uint8arr.subarray(0, length))
Expand All @@ -18,12 +18,57 @@ function compress (str: string) {
* @param buffer
* @returns {string} the decompressed string
*/
function decompress (buffer: Buffer) {
export function decompress (buffer: Buffer) {
return usx.unishox2_decompress_simple(buffer, buffer.length)
}

const delay = (ms: number) => new Promise(resolve => setTimeout(resolve, ms))
/**
* Calculates the least significant 2-bytes of the
* summation of the entire buffer/message.
*
* @param buffer
*/
export function calculateChecksum (buffer: Buffer) {
const checksum = Buffer.alloc(2)

let sum = 0
for (let i = 0; i < buffer.length; i++) {
sum += buffer[i]
}

// set the least significant byte of the message summation
checksum[1] = sum & 0xff

// drop the least significant byte
sum >>= 8

// set the (second) least significant byte of the message summation
checksum[0] = sum & 0xff

return checksum
}

/**
* Cuts padding 0's from the input buffer.
*
* @param buffer
* @returns {Buffer}
*/
export function trimBuffer (buffer: Buffer) {
let index = 0
for (let i = buffer.length - 1; i >= 0; i--) {
if (buffer[i] === 0x00) continue
index = i
break
}

const randomInterval = (min: number, max: number) => Math.floor(Math.random() * (max - min + 1) + min)
return buffer.slice(0, index + 1)
}

export function delay (ms: number) {
return new Promise(resolve => setTimeout(resolve, ms))
}

export { compress, decompress, delay, randomInterval }
export function randomInterval (min: number, max: number) {
return Math.floor(Math.random() * (max - min + 1) + min)
}

0 comments on commit b71ec40

Please sign in to comment.