siglent-sdg-mcp 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +467 -0
- package/build/connection.d.ts +29 -0
- package/build/connection.js +252 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +52 -0
- package/build/tools/arbitrary.d.ts +2 -0
- package/build/tools/arbitrary.js +83 -0
- package/build/tools/basic-wave.d.ts +2 -0
- package/build/tools/basic-wave.js +172 -0
- package/build/tools/burst.d.ts +2 -0
- package/build/tools/burst.js +191 -0
- package/build/tools/connection.d.ts +2 -0
- package/build/tools/connection.js +90 -0
- package/build/tools/modulation.d.ts +2 -0
- package/build/tools/modulation.js +200 -0
- package/build/tools/output.d.ts +2 -0
- package/build/tools/output.js +87 -0
- package/build/tools/scpi.d.ts +2 -0
- package/build/tools/scpi.js +65 -0
- package/build/tools/sweep.d.ts +2 -0
- package/build/tools/sweep.js +221 -0
- package/build/tools/utility.d.ts +2 -0
- package/build/tools/utility.js +126 -0
- package/package.json +49 -0
|
@@ -0,0 +1,191 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { connection } from "../connection.js";
|
|
3
|
+
export function registerBurstTools(server) {
|
|
4
|
+
server.tool("get_burst", "Get the burst wave parameters of a channel, including state, period, trigger source, burst mode (gate/ncycle), cycle count, carrier settings, and delay.", {
|
|
5
|
+
channel: z.enum(["C1", "C2"]).describe("Channel to query"),
|
|
6
|
+
}, { readOnlyHint: true }, async ({ channel }) => {
|
|
7
|
+
try {
|
|
8
|
+
const response = await connection.query(`${channel}:BTWV?`);
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: response,
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: "text",
|
|
23
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
server.tool("configure_burst", "Configure burst mode on a channel. State must be set to ON before other parameters. Builds a single BTWV command with all specified parameters.", {
|
|
31
|
+
channel: z.enum(["C1", "C2"]).describe("Channel to configure"),
|
|
32
|
+
state: z
|
|
33
|
+
.enum(["ON", "OFF"])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Burst state. Must be ON before setting other params."),
|
|
36
|
+
period: z
|
|
37
|
+
.number()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Burst period in seconds"),
|
|
40
|
+
start_phase: z
|
|
41
|
+
.number()
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Start phase in degrees (0-360)"),
|
|
44
|
+
burst_mode: z
|
|
45
|
+
.enum(["GATE", "NCYC"])
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Burst mode: GATE or NCYC (N-cycle)"),
|
|
48
|
+
trigger_source: z
|
|
49
|
+
.enum(["EXT", "INT", "MAN"])
|
|
50
|
+
.optional()
|
|
51
|
+
.describe("Trigger source"),
|
|
52
|
+
trigger_out: z
|
|
53
|
+
.enum(["RISE", "FALL", "OFF"])
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("Trigger output mode (when NCYC and INT/MAN)"),
|
|
56
|
+
trigger_edge: z
|
|
57
|
+
.enum(["RISE", "FALL"])
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("Trigger edge (when EXT or MAN)"),
|
|
60
|
+
cycles: z
|
|
61
|
+
.string()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("Number of burst cycles (integer, or 'INF' for infinite)"),
|
|
64
|
+
delay: z
|
|
65
|
+
.number()
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("Trigger delay in seconds (when NCYC mode)"),
|
|
68
|
+
gate_polarity: z
|
|
69
|
+
.enum(["NEG", "POS"])
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Gate polarity (when GATE mode)"),
|
|
72
|
+
manual_trigger: z
|
|
73
|
+
.boolean()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Send a manual trigger (only when trigger source is MAN)"),
|
|
76
|
+
carrier_waveform: z
|
|
77
|
+
.enum(["SINE", "SQUARE", "RAMP", "ARB", "PULSE", "NOISE"])
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Carrier waveform type"),
|
|
80
|
+
carrier_frequency: z
|
|
81
|
+
.number()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Carrier frequency in Hz"),
|
|
84
|
+
carrier_amplitude: z
|
|
85
|
+
.number()
|
|
86
|
+
.optional()
|
|
87
|
+
.describe("Carrier amplitude in Vpp"),
|
|
88
|
+
carrier_offset: z
|
|
89
|
+
.number()
|
|
90
|
+
.optional()
|
|
91
|
+
.describe("Carrier DC offset in volts"),
|
|
92
|
+
carrier_phase: z
|
|
93
|
+
.number()
|
|
94
|
+
.optional()
|
|
95
|
+
.describe("Carrier phase in degrees (0-360)"),
|
|
96
|
+
carrier_duty: z
|
|
97
|
+
.number()
|
|
98
|
+
.optional()
|
|
99
|
+
.describe("Carrier duty cycle in % (for SQUARE or PULSE)"),
|
|
100
|
+
carrier_symmetry: z
|
|
101
|
+
.number()
|
|
102
|
+
.optional()
|
|
103
|
+
.describe("Carrier symmetry in % (for RAMP)"),
|
|
104
|
+
}, { readOnlyHint: false }, async ({ channel, state, period, start_phase, burst_mode, trigger_source, trigger_out, trigger_edge, cycles, delay, gate_polarity, manual_trigger, carrier_waveform, carrier_frequency, carrier_amplitude, carrier_offset, carrier_phase, carrier_duty, carrier_symmetry, }) => {
|
|
105
|
+
try {
|
|
106
|
+
const sent = [];
|
|
107
|
+
// State must be set first and separately
|
|
108
|
+
if (state) {
|
|
109
|
+
const cmd = `${channel}:BTWV STATE,${state}`;
|
|
110
|
+
await connection.sendCommand(cmd);
|
|
111
|
+
sent.push(cmd);
|
|
112
|
+
}
|
|
113
|
+
// Build remaining parameters
|
|
114
|
+
const parts = [];
|
|
115
|
+
if (period !== undefined)
|
|
116
|
+
parts.push(`PRD,${period}`);
|
|
117
|
+
if (start_phase !== undefined)
|
|
118
|
+
parts.push(`STPS,${start_phase}`);
|
|
119
|
+
if (burst_mode)
|
|
120
|
+
parts.push(`GATE_NCYC,${burst_mode}`);
|
|
121
|
+
if (trigger_source)
|
|
122
|
+
parts.push(`TRSR,${trigger_source}`);
|
|
123
|
+
if (trigger_out)
|
|
124
|
+
parts.push(`TRMD,${trigger_out}`);
|
|
125
|
+
if (trigger_edge)
|
|
126
|
+
parts.push(`EDGE,${trigger_edge}`);
|
|
127
|
+
if (cycles !== undefined)
|
|
128
|
+
parts.push(`TIME,${cycles}`);
|
|
129
|
+
if (delay !== undefined)
|
|
130
|
+
parts.push(`DLAY,${delay}`);
|
|
131
|
+
if (gate_polarity)
|
|
132
|
+
parts.push(`PLRT,${gate_polarity}`);
|
|
133
|
+
if (carrier_waveform)
|
|
134
|
+
parts.push(`CARR,WVTP,${carrier_waveform}`);
|
|
135
|
+
if (carrier_frequency !== undefined)
|
|
136
|
+
parts.push(`CARR,FRQ,${carrier_frequency}`);
|
|
137
|
+
if (carrier_amplitude !== undefined)
|
|
138
|
+
parts.push(`CARR,AMP,${carrier_amplitude}`);
|
|
139
|
+
if (carrier_offset !== undefined)
|
|
140
|
+
parts.push(`CARR,OFST,${carrier_offset}`);
|
|
141
|
+
if (carrier_phase !== undefined)
|
|
142
|
+
parts.push(`CARR,PHSE,${carrier_phase}`);
|
|
143
|
+
if (carrier_duty !== undefined)
|
|
144
|
+
parts.push(`CARR,DUTY,${carrier_duty}`);
|
|
145
|
+
if (carrier_symmetry !== undefined)
|
|
146
|
+
parts.push(`CARR,SYM,${carrier_symmetry}`);
|
|
147
|
+
if (parts.length > 0) {
|
|
148
|
+
const cmd = `${channel}:BTWV ${parts.join(",")}`;
|
|
149
|
+
await connection.sendCommand(cmd);
|
|
150
|
+
sent.push(cmd);
|
|
151
|
+
}
|
|
152
|
+
// Manual trigger sent separately
|
|
153
|
+
if (manual_trigger) {
|
|
154
|
+
const cmd = `${channel}:BTWV MTRIG`;
|
|
155
|
+
await connection.sendCommand(cmd);
|
|
156
|
+
sent.push(cmd);
|
|
157
|
+
}
|
|
158
|
+
if (sent.length === 0) {
|
|
159
|
+
return {
|
|
160
|
+
content: [
|
|
161
|
+
{
|
|
162
|
+
type: "text",
|
|
163
|
+
text: "Error: At least one parameter must be specified.",
|
|
164
|
+
},
|
|
165
|
+
],
|
|
166
|
+
isError: true,
|
|
167
|
+
};
|
|
168
|
+
}
|
|
169
|
+
return {
|
|
170
|
+
content: [
|
|
171
|
+
{
|
|
172
|
+
type: "text",
|
|
173
|
+
text: `Burst configured:\n${sent.join("\n")}`,
|
|
174
|
+
},
|
|
175
|
+
],
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
return {
|
|
180
|
+
content: [
|
|
181
|
+
{
|
|
182
|
+
type: "text",
|
|
183
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
184
|
+
},
|
|
185
|
+
],
|
|
186
|
+
isError: true,
|
|
187
|
+
};
|
|
188
|
+
}
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
//# sourceMappingURL=burst.js.map
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { connection } from "../connection.js";
|
|
3
|
+
export function registerConnectionTools(server) {
|
|
4
|
+
server.tool("connect", "Connect to a Siglent SDG waveform generator over TCP. Returns device identification on success.", {
|
|
5
|
+
host: z
|
|
6
|
+
.string()
|
|
7
|
+
.optional()
|
|
8
|
+
.describe("IP address of the waveform generator (defaults to SIGLENT_SDG_IP or SIGLENT_IP env var)"),
|
|
9
|
+
port: z
|
|
10
|
+
.number()
|
|
11
|
+
.optional()
|
|
12
|
+
.describe("TCP port (defaults to 5025)"),
|
|
13
|
+
}, { readOnlyHint: false, openWorldHint: true }, async ({ host, port }) => {
|
|
14
|
+
const targetHost = host || process.env.SIGLENT_SDG_IP || process.env.SIGLENT_IP;
|
|
15
|
+
if (!targetHost) {
|
|
16
|
+
return {
|
|
17
|
+
content: [
|
|
18
|
+
{
|
|
19
|
+
type: "text",
|
|
20
|
+
text: "Error: No host specified. Provide a 'host' parameter or set the SIGLENT_SDG_IP environment variable.",
|
|
21
|
+
},
|
|
22
|
+
],
|
|
23
|
+
isError: true,
|
|
24
|
+
};
|
|
25
|
+
}
|
|
26
|
+
try {
|
|
27
|
+
const idn = await connection.connect(targetHost, port);
|
|
28
|
+
return {
|
|
29
|
+
content: [
|
|
30
|
+
{
|
|
31
|
+
type: "text",
|
|
32
|
+
text: `Connected to ${targetHost}:${port || 5025}\nDevice: ${idn}`,
|
|
33
|
+
},
|
|
34
|
+
],
|
|
35
|
+
};
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
return {
|
|
39
|
+
content: [
|
|
40
|
+
{
|
|
41
|
+
type: "text",
|
|
42
|
+
text: `Connection failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
43
|
+
},
|
|
44
|
+
],
|
|
45
|
+
isError: true,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
server.tool("disconnect", "Disconnect from the waveform generator.", {}, { readOnlyHint: false }, async () => {
|
|
50
|
+
const info = connection.getConnectionInfo();
|
|
51
|
+
connection.disconnect();
|
|
52
|
+
return {
|
|
53
|
+
content: [
|
|
54
|
+
{ type: "text", text: `Disconnected from ${info}` },
|
|
55
|
+
],
|
|
56
|
+
};
|
|
57
|
+
});
|
|
58
|
+
server.tool("identify", "Query the waveform generator identification (*IDN?). Returns manufacturer, model, serial number, and firmware version.", {}, { readOnlyHint: true }, async () => {
|
|
59
|
+
try {
|
|
60
|
+
const idn = await connection.query("*IDN?");
|
|
61
|
+
const parts = idn.split(",");
|
|
62
|
+
const result = {
|
|
63
|
+
manufacturer: parts[0]?.trim() || "Unknown",
|
|
64
|
+
model: parts[1]?.trim() || "Unknown",
|
|
65
|
+
serial: parts[2]?.trim() || "Unknown",
|
|
66
|
+
firmware: parts[3]?.trim() || "Unknown",
|
|
67
|
+
};
|
|
68
|
+
return {
|
|
69
|
+
content: [
|
|
70
|
+
{
|
|
71
|
+
type: "text",
|
|
72
|
+
text: JSON.stringify(result, null, 2),
|
|
73
|
+
},
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
return {
|
|
79
|
+
content: [
|
|
80
|
+
{
|
|
81
|
+
type: "text",
|
|
82
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
83
|
+
},
|
|
84
|
+
],
|
|
85
|
+
isError: true,
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
//# sourceMappingURL=connection.js.map
|
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { connection } from "../connection.js";
|
|
3
|
+
export function registerModulationTools(server) {
|
|
4
|
+
server.tool("get_modulation", "Get the modulation parameters of a channel. Returns all modulation settings including type, source, frequency, depth/deviation, and carrier parameters.", {
|
|
5
|
+
channel: z.enum(["C1", "C2"]).describe("Channel to query"),
|
|
6
|
+
}, { readOnlyHint: true }, async ({ channel }) => {
|
|
7
|
+
try {
|
|
8
|
+
const response = await connection.query(`${channel}:MDWV?`);
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: response,
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: "text",
|
|
23
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
server.tool("configure_modulation", "Configure modulation on a channel. Set state first (ON), then type and parameters. Commands are sent sequentially: state, then type, then type-specific parameters, then carrier parameters.", {
|
|
31
|
+
channel: z.enum(["C1", "C2"]).describe("Channel to configure"),
|
|
32
|
+
state: z
|
|
33
|
+
.enum(["ON", "OFF"])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Modulation state. Must be ON before setting other params."),
|
|
36
|
+
type: z
|
|
37
|
+
.enum(["AM", "DSBAM", "FM", "PM", "PWM", "ASK", "FSK", "PSK"])
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Modulation type"),
|
|
40
|
+
source: z
|
|
41
|
+
.enum(["INT", "EXT", "CH1", "CH2"])
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Modulation source (availability depends on type)"),
|
|
44
|
+
mod_wave: z
|
|
45
|
+
.enum(["SINE", "SQUARE", "TRIANGLE", "UPRAMP", "DNRAMP", "NOISE", "ARB"])
|
|
46
|
+
.optional()
|
|
47
|
+
.describe("Modulating waveform shape (only when source is INT)"),
|
|
48
|
+
frequency: z
|
|
49
|
+
.number()
|
|
50
|
+
.optional()
|
|
51
|
+
.describe("Modulation frequency in Hz (AM/FM/PM/PWM) or key frequency (ASK/FSK/PSK)"),
|
|
52
|
+
depth: z
|
|
53
|
+
.number()
|
|
54
|
+
.optional()
|
|
55
|
+
.describe("AM modulation depth in % (0-120)"),
|
|
56
|
+
deviation: z
|
|
57
|
+
.number()
|
|
58
|
+
.optional()
|
|
59
|
+
.describe("FM frequency deviation in Hz, or PM phase deviation in degrees (0-360), or PWM duty deviation in %"),
|
|
60
|
+
hop_frequency: z
|
|
61
|
+
.number()
|
|
62
|
+
.optional()
|
|
63
|
+
.describe("FSK hop frequency in Hz"),
|
|
64
|
+
polarity: z
|
|
65
|
+
.enum(["POS", "NEG"])
|
|
66
|
+
.optional()
|
|
67
|
+
.describe("PSK polarity"),
|
|
68
|
+
carrier_waveform: z
|
|
69
|
+
.enum(["SINE", "SQUARE", "RAMP", "ARB", "PULSE"])
|
|
70
|
+
.optional()
|
|
71
|
+
.describe("Carrier waveform type"),
|
|
72
|
+
carrier_frequency: z
|
|
73
|
+
.number()
|
|
74
|
+
.optional()
|
|
75
|
+
.describe("Carrier frequency in Hz"),
|
|
76
|
+
carrier_amplitude: z
|
|
77
|
+
.number()
|
|
78
|
+
.optional()
|
|
79
|
+
.describe("Carrier amplitude in Vpp"),
|
|
80
|
+
carrier_offset: z
|
|
81
|
+
.number()
|
|
82
|
+
.optional()
|
|
83
|
+
.describe("Carrier DC offset in volts"),
|
|
84
|
+
carrier_phase: z
|
|
85
|
+
.number()
|
|
86
|
+
.optional()
|
|
87
|
+
.describe("Carrier phase in degrees (0-360)"),
|
|
88
|
+
}, { readOnlyHint: false }, async ({ channel, state, type, source, mod_wave, frequency, depth, deviation, hop_frequency, polarity, carrier_waveform, carrier_frequency, carrier_amplitude, carrier_offset, carrier_phase, }) => {
|
|
89
|
+
try {
|
|
90
|
+
const sent = [];
|
|
91
|
+
// 1. Set state first
|
|
92
|
+
if (state) {
|
|
93
|
+
const cmd = `${channel}:MDWV STATE,${state}`;
|
|
94
|
+
await connection.sendCommand(cmd);
|
|
95
|
+
sent.push(cmd);
|
|
96
|
+
}
|
|
97
|
+
// 2. Set modulation type
|
|
98
|
+
if (type) {
|
|
99
|
+
const cmd = `${channel}:MDWV ${type}`;
|
|
100
|
+
await connection.sendCommand(cmd);
|
|
101
|
+
sent.push(cmd);
|
|
102
|
+
}
|
|
103
|
+
// 3. Set type-specific parameters
|
|
104
|
+
const modType = type || "AM"; // Use provided type or default for param prefix
|
|
105
|
+
if (source) {
|
|
106
|
+
const cmd = `${channel}:MDWV ${modType},SRC,${source}`;
|
|
107
|
+
await connection.sendCommand(cmd);
|
|
108
|
+
sent.push(cmd);
|
|
109
|
+
}
|
|
110
|
+
if (mod_wave) {
|
|
111
|
+
const cmd = `${channel}:MDWV ${modType},MDSP,${mod_wave}`;
|
|
112
|
+
await connection.sendCommand(cmd);
|
|
113
|
+
sent.push(cmd);
|
|
114
|
+
}
|
|
115
|
+
if (frequency !== undefined) {
|
|
116
|
+
const freqParam = ["ASK", "FSK", "PSK"].includes(modType) ? "KFRQ" : "FRQ";
|
|
117
|
+
const cmd = `${channel}:MDWV ${modType},${freqParam},${frequency}`;
|
|
118
|
+
await connection.sendCommand(cmd);
|
|
119
|
+
sent.push(cmd);
|
|
120
|
+
}
|
|
121
|
+
if (depth !== undefined) {
|
|
122
|
+
const cmd = `${channel}:MDWV ${modType},DEPTH,${depth}`;
|
|
123
|
+
await connection.sendCommand(cmd);
|
|
124
|
+
sent.push(cmd);
|
|
125
|
+
}
|
|
126
|
+
if (deviation !== undefined) {
|
|
127
|
+
const cmd = `${channel}:MDWV ${modType},DEVI,${deviation}`;
|
|
128
|
+
await connection.sendCommand(cmd);
|
|
129
|
+
sent.push(cmd);
|
|
130
|
+
}
|
|
131
|
+
if (hop_frequency !== undefined) {
|
|
132
|
+
const cmd = `${channel}:MDWV FSK,HFRQ,${hop_frequency}`;
|
|
133
|
+
await connection.sendCommand(cmd);
|
|
134
|
+
sent.push(cmd);
|
|
135
|
+
}
|
|
136
|
+
if (polarity) {
|
|
137
|
+
const cmd = `${channel}:MDWV PSK,PLRT,${polarity}`;
|
|
138
|
+
await connection.sendCommand(cmd);
|
|
139
|
+
sent.push(cmd);
|
|
140
|
+
}
|
|
141
|
+
// 4. Set carrier parameters
|
|
142
|
+
if (carrier_waveform) {
|
|
143
|
+
const cmd = `${channel}:MDWV CARR,WVTP,${carrier_waveform}`;
|
|
144
|
+
await connection.sendCommand(cmd);
|
|
145
|
+
sent.push(cmd);
|
|
146
|
+
}
|
|
147
|
+
if (carrier_frequency !== undefined) {
|
|
148
|
+
const cmd = `${channel}:MDWV CARR,FRQ,${carrier_frequency}`;
|
|
149
|
+
await connection.sendCommand(cmd);
|
|
150
|
+
sent.push(cmd);
|
|
151
|
+
}
|
|
152
|
+
if (carrier_amplitude !== undefined) {
|
|
153
|
+
const cmd = `${channel}:MDWV CARR,AMP,${carrier_amplitude}`;
|
|
154
|
+
await connection.sendCommand(cmd);
|
|
155
|
+
sent.push(cmd);
|
|
156
|
+
}
|
|
157
|
+
if (carrier_offset !== undefined) {
|
|
158
|
+
const cmd = `${channel}:MDWV CARR,OFST,${carrier_offset}`;
|
|
159
|
+
await connection.sendCommand(cmd);
|
|
160
|
+
sent.push(cmd);
|
|
161
|
+
}
|
|
162
|
+
if (carrier_phase !== undefined) {
|
|
163
|
+
const cmd = `${channel}:MDWV CARR,PHSE,${carrier_phase}`;
|
|
164
|
+
await connection.sendCommand(cmd);
|
|
165
|
+
sent.push(cmd);
|
|
166
|
+
}
|
|
167
|
+
if (sent.length === 0) {
|
|
168
|
+
return {
|
|
169
|
+
content: [
|
|
170
|
+
{
|
|
171
|
+
type: "text",
|
|
172
|
+
text: "Error: At least one parameter must be specified.",
|
|
173
|
+
},
|
|
174
|
+
],
|
|
175
|
+
isError: true,
|
|
176
|
+
};
|
|
177
|
+
}
|
|
178
|
+
return {
|
|
179
|
+
content: [
|
|
180
|
+
{
|
|
181
|
+
type: "text",
|
|
182
|
+
text: `Modulation configured:\n${sent.join("\n")}`,
|
|
183
|
+
},
|
|
184
|
+
],
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
catch (err) {
|
|
188
|
+
return {
|
|
189
|
+
content: [
|
|
190
|
+
{
|
|
191
|
+
type: "text",
|
|
192
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
193
|
+
},
|
|
194
|
+
],
|
|
195
|
+
isError: true,
|
|
196
|
+
};
|
|
197
|
+
}
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
//# sourceMappingURL=modulation.js.map
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { connection } from "../connection.js";
|
|
3
|
+
export function registerOutputTools(server) {
|
|
4
|
+
server.tool("get_output", "Get the output state of a channel, including on/off status, load impedance, and polarity.", {
|
|
5
|
+
channel: z.enum(["C1", "C2"]).describe("Channel to query"),
|
|
6
|
+
}, { readOnlyHint: true }, async ({ channel }) => {
|
|
7
|
+
try {
|
|
8
|
+
const response = await connection.query(`${channel}:OUTP?`);
|
|
9
|
+
return {
|
|
10
|
+
content: [
|
|
11
|
+
{
|
|
12
|
+
type: "text",
|
|
13
|
+
text: response,
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
catch (err) {
|
|
19
|
+
return {
|
|
20
|
+
content: [
|
|
21
|
+
{
|
|
22
|
+
type: "text",
|
|
23
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
24
|
+
},
|
|
25
|
+
],
|
|
26
|
+
isError: true,
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
});
|
|
30
|
+
server.tool("configure_output", "Configure the output of a channel. Can turn output on/off, set load impedance, and set polarity.", {
|
|
31
|
+
channel: z.enum(["C1", "C2"]).describe("Channel to configure"),
|
|
32
|
+
state: z
|
|
33
|
+
.enum(["ON", "OFF"])
|
|
34
|
+
.optional()
|
|
35
|
+
.describe("Output state: ON or OFF"),
|
|
36
|
+
load: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe("Load impedance in ohms (50-100000) or 'HZ' for high impedance"),
|
|
40
|
+
polarity: z
|
|
41
|
+
.enum(["NOR", "INVT"])
|
|
42
|
+
.optional()
|
|
43
|
+
.describe("Output polarity: NOR (normal) or INVT (inverted)"),
|
|
44
|
+
}, { readOnlyHint: false }, async ({ channel, state, load, polarity }) => {
|
|
45
|
+
try {
|
|
46
|
+
const parts = [];
|
|
47
|
+
if (state)
|
|
48
|
+
parts.push(state);
|
|
49
|
+
if (load)
|
|
50
|
+
parts.push(`LOAD,${load}`);
|
|
51
|
+
if (polarity)
|
|
52
|
+
parts.push(`PLRT,${polarity}`);
|
|
53
|
+
if (parts.length === 0) {
|
|
54
|
+
return {
|
|
55
|
+
content: [
|
|
56
|
+
{
|
|
57
|
+
type: "text",
|
|
58
|
+
text: "Error: At least one parameter (state, load, polarity) must be specified.",
|
|
59
|
+
},
|
|
60
|
+
],
|
|
61
|
+
isError: true,
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
await connection.sendCommand(`${channel}:OUTP ${parts.join(",")}`);
|
|
65
|
+
return {
|
|
66
|
+
content: [
|
|
67
|
+
{
|
|
68
|
+
type: "text",
|
|
69
|
+
text: `Output configured: ${channel}:OUTP ${parts.join(",")}`,
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
catch (err) {
|
|
75
|
+
return {
|
|
76
|
+
content: [
|
|
77
|
+
{
|
|
78
|
+
type: "text",
|
|
79
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
80
|
+
},
|
|
81
|
+
],
|
|
82
|
+
isError: true,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
});
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=output.js.map
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { connection } from "../connection.js";
|
|
3
|
+
export function registerScpiTools(server) {
|
|
4
|
+
server.tool("scpi_query", "Send an arbitrary SCPI query to the waveform generator and return the response. Use this as an escape hatch for commands not covered by other tools. Note: CHDR is set to OFF, so responses contain only values (no headers).", {
|
|
5
|
+
command: z
|
|
6
|
+
.string()
|
|
7
|
+
.describe("SCPI query command to send (e.g. '*IDN?', 'C1:BSWV?', 'C1:OUTP?')"),
|
|
8
|
+
timeout_ms: z
|
|
9
|
+
.number()
|
|
10
|
+
.optional()
|
|
11
|
+
.describe("Timeout in milliseconds (default 5000)"),
|
|
12
|
+
}, { readOnlyHint: true }, async ({ command, timeout_ms }) => {
|
|
13
|
+
try {
|
|
14
|
+
const response = await connection.query(command, timeout_ms || undefined);
|
|
15
|
+
return {
|
|
16
|
+
content: [
|
|
17
|
+
{
|
|
18
|
+
type: "text",
|
|
19
|
+
text: response,
|
|
20
|
+
},
|
|
21
|
+
],
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
catch (err) {
|
|
25
|
+
return {
|
|
26
|
+
content: [
|
|
27
|
+
{
|
|
28
|
+
type: "text",
|
|
29
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
isError: true,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
server.tool("scpi_command", "Send an arbitrary SCPI command to the waveform generator (no response expected). Use this as an escape hatch for commands not covered by other tools.", {
|
|
37
|
+
command: z
|
|
38
|
+
.string()
|
|
39
|
+
.describe("SCPI command to send (e.g. '*RST', 'C1:OUTP ON', 'C1:BSWV WVTP,SINE')"),
|
|
40
|
+
}, { readOnlyHint: false }, async ({ command }) => {
|
|
41
|
+
try {
|
|
42
|
+
await connection.sendCommand(command);
|
|
43
|
+
return {
|
|
44
|
+
content: [
|
|
45
|
+
{
|
|
46
|
+
type: "text",
|
|
47
|
+
text: `Command sent: ${command}`,
|
|
48
|
+
},
|
|
49
|
+
],
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
catch (err) {
|
|
53
|
+
return {
|
|
54
|
+
content: [
|
|
55
|
+
{
|
|
56
|
+
type: "text",
|
|
57
|
+
text: `Error: ${err instanceof Error ? err.message : String(err)}`,
|
|
58
|
+
},
|
|
59
|
+
],
|
|
60
|
+
isError: true,
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
});
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=scpi.js.map
|