UNPKG

ircbloq-link

Version:

Porvide local hardware function to ircbloq

155 lines (126 loc) 4.97 kB
const fs = require('fs'); const {spawn} = require('child_process'); const path = require('path'); const ansi = require('ansi-string'); const os = require('os'); const UFLASH_MODULE_NAME = 'uflash'; const MICROFS_MODULE_NAME = 'microfs'; const FLASH_TIME = 25 * 1000; // 20s class Microbit { constructor (peripheralPath, config, userDataPath, toolsPath, sendstd) { this._peripheralPath = peripheralPath; this._config = config; this._userDataPath = userDataPath; this._projectPath = path.join(userDataPath, 'microbit/project'); this._pythonPath = path.join(toolsPath, 'Python'); this._sendstd = sendstd; if (os.platform() === 'darwin') { this._pyPath = path.join(this._pythonPath, 'bin/python'); } else { this._pyPath = path.join(this._pythonPath, 'python'); } this._codefilePath = path.join(this._projectPath, 'main.py'); } _insertStr (soure, start, newStr) { return soure.slice(0, start) + newStr + soure.slice(start); } async flash (code, library = []) { const fileToPut = []; if (!fs.existsSync(this._projectPath)) { fs.mkdirSync(this._projectPath, {recursive: true}); } try { fs.writeFileSync(this._codefilePath, code); } catch (err) { return Promise.reject(err); } fileToPut.push(this._codefilePath); library.forEach(lib => { if (fs.existsSync(lib)) { const libraries = fs.readdirSync(lib); libraries.forEach(file => { fileToPut.push(path.join(lib, file)); }); } }); const ufsTestExitCode = await this.ufsTestFirmware(); if (ufsTestExitCode === 'Failed') { this._sendstd(`${ansi.yellow_dark}Could not enter raw REPL.\n`); this._sendstd(`${ansi.clear}Try to flash micropython for microbit firmware to fix.\n`); await this.uflash(); } this._sendstd('Writing files...\n'); for (const file of fileToPut) { const ufsPutExitCode = await this.ufsPut(file); if (ufsPutExitCode !== 'Success') { return Promise.reject(ufsPutExitCode); } } this._sendstd(`${ansi.green_dark}Success\n`); return Promise.resolve('Success'); } ufsTestFirmware () { return new Promise(resolve => { const ufs = spawn(this._pyPath, ['-m', MICROFS_MODULE_NAME, 'ls']); ufs.stdout.on('data', buf => { if (buf.toString().indexOf('Could not enter raw REPL.') !== -1){ return resolve('Failed'); } }); ufs.on('exit', () => resolve('Success')); }); } ufsPut (file) { return new Promise((resolve, reject) => { const ufs = spawn(this._pyPath, ['-m', MICROFS_MODULE_NAME, 'put', file]); ufs.stdout.on('data', buf => { this._sendstd(ansi.red + buf.toString()); return resolve('Failed'); }); ufs.on('exit', outCode => { switch (outCode) { case 0: this._sendstd(`${file} write finish\n`); return resolve('Success'); case 1: return reject('ufs failed to write'); } }); }); } uflash () { return new Promise((resolve, reject) => { const uflash = spawn(this._pyPath, [this._uflashPath]); this._sendstd(`${ansi.green_dark}Start flash firmware...\n`); this._sendstd(`${ansi.clear}This step will take tens of seconds, please wait.\n`); // Add finish flasg to solve uflash will exit immediately after start, nut not exit // after flash finish. So add a counter flag in order to ensure that enough time has // been spent to finish burning and uflash runs successfully. let finishFlag = 0; const finish = () => { finishFlag += 1; if (finishFlag === 2) { this._sendstd(`${ansi.green_dark}Flash Success.\n`); return resolve('Success'); } }; setTimeout(finish, FLASH_TIME); uflash.stdout.on('data', buf => { this._sendstd(buf.toString()); }); uflash.stderr.on('data', buf => { this._sendstd(ansi.red + buf.toString()); }); uflash.on('exit', outCode => { switch (outCode) { case 0: finish(); break; case 1: return reject('uflash failed to flash'); } }); }); } } module.exports = Microbit;