Skip to content

Commit

Permalink
Merge pull request #1 from cortex-debug/pack-asset-service
Browse files Browse the repository at this point in the history
Pack asset service
  • Loading branch information
thegecko authored Jan 30, 2023
2 parents a7507fd + 51f2ade commit c0707fd
Show file tree
Hide file tree
Showing 13 changed files with 552 additions and 107 deletions.
15 changes: 13 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
"serve": "serve --cors -p 9000"
},
"dependencies": {
"jszip": "^3.10.1",
"node-fetch": "^2.6.7",
"xml2js": "^0.4.23"
},
Expand Down Expand Up @@ -230,8 +231,13 @@
},
"svd-viewer.deviceConfig": {
"type": "string",
"default": "device",
"description": "Debug configuration key to use to get the device"
"default": "deviceName",
"description": "Debug configuration key to use to get the device name"
},
"svd-viewer.processorConfig": {
"type": "string",
"default": "processorName",
"description": "Debug configuration key to use to get the procerssor name"
},
"svd-viewer.svdAddrGapThreshold": {
"type": "number",
Expand All @@ -240,6 +246,11 @@
"minimum": -1,
"maximum": 32,
"description": "If the gap between registers is less than this threshold (multiple of 8), combine into a single read from device. -1 means never combine registers and is very slow"
},
"svd-viewer.packAssetUrl": {
"type": "string",
"default": "https://pack-asset-service.keil.arm.com",
"description": "Base URL for CMSIS pack assets"
}
}
}
Expand Down
10 changes: 8 additions & 2 deletions src/browser/extension.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/**
* Copyright (C) 2023 Arm Limited
*/

import * as vscode from 'vscode';
import { PeripheralTreeProvider } from '../views/peripheral';
import { Commands } from '../commands';
import { DebugTracker } from '../debug-tracker';
import { SvdRegistry } from '../svd-registry';
import { SvdResolver } from '../svd-resolver';

export const activate = async (context: vscode.ExtensionContext): Promise<SvdRegistry> => {
const registry = new SvdRegistry();
const tracker = new DebugTracker();
const peripheralTree = new PeripheralTreeProvider(tracker, registry);
const registry = new SvdRegistry();
const resolver = new SvdResolver(registry);
const peripheralTree = new PeripheralTreeProvider(tracker, resolver);
const commands = new Commands(peripheralTree);

await tracker.activate(context);
Expand Down
53 changes: 53 additions & 0 deletions src/cmsis-pack/pack-utils.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* Copyright (C) 2023 Arm Limited
*/

import * as vscode from 'vscode';

const MAIN_DELIMITER = '::';
const VERSION_DELIMITER = '@';

export interface Pack {
vendor: string;
pack: string;
version?: string;
}

export const parsePackString = (packString: string): Pack | undefined => {
let parts = packString.split(MAIN_DELIMITER);

if (parts.length < 2) {
return undefined;
}

const vendor = parts[0];
let pack = parts[1];

parts = pack.split(VERSION_DELIMITER);
let version: string | undefined;

if (parts.length > 1) {
pack = parts[0];
version = parts[1];
}

return {
vendor,
pack,
version
};
};

export const pdscFromPack = (basePath: string, pack: Pack): vscode.Uri => {
const pdscFile = `${pack.vendor}.${pack.pack}.pdsc`;
return fileFromPack(basePath, pack, pdscFile);
};

export const fileFromPack = (basePath: string, pack: Pack, file: string): vscode.Uri => {
if (!pack.version) {
throw new Error('CMSIS pack version is required');
}

const baseUri = vscode.Uri.parse(basePath);
return vscode.Uri.joinPath(baseUri, pack.vendor, pack.pack, pack.version, file);
};
185 changes: 185 additions & 0 deletions src/cmsis-pack/pdsc.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,185 @@
/**
* Copyright (C) 2023 Arm Limited
*/

/**
* Interface describing raw PDSC data returned from xml2js
*/
export interface PDSC {
package: {
devices?: Array<{
family: DeviceFamily[];
}>;
};
}

export interface DeviceProperties {
processor?: Array<{
$: {
Pname: string;
Punits: string;
Dclock: string;
DcoreVersion: string;
};
}>;
debug?: Array<{
$?: {
__dp?: string;
__ap?: string;
__apid?: string;
address?: string;
svd?: string;
Pname?: string;
Punit?: string;
defaultResetSequence?: string;
};
}>;
}

export interface DeviceVariant extends DeviceProperties {
$: {
Dvariant: string;
Dname: string;
};
}

export interface Device extends DeviceProperties {
$: {
Dname: string;
};
variant?: DeviceVariant[];
}

export interface DeviceSubFamily extends DeviceProperties {
$: {
DsubFamily: string;
};
device?: Device[];
}

export interface DeviceFamily extends DeviceProperties {
$: {
Dfamily: string;
Dvendor: string;
};
subFamily?: DeviceSubFamily[];
device?: Device[];
}

// Return whether an item is an object
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const isObject = (item: any): boolean => item && typeof item === 'object' && !Array.isArray(item);

// Merge two objects recursively, with source overwriting target when there's a conflict
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const deepMerge = <T extends { [key: string]: any }>(target: { [key: string]: any }, source: T): T => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
const output = Object.assign({} as any, target);

Object.keys(source).forEach(key => {
if (isObject(source[key]) && key in target) {
output[key] = deepMerge(target[key], source[key]);
} else {
Object.assign(output, { [key]: source[key] });
}
});

return output;
};

