资讯专栏INFORMATION COLUMN

golang实现仪表控制-visa32.dll方式

xcold / 1135人阅读

摘要:,语言实现仪表控制可以采用种方式,一种是使用编程,使用驱动自带的文件进行开发,但是感觉怪怪的,感觉这样还不如直接使用进行开发,还有现成的版本可用。硬件信息为查询仪表清单。类型转换是必须的,的是由首字符指针长度组成。

golang,go语言实现仪表控制可以采用2种方式,一种是使用CGO编程,使用驱动自带的VISA.H文件进行开发,但是感觉怪怪的,感觉这样还不如直接使用C进行开发,还有现成的版本可用。因此本文使用的是调用dll的方式来进行。

  • 常用函数

viOpenDefaultRM:打开设备管理器,初始化。

func OpenRM() uintptr {    VISA32 := syscall.NewLazyDLL("visa32.dll")    viOpenDefaultRM := VISA32.NewProc("viOpenDefaultRM")    ret, _, _ := viOpenDefaultRM.Call(uintptr(unsafe.Pointer(&resourceManager)))    fmt.Println("硬件信息为:", resourceManager)    return ret}

viFindRsrc:查询仪表清单。

func FindRsrc() bool {    VISA32 := syscall.NewLazyDLL("visa32.dll")    viFindRsrc := VISA32.NewProc("viFindRsrc")    var list int = 0    instrDor := getMyString("?*")    var data [180]byte    retcnt := 0    ret, _, _ := viFindRsrc.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(unsafe.Pointer(&list)), uintptr(unsafe.Pointer(&retcnt)), uintptr(unsafe.Pointer(&data)))    if ret != 0 {        fmt.Println("查询代码:", ret)        return false    }    fmt.Println("查询成功->")    viFindNext := VISA32.NewProc("viFindNext")    viFindNext.Call(uintptr(list), uintptr(unsafe.Pointer(&data)))    s := string(Bytes2string(data))    viClose := VISA32.NewProc("viClose")    viClose.Call(uintptr(list))    fmt.Println(s)    return true}

viOpen:使用地址打开仪表。

    instrDor := getMyString(addr)    VISA32 := syscall.NewLazyDLL("visa32.dll")    viOpen := VISA32.NewProc("viOpen")    var instr int = 0    ret, _, _ := viOpen.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&instr)))    if instr == 0 {        return "打开仪器失败,错误代码为:" + fmt.Sprint(ret)    }

viClose:关闭设备管理器,关闭仪器清单,关闭打开的仪表(可以理解为释放内存)上面的3个函数都要。

viPrintf/viScanf:发送和接收仪表的数据

// 发送信息给仪表// addr为仪器地址,m为需要发送的信息,如GPIB0::15::INSTR,send:DISP TXfunc SendMsg(addr, m string) string {    instrDor := getMyString(addr)    VISA32 := syscall.NewLazyDLL("visa32.dll")    viOpen := VISA32.NewProc("viOpen")    var instr int = 0    ret, _, _ := viOpen.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&instr)))    if instr == 0 {        return "打开仪器失败,错误代码为:" + fmt.Sprint(ret)    }    m = m + "/n"    msg := getMyString(m)    viPrintf := VISA32.NewProc("viPrintf")    ret2, _, _ := viPrintf.Call(uintptr(instr), uintptr(unsafe.Pointer(msg.Str)))    viClose := VISA32.NewProc("viClose")    viClose.Call(uintptr(instr))    if ret2 == 0 {        return "信息发送成功!---" + m    }    return "发送失败,代码为:" + fmt.Sprint(ret2)}// 发送信息给仪表,并等待仪表返回数据。func ReadData(addr, m string) string {    instrDor := getMyString(addr)    VISA32 := syscall.NewLazyDLL("visa32.dll")    viOpen := VISA32.NewProc("viOpen")    var instr int = 0    ret, _, _ := viOpen.Call(uintptr(resourceManager), uintptr(unsafe.Pointer(instrDor.Str)), uintptr(0), uintptr(0), uintptr(unsafe.Pointer(&instr)))    if instr == 0 {        return "打开仪器失败,错误代码为:" + fmt.Sprint(ret)    }    m = m + "/n"    msg := getMyString(m)    viPrintf := VISA32.NewProc("viPrintf")    viPrintf.Call(uintptr(instr), uintptr(unsafe.Pointer(msg.Str)))    readFmt := getMyString("%t")    viScanf := VISA32.NewProc("viScanf")    var data [180]byte    viScanf.Call(uintptr(instr), uintptr(unsafe.Pointer(readFmt.Str)), uintptr(unsafe.Pointer(&data)))    s := string(Bytes2string(data))    viClose := VISA32.NewProc("viClose")    viClose.Call(uintptr(instr))    return s}// 返回的数据后面有很多个0,截断处理会更好些。func Bytes2string(data [180]byte) string {	for i := 0; i < len(data); i++ {		if data[i] == 10 || data[i] == 0 {			return string(data[:i])		}	}	return string(data[:])}
  • 常见的坑

