#generator #signal #waveform #remote-control #arbitrary #gh-cjds66

signal-gen-cjds66-lib

一个非官方支持库,可以完全远程控制价格低廉的Koolertron DDS信号发生器,称为GH-CJDS66

8个版本

0.1.10 2021年7月12日
0.1.9 2021年1月12日

#267 in 数学

22 每月下载

自定义许可

280KB
7.5K SLoC

signal-gen-cjds66-lib

控制GH-CJDS66 60MHz信号发生器

docs crate gitlab-pipeline gitlab test coverage github-pipeline github test coverage License: MIT

https://gitlab.com/defcronyke/signal-gen-cjds66

版权所有 © 2020-2021 Jeremy Carter [email protected]

MIT许可

使用此软件即表示您同意项目顶层目录中名为LICENSE.md的文件中概述的许可条款。如果您不同意许可条款,则不允许使用此软件。

目的

这是一个非官方项目,完全实现了“酷冷tron升级版60MHz DDS信号发生器计数器,高精度双通道任意波形函数发生器频率计200MSa/s(60MHz)型号:GH-CJDS66-FU”的官方通信规范(除了一些规范错误,您可以在以下提交消息中了解: 713b026a4e10807d23f7436d26649dcc4c584019

设备和USB接口信息

制造商页面,提供购买信息
https://www.koolertron.com/koolertron-upgraded-60mhz-dds-signal-generator-counterhigh-precision-dualchannel-arbitrary-waveform-function-generator-frequency-meter-200msas-60mhz-p-867.html

Linux lsusb 输出

ID 1a86:7523 QinHeng Electronics CH340 serial converter

基本使用代码示例

入门

  • 此库作为crates.io上的Rust crate发布,以便您可以在自己的项目中轻松使用它
    https://crates.io/crates/signal-gen-cjds66-lib

  • 该crate的自动生成文档可以在docs.rs上查看
    https://docs.rs/signal-gen-cjds66-lib

  • 如果您想查看crate的master分支(开发版本)的文档,也可以下载最新的开发版本文档。此版本还包括关联的命令行程序的文档
    signal-gen-cjds66文档(开发版本)

  • 要使用此crate,请将以下行添加到您的Rust项目的Cargo.toml文件中(但请用上面crates.io链接中列出的最新版本号替换,以确保使用最新版本)

[dependencies]
signal-gen-cjds66-lib = { version = "0.1" }
  • 重要:请注意,此crate使用三部分版本号,例如0.1.7,但最好在Cargo.toml文件中省略版本号的第三部分,这样您可以更容易、更自动地更新到最新的0.1.x版本,而无需手动更新那个第三位数字。否则会很不方便,因为那个第三位数字可能需要经常更改。

代码示例 - 打印设备的型号和序列号
examples/basic-usage.rs

/*! A basic usage example for the library.  
  
Control one signal generator device on 
Linux or Windows. Print the device's 
model number and serial number.
*/

extern crate signal_gen_cjds66_lib;
extern crate clap;

use signal_gen_cjds66_lib::command::*;
use signal_gen_cjds66_lib::error;
use signal_gen_cjds66_lib::error::From;
use signal_gen_cjds66_lib::serial::*;

use clap::ErrorKind;

/// The main entrypoint.
fn main() {
	/* Call the main logic function, and save the
	result, which will either be Ok(0) on success,
	or some type of error.
	*/
	let res = real_main();

	/* Exit the program, returning an appropriate
	exit code to the parent shell or execution 
	environment. This is important so whoever
	ran this program (a bash or batch script maybe)
	can check if anything went wrong while the 
	program was running, and react accordingly.
	*/
	std::process::exit(
		/* If there was an error, get the proper
		exit code for it, to return on exit.
		*/
		error::handle_exit(res)
			.map_or_else(
				|e| e.code,	// Get the numeric error exit code (non-zero).
				
				|code| code,	// Or, get the success exit code (0).
			)
	);
}

/** The main logic area. Rust is a bit weird so it's
better in this case to have this function separate
from main().
*/
fn real_main() -> Result<i32, error::Error> {
	// An error variable, to specify if an error happened.
	let mut err: Option<error::Error> = None;

	/* Choose the serial device location depending 
	on which operating system you're using.  

	HINT: You can put more than one device location 
	in each of these arrays if you'd like to control 
	multiple devices in sequence.  

	NOTE: The values listed below are the default values
	used by the first connected serial device on my 
	Linux and Windows systems. If you get a connection
	error when you run this code, make sure your signal
	generator is plugged into your computer and powered
	on.  

	If you still have a connection error, you'll probably 
	need to find the correct path for your system and 
	change the values below so they	are pointing at the 
	correct device.
	*/
	let devices = 
		if cfg!(unix) {	// If running on Linux (or UNIX).
			vec!["/dev/ttyUSB0".to_string()]
			
		} else if cfg!(windows) {	// If running on Windows.
			vec!["COM3".to_string()]
			
		} else {	// If unsure of the operating system.
			vec!["/dev/ttyUSB0".to_string()]
		};

	/* Iterate over each device path you configured above,
	and perform operations on each device sequentially.
	This example is only connecting to one device, but you
	can add more above if you want.
	*/ 
	for device in &devices {
		/* A new error varialbe (an alias really), borrowing a mutable 
		reference to our error variable from above, and storing it in
		an immutable binding.
		*/
		let err = &mut err;

		/* Establish a serial connection to the signal generator device,
		with all the correct communication options configured. The
		second parameter to the `SerialPortType::new()` function should 
		always be false unless we are making a fake connection for 
		testing purposes, which is currently only useful for the crate's 
		automated test suite.
		*/
		println!("\nOpening communication link with device: {}\n", device);

		let opened = SerialPortType::new(device, false).map_or_else(
			// If opening the device failed, return an error.
			|e| {
				Err(error::Error::with_description(&format!("(device: {}): {}: make sure the device is connected and turned on, or try specifying a different device path with -d /path/to/device", device, e), clap::ErrorKind::Io))
			},

			/* If the device was opened successfully, go on to run some
			commands which operate on the device.
			*/
			|mut port| {
				// A new error variable, just for this inner scope.
				let mut err: Option<error::Error> = None;

				/* Get the model and serial numbers from the device
				(verbose version). The second parameter on the 
				`get_model_and_serial()` function enables 
				"verbose output mode" when you pass in a number 
				higher than 0.  
				  
				Note that this function, and all the other ones 
				which communicate with the signal generator, are 
				defined in the `command` module, and are imported 
				into the global scope in this file by this line 
				near the top of the file:  
				`use signal_gen_cjds66_lib::command::*;`
				*/
				println!("\nGetting the device's model number and serial number, with verbose output mode enabled...\n");

				get_model_and_serial(&mut port, 1)
					.map_err(
						|e| {
							// If there was a problem, report the error.
							err = Some(error::Error::from_clap_error(e));
							println!("{}", err.as_ref().unwrap());
						}
					)
					.unwrap();

				/* Get model and serial number from the device
				(non verbose version). Notice the second 
				parameter to the `get_model_and_serial()` 
				function below is 0 this time, which turns off
				"verbose output mode".  
				  
				NOTE: Every function in the `command` module 
				accepts the same type of "verbose" parameter,
				although it's not always the second parameter,
				rather, it's usually the last one.
				*/
				println!("\nGetting the device's model number and serial number, with verbose output mode disabled...\n");

				get_model_and_serial(&mut port, 0)
					.map_err(
						|e| {
							// If there was a problem, report the error.
							err = Some(error::Error::from_clap_error(e));
							println!("{}", err.as_ref().unwrap());
						}
					)
					.unwrap();

				println!("");	// Line break for nicer output.

				/* Return Ok(0) on success, or an error if there were
				any.
				*/
				err.map_or_else(|| { Ok(0) }, |v| { Err(v) })
			},
		);

		/* If we can't connect to a certain device, skip it and continue 
		with any remaining devices we haven't tried yet.
		*/
		if opened.is_err() {
			*err = opened.map_or_else(
				|e| {
					// If there was a problem, report the error.
					if e.kind == ErrorKind::Io {
						println!("{}", e);
					}

					Some(e)
				},

				|_val| None,
			);

			continue;
		}
	}

	/* If there was a problem during any of the above operations, 
	return the error to the parent function.
	*/
	if err.is_some() {
		Err(err.unwrap())

	} else {	// Otherwise, return Ok(0) to indicate success.
		Ok(0)
	}
}

注意:上述示例可以在文件signal-gen-cjds66-lib/examples/basic-usage.rs中找到,如果您想尝试运行它,可以从signal-gen-cjds66-lib/目录下执行以下命令

cargo run --release --example basic-usage

依赖项

~3.5MB
~65K SLoC