Skip to content

Commit

Permalink
fix: EZSP: Implemented several attempts to send a request in case of …
Browse files Browse the repository at this point in the history
…problems (#871)

The extended timeout setting has been removed (we need to analyze the need to set it).
  • Loading branch information
kirovilya authored Jan 13, 2024
1 parent b2ef363 commit 41a4543
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 39 deletions.
4 changes: 2 additions & 2 deletions src/adapter/ezsp/adapter/ezspAdapter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -439,8 +439,8 @@ class EZSPAdapter extends Adapter {
if (ieeeAddr == null) {
ieeeAddr = `0x${this.driver.ieee.toString()}`;
}
debug('sendZclFrameToEndpointInternal %s:%i/%i (%i,%i,%i)',
ieeeAddr, networkAddress, endpoint, responseAttempt, dataRequestAttempt, this.queue.count());
debug('sendZclFrameToEndpointInternal %s:%i/%i (%i,%i,%i), timeout=%i',
ieeeAddr, networkAddress, endpoint, responseAttempt, dataRequestAttempt, this.queue.count(), timeout);
let response = null;
const command = zclFrame.getCommand();
if (command.hasOwnProperty('response') && disableResponse === false) {
Expand Down
77 changes: 47 additions & 30 deletions src/adapter/ezsp/driver/driver.ts
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,6 @@ const IEEE_PREFIX_MFG_ID: IeeeMfg[] = [
const DEFAULT_MFG_ID = 0x1049;

export class Driver extends EventEmitter {
private direct = EmberOutgoingMessageType.OUTGOING_DIRECT;
public ezsp: Ezsp;
private nwkOpt: TsType.NetworkOptions;
private greenPowerGroup: number;
Expand Down Expand Up @@ -444,39 +443,57 @@ export class Driver extends EventEmitter {

public async request(nwk: number | EmberEUI64, apsFrame: EmberApsFrame,
/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
data: Buffer, timeout = 30000): Promise<boolean> {
try {
const seq = (apsFrame.sequence + 1) & 0xFF;
let eui64: EmberEUI64;
if (typeof nwk !== 'number') {
eui64 = nwk as EmberEUI64;
const strEui64 = eui64.toString();
let nodeId = this.eui64ToNodeId.get(strEui64);
if (nodeId === undefined) {
nodeId = (await this.ezsp.execCommand('lookupNodeIdByEui64', {eui64: eui64})).nodeId;
if (nodeId && nodeId !== 0xFFFF) {
this.eui64ToNodeId.set(strEui64, nodeId);
} else {
throw new Error('Unknown EUI64:' + strEui64);
data: Buffer, extendedTimeout = false): Promise<boolean> {
let result = false;
// we make three attempts to send the request
for (const delay of [500, 1000, 1500]) {
try {
const seq = (apsFrame.sequence + 1) & 0xFF;
let eui64: EmberEUI64;
if (typeof nwk !== 'number') {
eui64 = nwk as EmberEUI64;
const strEui64 = eui64.toString();
let nodeId = this.eui64ToNodeId.get(strEui64);
if (nodeId === undefined) {
nodeId = (await this.ezsp.execCommand('lookupNodeIdByEui64', {eui64: eui64})).nodeId;
if (nodeId && nodeId !== 0xFFFF) {
this.eui64ToNodeId.set(strEui64, nodeId);
} else {
throw new Error('Unknown EUI64:' + strEui64);
}
}
nwk = nodeId;
} else {
eui64 = await this.networkIdToEUI64(nwk);
}
nwk = nodeId;
} else {
eui64 = await this.networkIdToEUI64(nwk);
}
if (this.ezsp.ezspV < 8) {
// const route = this.eui64ToRelays.get(eui64.toString());
// if (route) {
// const = await this.ezsp.execCommand('setSourceRoute', {eui64});
// // }
if (this.ezsp.ezspV < 8) {
// const route = this.eui64ToRelays.get(eui64.toString());
// if (route) {
// const = await this.ezsp.execCommand('setSourceRoute', {eui64});
// // }
}
if (extendedTimeout) {
await this.ezsp.execCommand('setExtendedTimeout', {remoteEui64: eui64, extendedTimeout: true});
}
const sendResult = await this.ezsp.sendUnicast(
EmberOutgoingMessageType.OUTGOING_DIRECT, nwk, apsFrame, seq, data
);
// repeat only for these statuses
if ([EmberStatus.MAX_MESSAGE_LIMIT_REACHED, EmberStatus.NO_BUFFERS, EmberStatus.NETWORK_BUSY]
.includes(sendResult.status)) {
// need to repeat after pause
debug.log(`Request send status ${sendResult.status}. Attempt to repeat the request`);
await Wait(delay);
} else {
result = (sendResult.status == EmberStatus.SUCCESS);
break;
}
} catch (e) {
debug.error(`Request error ${e}: ${e.stack}`);
break;
}
await this.ezsp.execCommand('setExtendedTimeout', {remoteEui64: eui64, extendedTimeout: true});
const result = await this.ezsp.sendUnicast(this.direct, nwk, apsFrame, seq, data);
return result.status == EmberStatus.SUCCESS;
} catch (e) {
debug.error(`Request error ${e}: ${e.stack}`);
return false;
}
return result;
}

/* eslint-disable-next-line @typescript-eslint/no-unused-vars */
Expand Down
14 changes: 7 additions & 7 deletions src/adapter/ezsp/driver/ezsp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -394,14 +394,14 @@ export class Ezsp extends EventEmitter {
debug.log('Set %s = %s', EzspConfigId.valueToName(EzspConfigId, configId), value);
const ret = await this.execCommand('setConfigurationValue', {configId: configId, value: value});
console.assert(ret.status === EmberStatus.SUCCESS,
`Command (setConfigurationValue) returned unexpected state: ${ret}`);
`Command (setConfigurationValue(${configId}, ${value})) returned unexpected state: ${JSON.stringify(ret)}`);
}

async getConfigurationValue(configId: number): Promise<number> {
debug.log('Get %s', EzspConfigId.valueToName(EzspConfigId, configId));
const ret = await this.execCommand('getConfigurationValue', {configId: configId});
console.assert(ret.status === EmberStatus.SUCCESS,
`Command (getConfigurationValue) returned unexpected state: ${ret}`);
`Command (getConfigurationValue(${configId})) returned unexpected state: ${JSON.stringify(ret)}`);
debug.log('Got %s = %s', EzspConfigId.valueToName(EzspConfigId, configId), ret.value.toString());
return ret.value;
}
Expand All @@ -414,29 +414,29 @@ export class Ezsp extends EventEmitter {
async setMulticastTableEntry(index: number, entry: t.EmberMulticastTableEntry): Promise<EmberStatus> {
const ret = await this.execCommand('setMulticastTableEntry', {index: index, value: entry});
console.assert(ret.status === EmberStatus.SUCCESS,
`Command (setMulticastTableEntry) returned unexpected state: ${ret}`);
`Command (setMulticastTableEntry) returned unexpected state: ${JSON.stringify(ret)}`);
return ret.status;
}

async setInitialSecurityState(entry: t.EmberInitialSecurityState): Promise<EmberStatus>{
const ret = await this.execCommand('setInitialSecurityState', {state: entry});
console.assert(ret.success === EmberStatus.SUCCESS,
`Command (setInitialSecurityState) returned unexpected state: ${ret}`);
`Command (setInitialSecurityState) returned unexpected state: ${JSON.stringify(ret)}`);
return ret.success;
}

async getCurrentSecurityState(): Promise<EZSPFrameData> {
const ret = await this.execCommand('getCurrentSecurityState');
console.assert(ret.status === EmberStatus.SUCCESS,
`Command (getCurrentSecurityState) returned unexpected state: ${ret}`);
`Command (getCurrentSecurityState) returned unexpected state: ${JSON.stringify(ret)}`);
return ret;
}

async setValue(valueId: t.EzspValueId, value: number): Promise<EZSPFrameData> {
debug.log('Set %s = %s', t.EzspValueId.valueToName(t.EzspValueId, valueId), value);
const ret = await this.execCommand('setValue', {valueId, value});
console.assert(ret.status === EmberStatus.SUCCESS,
`Command (setValue) returned unexpected state: ${ret.status}`);
`Command (setValue) returned unexpected state: ${JSON.stringify(ret)}`);

return ret;
}
Expand All @@ -454,7 +454,7 @@ export class Ezsp extends EventEmitter {
debug.log('Set %s = %s', EzspPolicyId.valueToName(EzspPolicyId, policyId), value);
const ret = await this.execCommand('setPolicy', {policyId: policyId, decisionId: value});
console.assert(ret.status === EmberStatus.SUCCESS,
`Command (setPolicy) returned unexpected state: ${ret}`);
`Command (setPolicy) returned unexpected state: ${JSON.stringify(ret)}`);
return ret;
}

Expand Down

0 comments on commit 41a4543

Please sign in to comment.