go语言的string与C的string是有所区别的,gostring的结构是首字符的指针+长度,而Cstring的结构只有首字符指针,然后读取时顺序读到字符0为止。因此在传递中要进行转换,比如:

使用CGO使用C.CString进行转换,但这个方式会导致内存不能释放。

文中采用了另一种方式,改造结构体的方式,因此采用了另一种结构体MyString。

// 新建类型,代替C.CString// C.CString使用会产生拷贝,并不会自动释放,需要进行free。type MyString struct {    Str unsafe.Pointer    Len int}//类型转换// /x00是必须的,go的string是由首字符指针+长度组成。而C的string只有首字符指针,长度由字节0来确定,即顺序读,直到读到0。/x00即代表字符0func getMyString(s string) *MyString {    s = s + "/x00"    return (*MyString)(unsafe.Pointer(&s))}

包的下载,目前还没有完善,后续会上传一个共享包和示例程序,着急的也可以留言。

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/121761.html

相关文章

  • dockercon17 Day2|金融+保险助阵,Docker企业级初现峥嵘

    摘要:如果说是主要针对和的三个关键信息成长和,那么上午则是专注的企业级应用。将以季度为单位进行版本更新。天的已经接近尾声,金融保险两大客户现身说法,企业级初现峥嵘,从技术到商业落地,从开发者到企业级用户,容器世界的大门已经打开。 If the container ecosystem succeeds, Docker succeeds. showImg(https://segmentfault...

    NervosNetwork 评论0 收藏0
  • Win32/64-Napolar 木马界的明星

    摘要:为了了解被这种木马感染的地区分布情况,我们分析了相关检测部分的运行状况。受到感染影响最严重的区域为中南美的哥伦比亚委内瑞拉秘鲁墨西哥阿根廷以及亚洲的菲利宾越南和欧洲的波兰。通信协议目前发现的服务器有。响应结构采用以分割的字符串数组的形式。 在最近几个星期里的AVAST恶意样本分析名单中,Win32/64:Napolar拥有极高的文件和网络屏蔽率。另外,我们发现了被冠以Solarbot名...

    Amio 评论0 收藏0
  • 数据库管理平台NetopGO简介

    摘要:原文出自听云技术博客断断续续写了将近一个月,听云第一版数据库管理平台终于写完了,期间来来回回的改了好多次小毛病,现在已经部署到生产环境上去了。主机管理这里主要是主机列表管理和业务组列表管理。 原文出自【听云技术博客】:http://blog.tingyun.com/web/article/detail/600 断断续续写了将近一个月,听云第一版数据库管理平台终于写完了,期间来来回回的改...

    YacaToy 评论0 收藏0
  • 使用C编译器编写shellcode

    摘要:最终我厌倦了这样的方式,虽然很怀念完备的功能,我还是开始使用内联汇编来解决问题。禁用栈缓冲区安全检查。为了使微软编译器在栈上动态的分配字符以便重定位,你需要如下处理你会发现,我将字符串声明为字符数组的形式。 背景 有时候程序员们需要写一段独立于位置操作的代码,可当作一段数据写到其他进程或者网络中去。该类型代码在它诞生之初就被称为shellcode,在软件中黑客们以此获取到shell权...

    MasonEast 评论0 收藏0

发表评论

0条评论

最新活动
阅读需要支付1元查看
<