// Recurse DeviceFamily and DeviceSubFamily to find Devices and DeviceVariants, merging them as we go
export const getDevices = (pack: PDSC): Array<Device | DeviceVariant> => {
const result: Device[] = [];

const addDevice = (device: Device, parent: DeviceProperties = {}) => {
const entry = deepMerge(parent, device);
result.push(entry);
};

const walkDevices = (devices?: Device[], parent: DeviceProperties = {}) => {
if (devices) {
for (const device of devices) {
if (device.variant) {
// If there are variants, add them instead of the parent device
for (const variant of device.variant) {
// Merge in device
const variantParent = deepMerge(parent, device);
addDevice(variant, variantParent);
}
} else {
addDevice(device, parent);
}
}
}
};

// Walk the DeviceFamily array
if (pack.package.devices) {
for (const device of pack.package.devices) {
for (const family of device.family) {
walkDevices(family.device, family);

// Walk the DeviceSubFamily array
if (family.subFamily) {
for (const sub of family.subFamily) {
const parent = deepMerge(family, sub);
walkDevices(sub.device, parent);
}
}
}
}
}

return result;
};

/**
* Return list of processor names available for specified device
*/
export const getProcessors = (device: Device): string[] => {
const processors: string[] = [];

if (device.processor) {
for (const processor of device.processor) {
if (processor.$ && processor.$.Pname) {
processors.push(processor.$.Pname);
}
}
}

return processors;
};

/**
* Return svd path (or undefined) for specified device
* If processorName specified, matching svd file is returned, else the first one
*/
export const getSvdPath = (device: Device, processorName?: string): string | undefined => {
if (device.debug) {
const filtered = filterByProcessor(device.debug, processorName);
for (const debug of filtered) {
if (debug.$ && debug.$.svd) {
return debug.$.svd;
}
}
}

return undefined;
};

const filterByProcessor = <T extends { $?: { Pname?: string } }>(theArray: T[], processorName: string | undefined): T[] => {
// If processorName not specified, return all items
if (!processorName) {
return theArray;
}

return filter(theArray, item => item.$?.Pname === processorName) as T[];
};

// eslint-disable-next-line @typescript-eslint/no-explicit-any
const filter = <T extends { $?: { [key: string]: any } }>(theArray: T[], predicate: (item: T) => boolean): T[] => {
const filtered = theArray.filter(item => item.$ && predicate(item));

// If no items match, return them all
return filtered.length > 0 ? filtered as T[] : theArray;
};
24 changes: 5 additions & 19 deletions src/debug-tracker.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,5 @@
/*
* Copyright 2017-2019 Marcel Ball
* https://github.com/Marus/cortex-debug
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
/**
* Copyright (C) 2023 Arm Limited
*/

