添加“scpi指令编辑功能”示例

This commit is contained in:
CSSC-WORK\murmur 2024-12-04 20:27:46 +08:00
parent d983067837
commit 6e308647c5
8 changed files with 566 additions and 0 deletions

153
visa-scpi-example/File.cpp Normal file
View File

@ -0,0 +1,153 @@
// C++ script created by FSW: 04:12:2024 14:23:36
#include <string>
#include <iostream>
#include <visa.h>
// forward declarations
static bool write_command(const ViSession& handle, const std::string& command);
static bool write_query(const ViSession& handle, const std::string& query, ViPBuf result_buffer, const ViUInt32 buffer_size, ViPUInt32 read_count = nullptr);
static bool process_system_error(const ViSession& handle);
static unsigned char get_esr(const ViSession& handle);
static ViSession g_analyzer;
// assign your own variables
static ViByte g_result[1000000];
static bool write_command( const ViSession& handle, const std::string& command )
{
ViStatus status = viWrite(handle, (ViBuf)command.c_str(), command.length(), VI_NULL);
// return true if successful
return ((status >= VI_SUCCESS) && process_system_error(handle));
}
static bool write_query( const ViSession& handle, const std::string& query, ViPBuf result_buffer, const ViUInt32 buffer_size, ViPUInt32 read_count )
{
ViStatus status = viWrite(handle, (ViBuf)query.c_str(), query.length(), VI_NULL);
if (status >= VI_SUCCESS)
{
status = viRead(handle, result_buffer, buffer_size, read_count);
}
// return true if successful
return ((status >= VI_SUCCESS) && process_system_error(handle));
}
static bool process_system_error(const ViSession& handle)
{
bool success = true;
const unsigned char EsrErrorMask = 0x3C;
if ((get_esr(handle) & EsrErrorMask) != 0)
{
char err_buf[256];
ViUInt32 readCount;
viWrite(handle, (ViBuf)":SYST:ERR?", 10, VI_NULL);
viRead(handle, (ViPBuf)err_buf, sizeof(err_buf), &readCount);
err_buf[readCount] = '\0';
std::cout << err_buf << std::endl;
viWrite(handle, (ViBuf)"*CLS", 4, VI_NULL);
success = false;
}
return success;
}
static unsigned char get_esr(const ViSession& handle)
{
char esr_buf[16];
ViUInt32 readCount;
viWrite(handle, (ViBuf)"*ESR?", 5, VI_NULL);
viRead(handle, (ViPBuf)esr_buf, sizeof(esr_buf), &readCount);
esr_buf[readCount] = '\0';
return (static_cast<unsigned char>(std::stoi(std::string(esr_buf))));
}
int main ()
{
ViSession defaultRM;
bool success = true;
// create a VISA session and return a handle to it
viOpenDefaultRM(&defaultRM);
// create a VISA session to the connected device and return a handle to it
viOpen(defaultRM, (ViRsrc)"TCPIP::169.254.177.77::inst0::INSTR", VI_NULL, VI_NULL, &g_analyzer);
success = write_command( g_analyzer, "*RST" );
success = write_command( g_analyzer, "*CLS" );
success = write_command( g_analyzer, ":SYST:DISP:UPD ON" );
success = write_command( g_analyzer, ":INIT:CONT OFF" );
success = write_command( g_analyzer, ":SENS:FREQ:STAR 1000000000" );
success = write_command( g_analyzer, ":SENS:FREQ:STOP 2000000000" );
success = write_command( g_analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV -30" );
success = write_command( g_analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV 30" );
success = write_command( g_analyzer, ":SENS:BAND:RES:AUTO OFF" );
success = write_command( g_analyzer, ":SENS:BAND:RES:AUTO ON" );
success = write_command( g_analyzer, ":SENS:BAND:VID:AUTO OFF" );
success = write_command( g_analyzer, ":SENS:BAND:VID:AUTO ON" );
success = write_command( g_analyzer, ":SENS:FREQ:MODE SWE" );
success = write_command( g_analyzer, ":DISP:WIND1:SIZE LARG" );
success = write_command( g_analyzer, ":CALC1:MARK1:FUNC:STR:STAT ON" );
success = write_command( g_analyzer, ":CALC1:MARK1:FUNC:STR:STAT OFF" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN" );
success = write_command( g_analyzer, ":SENS:POW:ACH:BAND:CHAN 300000" );
success = write_command( g_analyzer, ":SENS:POW:ACH:PRES CN" );
success = write_command( g_analyzer, ":CALC:MARK1:STAT ON" );
success = write_command( g_analyzer, ":CALC:MARK1:X 1200000000" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN" );
success = write_command( g_analyzer, ":SENS:POW:ACH:PRES CN" );
success = write_command( g_analyzer, ":SENS:POW:ACH:PRES CN" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN0" );
success = write_command( g_analyzer, ":CALC:MARK:FUNC:POW:SEL CN" );
success = write_command( g_analyzer, ":SENS:FREQ:SPAN 1000000" );
success = write_command( g_analyzer, ":SENS:FREQ:SPAN 1000000000" );
success = write_command( g_analyzer, ":CALC:MARK1:STAT ON" );
success = write_command( g_analyzer, ":CALC:MARK1:X 1200000000" );
success = write_command( g_analyzer, ":CALC:DELT2:STAT ON" );
success = write_command( g_analyzer, ":CALC:DELT2:X 1600000000" );
success = write_command( g_analyzer, ":INIT:SPUR" );
success = write_command( g_analyzer, ":MMEM:NAME 'C:\R_S\Instr\user\FSW_ScreenShot_2024-12-04_14-22-12.PNG'" );
success = write_command( g_analyzer, ":HCOP:IMM1" );
viClose(g_analyzer);
viClose(defaultRM);
return 0;
}

View File

@ -0,0 +1,35 @@
*RST
*CLS
:SYST:DISP:UPD ON
:INIT:CONT OFF
:SENS:FREQ:STAR 1000000000
:SENS:FREQ:STOP 2000000000
:DISP:WIND:TRAC:Y:SCAL:RLEV 0
:DISP:WIND:TRAC:Y:SCAL:RLEV 0
:SENS:BAND:RES:AUTO OFF
:SENS:BAND:RES:AUTO ON
:SENS:BAND:VID:AUTO OFF
:SENS:BAND:VID:AUTO ON
:SENS:FREQ:MODE SWE
:DISP:WIND1:SIZE LARG
:CALC1:MARK1:FUNC:STR:STAT ON
:CALC1:MARK1:FUNC:STR:STAT OFF
:CALC:MARK:FUNC:POW:SEL CN
:SENS:POW:ACH:BAND:CHAN 300000
:SENS:POW:ACH:PRES CN
:CALC:MARK1:STAT ON
:CALC:MARK1:X 1200000000
:CALC:MARK:FUNC:POW:SEL CN
:SENS:POW:ACH:PRES CN
:SENS:POW:ACH:PRES CN
:CALC:MARK:FUNC:POW:SEL CN0
:CALC:MARK:FUNC:POW:SEL CN
:SENS:FREQ:SPAN 1000000
:SENS:FREQ:SPAN 1000000000
:CALC:MARK1:STAT ON
:CALC:MARK1:X 1200000000
:CALC:DELT2:STAT ON
:CALC:DELT2:X 1600000000
:INIT:SPUR
:MMEM:NAME 'C:\R_S\Instr\user\FSW_ScreenShot_2024-12-04_14-22-12.PNG'
:HCOP:IMM1

109
visa-scpi-example/File.py Normal file
View File

@ -0,0 +1,109 @@
# python script created by FSW: 04:12:2024 14:23:54
import pyvisa as visa
def write_command(instrument, command) :
instrument.write(command)
return process_system_error(instrument)
def write_query(instrument, command) :
buffer = instrument.query(command)
bSuccess = process_system_error(instrument)
return bSuccess, buffer
def process_system_error(instrument) :
bSuccess = True
EsrErrorMask = 0x3C
if ((get_esr(instrument) & EsrErrorMask) != 0) :
print(instrument.query(":SYST:ERR?"))
instrument.write("*CLS")
bSuccess = False
return bSuccess
def get_esr(instrument) :
esr = instrument.query("*ESR?")
return int(esr)
VisaResourceManager = visa.ResourceManager()
# connect to analyzer
Analyzer = VisaResourceManager.open_resource("TCPIP::169.254.177.77::inst0::INSTR")
success = write_command( Analyzer, "*RST" )
success = write_command( Analyzer, "*CLS" )
success = write_command( Analyzer, ":SYST:DISP:UPD ON" )
success = write_command( Analyzer, ":INIT:CONT OFF" )
success = write_command( Analyzer, ":SENS:FREQ:STAR 1000000000" )
success = write_command( Analyzer, ":SENS:FREQ:STOP 2000000000" )
success = write_command( Analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV -30" )
success = write_command( Analyzer, ":DISP:WIND:TRAC:Y:SCAL:RLEV 30" )
success = write_command( Analyzer, ":SENS:BAND:RES:AUTO OFF" )
success = write_command( Analyzer, ":SENS:BAND:RES:AUTO ON" )
success = write_command( Analyzer, ":SENS:BAND:VID:AUTO OFF" )
success = write_command( Analyzer, ":SENS:BAND:VID:AUTO ON" )
success = write_command( Analyzer, ":SENS:FREQ:MODE SWE" )
success = write_command( Analyzer, ":DISP:WIND1:SIZE LARG" )
success = write_command( Analyzer, ":CALC1:MARK1:FUNC:STR:STAT ON" )
success = write_command( Analyzer, ":CALC1:MARK1:FUNC:STR:STAT OFF" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN" )
success = write_command( Analyzer, ":SENS:POW:ACH:BAND:CHAN 300000" )
success = write_command( Analyzer, ":SENS:POW:ACH:PRES CN" )
success = write_command( Analyzer, ":CALC:MARK1:STAT ON" )
success = write_command( Analyzer, ":CALC:MARK1:X 1200000000" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN" )
success = write_command( Analyzer, ":SENS:POW:ACH:PRES CN" )
success = write_command( Analyzer, ":SENS:POW:ACH:PRES CN" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN0" )
success = write_command( Analyzer, ":CALC:MARK:FUNC:POW:SEL CN" )
success = write_command( Analyzer, ":SENS:FREQ:SPAN 1000000" )
success = write_command( Analyzer, ":SENS:FREQ:SPAN 1000000000" )
success = write_command( Analyzer, ":CALC:MARK1:STAT ON" )
success = write_command( Analyzer, ":CALC:MARK1:X 1200000000" )
success = write_command( Analyzer, ":CALC:DELT2:STAT ON" )
success = write_command( Analyzer, ":CALC:DELT2:X 1600000000" )
success = write_command( Analyzer, ":INIT:SPUR" )
success = write_command( Analyzer, ":MMEM:NAME 'C:\R_S\Instr\user\FSW_ScreenShot_2024-12-04_14-22-12.PNG'" )
success = write_command( Analyzer, ":HCOP:IMM1" )
# back to local mode
success = write_command(Analyzer, "@LOC")
# cleanup
Analyzer.close()
VisaResourceManager.close()

View File

@ -0,0 +1,9 @@
{
":SENS:FREQ:STAR": "1000000000",
":SENS:FREQ:STOP": "2000000000",
":DISP:WIND:TRAC:Y:SCAL:RLEV": "0",
":SENS:POW:ACH:BAND:CHAN": "300000",
":CALC:MARK1:X": "1200000000",
":SENS:FREQ:SPAN": "1000000000",
":CALC:DELT2:X": "1600000000"
}

View File

@ -0,0 +1,9 @@
{
":SENS:FREQ:STAR": "\u8d77\u59cb\u9891\u7387",
":SENS:FREQ:STOP": " ",
":DISP:WIND:TRAC:Y:SCAL:RLEV": " ",
":SENS:POW:ACH:BAND:CHAN": " ",
":CALC:MARK1:X": " ",
":SENS:FREQ:SPAN": " ",
":CALC:DELT2:X": " "
}

View File

@ -0,0 +1,153 @@
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>SCPI命令参数编辑器</title>
<style>
body {
font-family: Arial, sans-serif;
margin: 0;
padding: 20px;
box-sizing: border-box;
}
.command-container {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 10px;
}
.command-row {
box-sizing: border-box;
height: inherit;
/* margin: 10px 0; */
padding: 10px ;
border: 1px solid #ddd;
border-radius: 4px;
display: flex;
flex: 1 1 30%;
flex-direction: column;
/* width: calc(30% - 20px); */
}
.comment-input {
display: inline-block;
width: 100%;
height: 100%;
padding: 5px;
border: none;
background: none;
font-size: 14px;
cursor: text;
}
.command-label {
display: inline-block;
width: auto;
font-family: monospace;
margin-top: 5px;
}
.value-input {
width: auto;
padding: 5px;
margin-top: 5px;
}
.update-btn {
width: auto;
margin-top: 10px;
padding: 5px 10px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.update-btn:hover {
background-color: #45a049;
}
</style>
</head>
<body>
<h1>SCPI命令参数编辑器</h1>
<div class="command-container" id="commands-container"></div>
<script>
async function loadCommands() {
const response = await fetch('commands.json');
const commands = await response.json();
const commentsResponse = await fetch('comments.json');
const comments = await commentsResponse.json();
const container = document.getElementById('commands-container');
for (const [command, value] of Object.entries(commands)) {
const row = document.createElement('div');
row.className = 'command-row';
const commentDisplay = document.createElement('span');
commentDisplay.className = 'comment-input';
commentDisplay.textContent = comments[command] || '';
commentDisplay.ondblclick = () => {
const commentInput = document.createElement('input');
commentInput.type = 'text';
commentInput.value = commentDisplay.textContent;
commentInput.onblur = async () => {
comments[command] = commentInput.value;
commentDisplay.textContent = commentInput.value;
row.replaceChild(commentDisplay, commentInput);
await fetch('/save_comments', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify(comments)
});
};
row.replaceChild(commentInput, commentDisplay);
commentInput.focus();
};
const label = document.createElement('span');
label.className = 'command-label';
label.textContent = command;
const input = document.createElement('input');
input.className = 'value-input';
input.type = 'text';
input.value = value;
const button = document.createElement('button');
button.className = 'update-btn';
button.textContent = '更新';
button.onclick = async () => {
if (confirm(`确认要将命令 ${command} 的参数更新为 ${input.value} 吗?`)) {
const response = await fetch('/update_command', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({
command: command,
value: input.value
})
});
if (response.ok) {
alert('更新成功!');
} else {
alert('更新失败!');
}
}
};
row.appendChild(commentDisplay);
// row.appendChild(document.createElement('br'));
row.appendChild(label);
row.appendChild(input);
row.appendChild(button);
container.appendChild(row);
}
}
window.onload = loadCommands;
</script>
</body>
</html>

View File

@ -0,0 +1,55 @@
import re
import json
import os
def parse_inp_file(file_path):
commands_dict = {}
comments_dict = {}
with open(file_path, 'r') as f:
lines = f.readlines()
for line in lines:
# 去除首尾空格并按空格分割
parts = line.strip().split(' ')
if len(parts) == 2: # 只处理有一个参数的指令
command, value = parts
# 检查参数是否为数字(包括科学计数法)
if re.match(r'^-?\d+\.?\d*([eE][-+]?\d+)?$', value):
commands_dict[command] = value
# 读取注释文件
comments_file_path = 'visa-scpi-example/comments.json'
if not os.path.exists(comments_file_path):
with open(comments_file_path, 'w') as f:
# 为空时创建一个空的注释文件将commands_dict的值以“”表示
comments_dict = {key: " " for key in commands_dict.keys()}
json.dump(comments_dict, f)
else:
with open(comments_file_path, 'r') as f:
comments_dict = json.load(f)
# 保存为JSON文件
with open('visa-scpi-example/commands.json', 'w') as f:
json.dump(commands_dict, f, indent=2)
return commands_dict, comments_dict
def save_comments(comments_dict):
with open('visa-scpi-example/comments.json', 'w') as f:
json.dump(comments_dict, f, indent=2)
def update_inp_file(file_path, command, new_value):
with open(file_path, 'r') as f:
lines = f.readlines()
updated_lines = []
for line in lines:
parts = line.strip().split(' ')
if len(parts) == 2 and parts[0] == command:
updated_lines.append(f"{command} {new_value}\n")
else:
updated_lines.append(line)
with open(file_path, 'w') as f:
f.writelines(updated_lines)

View File

@ -0,0 +1,43 @@
from flask import Flask, request, jsonify, send_from_directory
from parse_inp import parse_inp_file, update_inp_file, save_comments
import os
app = Flask(__name__)
# 确保在启动时解析inp文件
INP_FILE_PATH = 'visa-scpi-example/File.inp'
@app.route('/')
def index():
commands, comments = parse_inp_file(INP_FILE_PATH)
return send_from_directory(os.path.abspath('visa-scpi-example'), 'index.html')
@app.route('/commands.json')
def get_commands():
return send_from_directory(os.path.abspath('visa-scpi-example'), 'commands.json')
@app.route('/update_command', methods=['POST'])
def update_command():
data = request.json
try:
update_inp_file(INP_FILE_PATH, data['command'], data['value'])
# 更新后重新解析文件
parse_inp_file(INP_FILE_PATH)
return jsonify({'success': True})
except Exception as e:
return jsonify({'success': False, 'error': str(e)}), 500
@app.route('/save_comments', methods=['POST'])
def save_comments_route():
comments = request.json
save_comments(comments)
return jsonify({'success': True})
@app.route('/comments.json')
def get_comments():
return send_from_directory(os.path.abspath('visa-scpi-example'), 'comments.json')
if __name__ == '__main__':
# 启动时先解析一次文件
parse_inp_file(INP_FILE_PATH)
app.run(debug=True)