const fs = require('fs') const debug = require('debug') const logger = debug('serialport/bindings/unixWrite') const { promisify } = require('util') const writeAsync = promisify(fs.write) const writable = binding => { return new Promise((resolve, reject) => { binding.poller.once('writable', err => (err ? reject(err) : resolve())) }) } const unixWrite = async ({ binding, buffer, offset = 0, fsWriteAsync = writeAsync }) => { const bytesToWrite = buffer.length - offset logger('Starting write', buffer.length, 'bytes offset', offset, 'bytesToWrite', bytesToWrite) if (!binding.isOpen) { throw new Error('Port is not open') } try { const { bytesWritten } = await fsWriteAsync(binding.fd, buffer, offset, bytesToWrite) logger('write returned: wrote', bytesWritten, 'bytes') if (bytesWritten + offset < buffer.length) { if (!binding.isOpen) { throw new Error('Port is not open') } return unixWrite({ binding, buffer, offset: bytesWritten + offset, fsWriteAsync }) } logger('Finished writing', bytesWritten + offset, 'bytes') } catch (err) { logger('write errored', err) if (err.code === 'EAGAIN' || err.code === 'EWOULDBLOCK' || err.code === 'EINTR') { if (!binding.isOpen) { throw new Error('Port is not open') } logger('waiting for writable because of code:', err.code) await writable(binding) return unixWrite({ binding, buffer, offset, fsWriteAsync }) } const disconnectError = err.code === 'EBADF' || // Bad file number means we got closed err.code === 'ENXIO' || // No such device or address probably usb disconnect err.code === 'UNKNOWN' || err.errno === -1 // generic error if (disconnectError) { err.disconnect = true logger('disconnecting', err) } logger('error', err) throw err } } module.exports = unixWrite