Skip to content
This repository has been archived by the owner on Feb 3, 2021. It is now read-only.

Commit

Permalink
feat(cli): implement flash command
Browse files Browse the repository at this point in the history
  • Loading branch information
coderbyheart committed Nov 18, 2020
1 parent 26b8ec6 commit 49dffb3
Show file tree
Hide file tree
Showing 5 changed files with 1,504 additions and 51 deletions.
4 changes: 4 additions & 0 deletions cli/bifravst.ts
Expand Up @@ -23,6 +23,7 @@ import { purgeCAsCommand } from './commands/purge-cas'
import { region } from '../cdk/regions'
import { firmwareCICommand } from './commands/firmware-ci'
import { certsDir as provideCertsDir } from './jitp/certsDir'
import { flashCommand } from './commands/flash'

const iot = new Iot({
region,
Expand Down Expand Up @@ -94,6 +95,9 @@ const bifravstCLI = async ({ isCI }: { isCI: boolean }) => {
)
} else {
commands.push(
flashCommand({
certsDir,
}),
connectCommand({
endpoint,
certsDir,
Expand Down
10 changes: 9 additions & 1 deletion cli/commands/create-device-cert.ts
Expand Up @@ -47,9 +47,17 @@ export const createDeviceCertCommand = ({
chalk.greenBright('node cli connect'),
chalk.blueBright(id),
)

console.log()
console.log(
chalk.green('You can now flash the credentials to your device'),
chalk.greenBright(`node cli flash ${id}`),
chalk.blueBright(id),
)

console.log()
console.log(
chalk.gray('Use the file'),
chalk.gray('Alternatively, use the file'),
chalk.yellow(deviceFileLocations({ certsDir, deviceId: id }).json),
)
console.log(
Expand Down
154 changes: 154 additions & 0 deletions cli/commands/flash.ts
@@ -0,0 +1,154 @@
import { CommandDefinition } from './CommandDefinition'
import * as path from 'path'
import * as fs from 'fs'
import * as os from 'os'
import {
flashCredentials,
connect,
atHostHexfile,
flash,
} from '@bifravst/firmware-ci'
import { deviceFileLocations } from '../jitp/deviceFileLocations'
import { Octokit } from '@octokit/rest'
import * as chalk from 'chalk'
import * as https from 'https'
import { v4 } from 'uuid'

const defaultPort = '/dev/ttyACM0'

const getLatestFirmware = async ({
nbiot,
nodebug,
dk,
}: {
nbiot: boolean
nodebug: boolean
dk: boolean
}) => {
const octokit = new Octokit({
auth: fs
.readFileSync(
path.resolve(process.env.HOME as 'string', '.netrc'),
'utf-8',
)
.split(os.EOL)
.find((s) => s.includes('machine api.github.com'))
?.split(' ')[5],
})
const latestRelease = (
await octokit.repos.listReleases({
owner: 'bifravst',
repo: 'firmware',
per_page: 1,
})
).data[0]
const assets = (
await octokit.repos.listReleaseAssets({
owner: 'bifravst',
repo: 'firmware',
release_id: latestRelease.id,
})
).data

const hexfile = assets.find(
({ name }) =>
name.includes('.hex') &&
name.includes(dk ? 'nRF9160DK' : 'Thingy91') &&
name.includes(nbiot ? 'nbiot' : 'ltem') &&
(nodebug ? name.includes('nodebug') : !name.includes('nodebug')),
)

if (hexfile === undefined) throw new Error(`Failed to detect latest release.`)

const downloadTarget = path.join(os.tmpdir(), `${v4()}.hex`)
console.log(chalk.magenta(`Downloading`), chalk.blue(hexfile.name))

await new Promise((resolve) => {
const file = fs.createWriteStream(downloadTarget)
https.get(hexfile.browser_download_url, (response) => {
https.get(response.headers.location as string, (response) => {
response.pipe(file).on('close', resolve)
})
})
})

return downloadTarget
}

export const flashCommand = ({
certsDir,
}: {
certsDir: string
}): CommandDefinition => ({
command: 'flash <deviceId>',
options: [
{
flags: '--dk',
description: `Flash a 9160 DK`,
},
{
flags: '--nbiot',
description: `Flash NB-IoT firmware`,
},
{
flags: '--nodebug',
description: `Flash no-debug firmware`,
},
{
flags: '-p, --port <port>',
description: `The port the device is connected to, defaults to ${defaultPort}`,
},
{
flags: '-f, --firmware <firmware>',
description: `Flash application from this file`,
},
],
action: async (deviceId: string, { dk, nbiot, nodebug, port, firmware }) => {
const hexfile =
firmware ?? (await getLatestFirmware({ dk, nbiot, nodebug }))

console.log(
chalk.magenta(`Connecting to device`),
chalk.blue(port ?? defaultPort),
)

const connection = await connect({
atHostHexfile:
dk === true ? atHostHexfile['9160dk'] : atHostHexfile['thingy91'],
device: port ?? defaultPort,
warn: console.error,
})

console.log(
chalk.magenta(`Flashing credentials`),
chalk.blue(port ?? defaultPort),
)

const certs = deviceFileLocations({
certsDir,
deviceId,
})

await flashCredentials({
at: connection.connection.at,
caCert: fs.readFileSync(
path.resolve(process.cwd(), 'data', 'AmazonRootCA1.pem'),
'utf-8',
),
secTag: 42,
clientCert: fs.readFileSync(certs.certWithCA, 'utf-8'),
privateKey: fs.readFileSync(certs.key, 'utf-8'),
})

console.log(chalk.magenta(`Flashing firmware`), chalk.blue(hexfile))

await flash({
hexfile,
})

await connection.connection.end()

console.log(chalk.green(`Done`))
},
help: 'Flash credentials and latest firmware release to a device using JLink',
})

0 comments on commit 49dffb3

Please sign in to comment.