import * as vscode from 'vscode';
Expand All @@ -28,8 +14,8 @@ export class DebugTracker {
private _onWillStopSession: vscode.EventEmitter<vscode.DebugSession> = new vscode.EventEmitter<vscode.DebugSession>();
public readonly onWillStopSession: vscode.Event<vscode.DebugSession> = this._onWillStopSession.event;

private _onDidStopSession: vscode.EventEmitter<vscode.DebugSession> = new vscode.EventEmitter<vscode.DebugSession>();
public readonly onDidStopSession: vscode.Event<vscode.DebugSession> = this._onDidStopSession.event;
private _onDidStopDebug: vscode.EventEmitter<vscode.DebugSession> = new vscode.EventEmitter<vscode.DebugSession>();
public readonly onDidStopDebug: vscode.Event<vscode.DebugSession> = this._onDidStopDebug.event;

public async activate(context: vscode.ExtensionContext): Promise<void> {
const createDebugAdapterTracker = (session: vscode.DebugSession): vscode.DebugAdapterTracker => {
Expand All @@ -38,7 +24,7 @@ export class DebugTracker {
onWillStopSession: () => this._onWillStopSession.fire(session),
onDidSendMessage: message => {
if (message.type === 'event' && message.event === 'stopped') {
this._onDidStopSession.fire(session);
this._onDidStopDebug.fire(session);
}
}
};
Expand Down
10 changes: 8 additions & 2 deletions src/desktop/extension.ts
Original file line number Diff line number Diff line change
@@ -1,13 +1,19 @@
/**
* Copyright (C) 2023 Arm Limited
*/

import * as vscode from 'vscode';
import { PeripheralTreeProvider } from '../views/peripheral';
import { Commands } from '../commands';
import { DebugTracker } from '../debug-tracker';
import { SvdRegistry } from '../svd-registry';
import { SvdResolver } from '../svd-resolver';

export const activate = async (context: vscode.ExtensionContext): Promise<SvdRegistry> => {
const registry = new SvdRegistry();
const tracker = new DebugTracker();
const peripheralTree = new PeripheralTreeProvider(tracker, registry);
const registry = new SvdRegistry();
const resolver = new SvdResolver(registry);
const peripheralTree = new PeripheralTreeProvider(tracker, resolver);
const commands = new Commands(peripheralTree);

await tracker.activate(context);
Expand Down
24 changes: 7 additions & 17 deletions src/manifest.ts
Original file line number Diff line number Diff line change
@@ -1,25 +1,15 @@
/*
* Copyright 2017-2019 Marcel Ball
* https://github.com/Marus/cortex-debug
*
* Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
* documentation files (the "Software"), to deal in the Software without restriction, including without
* limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the
* Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
* TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF
* CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
* IN THE SOFTWARE.
/**
* Copyright (C) 2023 Arm Limited
*/

export const PACKAGE_NAME = 'svd-viewer';
export const CONFIG_SVD_PATH = 'svdPathConfig';
export const DEFAULT_SVD_PATH = 'svdPath';
export const CONFIG_DEVICE = 'deviceConfig';
export const DEFAULT_DEVICE = 'device';
export const DEFAULT_DEVICE = 'deviceName';
export const CONFIG_PROCESSOR = 'processorConfig';
export const DEFAULT_PROCESSOR = 'processorName';
export const CONFIG_ADDRGAP = 'svdAddrGapThreshold';
export const DEFAULT_ADDRGAP = 16;
export const CONFIG_ASSET_PATH = 'packAssetUrl';
export const DEFAULT_ASSET_PATH = 'https://pack-asset-service.keil.arm.com';
Loading

0 comments on commit c0707fd

Please sign in to comment.