Skip to content

Commit 1abdbb4

Browse files
thegeckoarekzaluski
authored andcommitted
Serial updates
1 parent 86372f1 commit 1abdbb4

File tree

3 files changed

+139
-42
lines changed

3 files changed

+139
-42
lines changed

examples/daplink-serial/common.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ function listen(transport) {
4040
const target = new DAPjs.DAPLink(transport);
4141

4242
target.on(DAPjs.DAPLink.EVENT_SERIAL_DATA, data => {
43-
console.log(data);
43+
process.stdout.write(data);
4444
});
4545

4646
return target.connect()

src/daplink/index.ts

Lines changed: 119 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
* SOFTWARE.
2222
*/
2323

24-
import { CmsisDAP, Proxy } from "../proxy";
24+
import { CmsisDAP, DAPProtocol, DEFAULT_CLOCK_FREQUENCY } from "../proxy";
25+
import { Transport } from "../transport";
2526
import { DAPLinkFlash, DAPLinkSerial } from "./enums";
2627

2728
/**
@@ -31,16 +32,20 @@ const DEFAULT_BAUDRATE = 9600;
3132
/**
3233
* @hidden
3334
*/
34-
const DEFAULT_SERIAL_DELAY = 200;
35+
const DEFAULT_SERIAL_DELAY = 100;
3536
/**
3637
* @hidden
3738
*/
3839
const DEFAULT_PAGE_SIZE = 62;
40+
/**
41+
* @hidden
42+
*/
43+
const SERIAL_VENDOR_CODE = 131;
3944

4045
/**
4146
* DAPLink Class
4247
*/
43-
export class DAPLink extends CmsisDAP implements Proxy {
48+
export class DAPLink extends CmsisDAP {
4449

4550
/**
4651
* Progress event
@@ -54,7 +59,45 @@ export class DAPLink extends CmsisDAP implements Proxy {
5459
*/
5560
public static EVENT_SERIAL_DATA: string = "serial";
5661

57-
private timer?: any;
62+
/**
63+
* @hidden
64+
*/
65+
protected serialPolling = false;
66+
67+
/**
68+
* @hidden
69+
*/
70+
protected serialListeners = false;
71+
72+
/**
73+
* DAPLink constructor
74+
* @param transport Debug transport to use
75+
* @param mode Debug mode to use
76+
* @param clockFrequency Communication clock frequency to use (default 10000000)
77+
*/
78+
constructor(transport: Transport, mode: DAPProtocol = DAPProtocol.DEFAULT, clockFrequency: number = DEFAULT_CLOCK_FREQUENCY) {
79+
super(transport, mode, clockFrequency);
80+
81+
this.on("newListener", async event => {
82+
if (event === DAPLink.EVENT_SERIAL_DATA) {
83+
const listenerCount = this.listenerCount(event);
84+
85+
if (listenerCount === 0) {
86+
this.serialListeners = true;
87+
}
88+
}
89+
});
90+
91+
this.on("removeListener", event => {
92+
if (event === DAPLink.EVENT_SERIAL_DATA) {
93+
const listenerCount = this.listenerCount(event);
94+
95+
if (listenerCount === 0) {
96+
this.serialListeners = false;
97+
}
98+
}
99+
});
100+
}
58101

59102
/**
60103
* Detect if buffer contains text or binary data
@@ -146,51 +189,88 @@ export class DAPLink extends CmsisDAP implements Proxy {
146189
}
147190

148191
/**
149-
* Start listening for serial data
150-
* @param serialDelay The serial delay to use (defaults to 200)
192+
* Write serial data
193+
* @param data The data to write
194+
* @returns Promise
151195
*/
152-
public startSerialRead(serialDelay: number = DEFAULT_SERIAL_DELAY) {
153-
this.stopSerialRead();
154-
this.timer = setInterval(() => {
155-
return this.send(DAPLinkSerial.READ)
156-
.then(serialData => {
157-
if (serialData.byteLength > 0) {
158-
// check if there is any data returned from the device
159-
// first byte contains the vendor code
160-
// second byte contains the actual length of data read from the device
161-
const dataLength = serialData.getUint8(1);
162-
if (dataLength !== 0) {
163-
const offset = 2;
164-
const dataArray = serialData.buffer.slice(offset, offset + dataLength);
165-
const numberArray = Array.prototype.slice.call(new Uint8Array(dataArray));
166-
const data = String.fromCharCode.apply(null, numberArray);
167-
this.emit(DAPLink.EVENT_SERIAL_DATA, data);
168-
}
169-
}
170-
});
171-
}, serialDelay);
196+
public serialWrite(data: string): Promise<void> {
197+
const arrayData = data.split("").map((e: string) => e.charCodeAt(0));
198+
arrayData.unshift(arrayData.length);
199+
return this.send(DAPLinkSerial.WRITE, new Uint8Array(arrayData).buffer)
200+
.then(() => undefined);
172201
}
173202

174203
/**
175-
* Stop listening for serial data
204+
* Read serial data
205+
* @returns Promise of any arrayBuffer read
176206
*/
177-
public stopSerialRead() {
178-
if (this.timer) {
179-
clearInterval(this.timer);
180-
this.timer = undefined;
207+
public serialRead(): Promise<ArrayBuffer | undefined> {
208+
return this.send(DAPLinkSerial.READ)
209+
.then(serialData => {
210+
// Check if there is any data returned from the device
211+
if (serialData.byteLength === 0) {
212+
return undefined;
213+
}
214+
215+
// First byte contains the vendor code
216+
if (serialData.getUint8(0) !== SERIAL_VENDOR_CODE) {
217+
return undefined;
218+
}
219+
220+
// Second byte contains the actual length of data read from the device
221+
const dataLength = serialData.getUint8(1);
222+
if (dataLength === 0) {
223+
return undefined;
224+
}
225+
226+
const offset = 2;
227+
return serialData.buffer.slice(offset, offset + dataLength);
228+
});
229+
}
230+
231+
/**
232+
* Start listening for serial data
233+
* @param serialDelay The serial delay to use (default 100)
234+
* @param autoConnect whether to automatically connect to the target (default true)
235+
*/
236+
public async startSerialRead(serialDelay: number = DEFAULT_SERIAL_DELAY, autoConnect = true) {
237+
this.serialPolling = true;
238+
239+
while (this.serialPolling) {
240+
241+
// Don't read serial output unless we have event listeners
242+
if (this.serialListeners) {
243+
244+
// Remember connection state
245+
const connectedState = this.connected;
246+
247+
if (this.connected === false && autoConnect === true) {
248+
await this.connect();
249+
}
250+
251+
const serialData = await this.serialRead();
252+
253+
// Put state back
254+
if (connectedState === false && autoConnect === true) {
255+
await this.disconnect();
256+
}
257+
258+
if (serialData !== undefined) {
259+
const numberArray = Array.prototype.slice.call(new Uint8Array(serialData));
260+
const data = String.fromCharCode.apply(null, numberArray);
261+
this.emit(DAPLink.EVENT_SERIAL_DATA, data);
262+
}
263+
}
264+
265+
await new Promise(resolve => setTimeout(() => resolve(), serialDelay));
181266
}
182267
}
183268

184269
/**
185-
* Write serial data
186-
* @param data The data to write
187-
* @returns Promise
270+
* Stop listening for serial data
188271
*/
189-
public serialWrite(data: string): Promise<void> {
190-
const arrayData = data.split("").map((e: string) => e.charCodeAt(0));
191-
arrayData.unshift(arrayData.length);
192-
return this.send(DAPLinkSerial.WRITE, new Uint8Array(arrayData).buffer)
193-
.then(() => undefined);
272+
public stopSerialRead() {
273+
this.serialPolling = false;
194274
}
195275
}
196276

src/proxy/cmsis-dap.ts

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,11 @@ const TRANSFER_OPERATION_SIZE = 5;
6868
*/
6969
export class CmsisDAP extends EventEmitter implements Proxy {
7070

71+
/**
72+
* Whether the device has been opened
73+
*/
74+
public connected = false;
75+
7176
/**
7277
* The maximum DAPOperations which can be transferred
7378
*/
@@ -246,6 +251,10 @@ export class CmsisDAP extends EventEmitter implements Proxy {
246251
* @returns Promise
247252
*/
248253
public connect(): Promise<void> {
254+
if (this.connected === true) {
255+
return Promise.resolve();
256+
}
257+
249258
return this.transport.open()
250259
.then(() => this.send(DAPCommand.DAP_SWJ_CLOCK, new Uint32Array([this.clockFrequency])))
251260
.then(() => this.send(DAPCommand.DAP_CONNECT, new Uint8Array([this.mode])))
@@ -255,17 +264,25 @@ export class CmsisDAP extends EventEmitter implements Proxy {
255264
}
256265
})
257266
.then(() => this.configureTransfer(0, 100, 0))
258-
.then(() => this.selectProtocol(DAPProtocol.SWD));
267+
.then(() => this.selectProtocol(DAPProtocol.SWD))
268+
.then(() => {
269+
this.connected = true;
270+
});
259271
}
260272

261273
/**
262274
* Disconnect from target device
263275
* @returns Promise
264276
*/
265277
public disconnect(): Promise<void> {
278+
if (this.connected === false) {
279+
return Promise.resolve();
280+
}
281+
266282
return this.send(DAPCommand.DAP_DISCONNECT)
283+
.then(() => this.transport.close())
267284
.then(() => {
268-
return this.transport.close();
285+
this.connected = false;
269286
});
270287
}
271288

0 commit comments

Comments
 (0)