Skip to content

Commit 9306808

Browse files
committed
Add mutex to ensure send is atomic
1 parent 7885600 commit 9306808

File tree

2 files changed

+43
-5
lines changed

2 files changed

+43
-5
lines changed

src/proxy/cmsis-dap.ts

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,31 @@ const TRANSFER_HEADER_SIZE = 2;
6363
*/
6464
const TRANSFER_OPERATION_SIZE = 5;
6565

66+
/**
67+
* @hidden
68+
*/
69+
class Mutex {
70+
private locked = false;
71+
72+
/**
73+
* Wait until the Mutex is available and claim it
74+
*/
75+
public async lock(): Promise<void> {
76+
while (this.locked) {
77+
// Yield the current execution context, effectively moving it to the back of the promise queue
78+
await new Promise(resolve => setTimeout(resolve, 1));
79+
}
80+
this.locked = true;
81+
}
82+
83+
/**
84+
* Unlock the Mutex
85+
*/
86+
public unlock(): void {
87+
this.locked = false;
88+
}
89+
}
90+
6691
/**
6792
* CMSIS-DAP class
6893
* https://www.keil.com/pack/doc/CMSIS/DAP/html/group__DAP__Commands__gr.html
@@ -84,6 +109,8 @@ export class CmsisDAP extends EventEmitter implements Proxy {
84109
*/
85110
public blockSize: number;
86111

112+
private sendMutex = new Mutex();
113+
87114
/**
88115
* CMSIS-DAP constructor
89116
* @param transport Debug transport to use
@@ -142,8 +169,10 @@ export class CmsisDAP extends EventEmitter implements Proxy {
142169
protected async send(command: number, data?: BufferSource): Promise<DataView> {
143170
const array = this.bufferSourceToUint8Array(command, data);
144171

172+
await this.sendMutex.lock();
145173
await this.transport.write(array);
146174
const response = await this.transport.read();
175+
this.sendMutex.unlock();
147176

148177
if (response.getUint8(0) !== command) {
149178
throw new Error(`Bad response for ${command} -> ${response.getUint8(0)}`);
@@ -265,7 +294,7 @@ export class CmsisDAP extends EventEmitter implements Proxy {
265294
*/
266295
public async connect(): Promise<void> {
267296
if (this.connected === true) {
268-
return Promise.resolve();
297+
return;
269298
}
270299

271300
await this.transport.open();
@@ -279,11 +308,18 @@ export class CmsisDAP extends EventEmitter implements Proxy {
279308
}
280309
} catch (error) {
281310
await this.clearAbort();
311+
await this.transport.close();
312+
throw error;
313+
}
314+
315+
try {
316+
await this.configureTransfer(0, 100, 0);
317+
await this.selectProtocol(DAPProtocol.SWD);
318+
} catch (error) {
319+
await this.transport.close();
282320
throw error;
283321
}
284322

285-
await this.configureTransfer(0, 100, 0);
286-
await this.selectProtocol(DAPProtocol.SWD);
287323
this.connected = true;
288324
}
289325

@@ -293,7 +329,7 @@ export class CmsisDAP extends EventEmitter implements Proxy {
293329
*/
294330
public async disconnect(): Promise<void> {
295331
if (this.connected === false) {
296-
return Promise.resolve();
332+
return;
297333
}
298334

299335
try {

src/transport/webusb.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,9 @@ export class WebUSB implements Transport {
139139
* @returns Promise of DataView
140140
*/
141141
public async read(): Promise<DataView> {
142-
if (this.interfaceNumber === undefined) return Promise.reject('No device opened');
142+
if (this.interfaceNumber === undefined) {
143+
throw new Error('No device opened');
144+
}
143145

144146
let result: USBInTransferResult;
145147

0 commit comments

Comments
 (0)