• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

taichunmin / chameleon-ultra.js / 16902739519

12 Aug 2025 08:00AM UTC coverage: 68.124% (-1.1%) from 69.192%
16902739519

push

github

web-flow
Add support 9 new cmds (#204)

504 of 658 branches covered (76.6%)

Branch coverage included in aggregate %.

415 of 589 new or added lines in 10 files covered. (70.46%)

9 existing lines in 3 files now uncovered.

2815 of 4214 relevant lines covered (66.8%)

2958829.46 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/src/plugin/SerialPortAdapter.ts
1
import * as _ from 'lodash-es'
×
2
import { SerialPort } from 'serialport'
×
3
import { Duplex } from 'stream'
×
4
import { type ChameleonUltra } from '../ChameleonUltra'
5
import { setObject } from '../iifeExportHelper'
×
6
import { type AdapterInstallResp, type UltraPlugin, type PluginInstallContext, type SerialPortOption } from '../types'
7

8
async function findDevicePath (): Promise<string> {
×
9
  const device = _.find(await SerialPort.list(), { vendorId: '6868', productId: '8686' }) // ChameleonUltra
×
10
  if (_.isNil(device)) throw new Error('device not found')
×
11
  return device?.path
×
12
}
×
13

NEW
14
export default class SerialPortAdapter implements UltraPlugin {
×
15
  duplex: SerialPort | null = null
×
16
  name = 'adapter'
×
17
  readonly #emitErr: (err: Error) => void
×
18
  ultra?: ChameleonUltra
×
19

20
  constructor () {
×
21
    this.#emitErr = (err: Error): void => { this.ultra?.emitter.emit('error', _.set(new Error(err.message), 'originalError', err)) }
×
22
  }
×
23

24
  #debug (formatter: any, ...args: [] | any[]): void {
×
25
    this.ultra?.emitter.emit('debug', 'serial', formatter, ...args)
×
26
  }
×
27

28
  async install (context: AdapterInstallContext, pluginOption: SerialPortOption = {}): Promise<AdapterInstallResp> {
×
29
    const ultra = this.ultra = context.ultra
×
30

31
    if (!_.isNil(ultra.$adapter)) {
×
32
      await ultra.disconnect(new Error('adapter replaced'))
×
33
    }
×
34

35
    const adapter: AdapterInstallResp = {
×
36
      isSupported: () => !_.isNil(SerialPort),
×
37
    }
×
38

39
    ultra.addHook('connect', async (ctx: any, next: () => Promise<unknown>) => {
×
40
      if (ultra.$adapter !== adapter) return await next() // 代表已經被其他 adapter 接管
×
41

42
      try {
×
43
        if (!adapter.isSupported()) throw new Error('SerialPort not supported')
×
44

45
        const baudRate = pluginOption?.baudRate ?? 115200
×
46
        const path = pluginOption?.path ?? await findDevicePath()
×
47

48
        this.duplex = await new Promise<SerialPort>((resolve, reject) => {
×
49
          const tmp = new SerialPort({ baudRate, path }, err => { _.isNil(err) ? resolve(tmp) : reject(err) })
×
50
        })
×
51
        this.duplex?.once('close', () => { void ultra.disconnect(new Error('SerialPort closed')) })
×
52
        this.#debug(`port connected, path = ${path}, baudRate = ${baudRate}`)
×
53
        ultra.port = _.merge(Duplex.toWeb(this.duplex), {
×
54
          isOpen: () => { return this.duplex?.isOpen ?? false },
×
55
          isDfu: () => false, // TODO: dfu
×
56
        })
×
57
        return await next()
×
58
      } catch (err) {
×
59
        this.#debug(err)
×
60
        throw err
×
61
      }
×
62
    })
×
63

64
    ultra.addHook('disconnect', async (ctx: any, next: () => Promise<unknown>) => {
×
65
      if (ultra.$adapter !== adapter || _.isNil(this.duplex)) return await next() // 代表已經被其他 adapter 接管
×
66

67
      await next().catch(this.#emitErr)
×
68
      await new Promise<void>((resolve, reject) => { this.duplex?.close(err => { _.isNil(err) ? resolve() : reject(err) }) })
×
69
      this.duplex = null
×
70
    })
×
71

72
    return adapter
×
73
  }
×
74
}
×
75

76
setObject(globalThis, ['ChameleonUltraJS', 'SerialPortAdapter'], SerialPortAdapter)
×
77

78
/** @inline */
79
type AdapterInstallContext = PluginInstallContext & {
80
  ultra: PluginInstallContext['ultra'] & { $adapter?: any }
81
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc