Skip to content

Commit

Permalink
Merge pull request #115 from particle-iot/feature/improve-device-stat…
Browse files Browse the repository at this point in the history
…e-detection

Accurate device state detection for devices in DFU
  • Loading branch information
keeramis authored Jul 30, 2024
2 parents d4312f1 + 530b91a commit 1eb9d87
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 11 deletions.
30 changes: 19 additions & 11 deletions src/dfu.js
Original file line number Diff line number Diff line change
Expand Up @@ -236,18 +236,26 @@ class Dfu {
* @return {Promise} Object with property 'protected'
*/
async getProtectionState() {
// setting 0 is for Internal Flash
await this.setAltSetting(0);

let allSegmentsProtected = true;
this._memoryInfo.segments.forEach(s => {
if (!(s.erasable === true && s.writable === false && s.readable === false)) {
allSegmentsProtected = false;
try {
const res = await this._getStringDescriptor(0xfa);
const state = res.split(';').find(kv => kv.startsWith('sm=')).split('=')[1].trim().charAt(0);
switch (state) {
case 'o': return { protected: false, overridden: false };
case 'p': return { protected: true };
case 's': return { protected: false, overridden: true };
default: throw new Error('Unknown device state');
}
});
// FIXME: Currently, device-os does not reliably distinguish the `overridden` value for different protection modes.
// As a workaround, we use `null` to uniquely indicate the distinction.
return { protected: allSegmentsProtected, overridden: null };
} catch (error) {
// Fallback for devices with Device-OS < 6.1.2
await this.setAltSetting(0); // setting 0 is for Internal Flash

const allSegmentsProtected = this._memoryInfo.segments.every(s =>
s.erasable === true && s.writable === false && s.readable === false
);

// Use `null` for `overridden` since we cannot distinguish between Open and Service Mode
return { protected: allSegmentsProtected, overridden: null };
}
}

/**
Expand Down
30 changes: 30 additions & 0 deletions src/dfu.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -365,8 +365,35 @@ describe('dfu', () => {
});

describe('getProtectionState', () => {
it ('detects an Open Device from string desc for Device-OS >= 6.1.2', async () => {
const dfu = new Dfu();
sinon.stub(dfu, '_getStringDescriptor').resolves('sm=o');

const res = await dfu.getProtectionState();
expect(res.protected).to.eql(false);
expect(res.overridden).to.eql(false);
});

it ('detects a Protected Device from string desc for Device-OS >= 6.1.2', async () => {
const dfu = new Dfu();
sinon.stub(dfu, '_getStringDescriptor').resolves('sm=p');

const res = await dfu.getProtectionState();
expect(res.protected).to.eql(true);
});

it ('detects a Protected Device in Service Mode from string desc for Device-OS >= 6.1.2', async () => {
const dfu = new Dfu();
sinon.stub(dfu, '_getStringDescriptor').resolves('sm=s');

const res = await dfu.getProtectionState();
expect(res.protected).to.eql(false);
expect(res.overridden).to.eql(true);
});

it('returns that all segments are protected', async () => {
const dfu = new Dfu();
sinon.stub(dfu, '_getStringDescriptor').rejects('random error');
sinon.stub(dfu, 'setAltSetting').resolves();
const internalFlashDesc = {
'name': 'Internal Flash',
Expand Down Expand Up @@ -409,11 +436,13 @@ describe('dfu', () => {

const res = await dfu.getProtectionState();

expect(dfu.setAltSetting).to.have.been.calledOnce;
expect(res.protected).to.eql(true);
});

it('returns that all segments are not protected', async () => {
const dfu = new Dfu();
sinon.stub(dfu, '_getStringDescriptor').rejects('random error');
sinon.stub(dfu, 'setAltSetting').resolves();
const internalFlashDesc = {
'name': 'Internal Flash',
Expand Down Expand Up @@ -456,6 +485,7 @@ describe('dfu', () => {

const res = await dfu.getProtectionState();

expect(dfu.setAltSetting).to.have.been.calledOnce;
expect(res.protected).to.eql(false);
});
});
Expand Down

0 comments on commit 1eb9d87

Please sign in to comment.