赞
踩
项目背景:
成人本科的论文选题是用golang做一个简易的嵌入式POS机应用, 支持扫zfb/wx的在线支付二维码, 所以用c封装了几个函数给golang使用. 那这里面又涉及到了另一个问题, 如何使用arm版golang.
在我前面的文章里有一篇如何去编译arm版golang, 但是就这个项目而言, 我忽略了一个问题: golang调用c代码的时候, 需要指定gcc, 而我所指定的gcc是amd64架构, 就算直接copy到arm板子上也不能用, 还需要编译arm版gcc, 这就很麻烦. 还好, 我们同样可以通过指定交叉编译器去交叉编译golang的代码, 这只需要通过一些简单的设置就能成功.
环境说明:
执行环境: Linux ubuntu 5.0.0-32-generic. 即我编译(执行go build)golang代码的环境.
目标环境: arm.
设置参数:
首先, 在编译之前, 要确保ubuntu下有golang环境(能执行go命令), 我的golang版本是:
go version go1.13.10 linux/amd64
golang的环境变量设置跟我前面如何编译arm版golang文章里设置的环境变量差不多, 如下:
export GO111MODULE=on
export GOPROXY=https://goproxy.io
export GOARM=7
export GOARCH=arm
export GOOS=linux
export CGO_ENABLED=1
export CC_FOR_TARGET=/opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/arm-linux-gnueabihf-gcc
export CXX_FOR_TARGET=/opt/gcc-linaro-arm-linux-gnueabihf-4.9-2014.09_linux/bin/arm-linux-gnueabihf-g++
export GOROOT=/usr/local/go
export GOPATH=/usr/local/gopath
主要是开启cgo和指定交叉编译器.
代码展示:
首先, 目录结构如下:
其中目录cdep/包含了scanDevice.h/scanDevice.c文件, 主要是指定波特率/数据位等参数, scandevice.go对外提供了一个包.
scanDevice.h代码如下:
- #ifndef SCANDEVICE_H
- #define SCANDEVICE_H
-
- #include <sys/types.h>
- #include <sys/syscall.h>
- #include <sys/ioctl.h>
- #include <termios.h>
- #include <sys/stat.h>
- #include <fcntl.h>
- #include <stdbool.h>
-
- #define MSG_SIZE_MIN 20
- #define MSG_SIZE_MAX 1024
-
- typedef struct SerialInfo
- {
- unsigned char databit;
- unsigned char stopbit;
- speed_t rate;
-
- }SerialInfo;
-
- int32_t SetGetFD(int32_t rate, const char *file);
- bool Read(int32_t fd, void *msg, int32_t msgSize);
- void CloseFD(int32_t fd);
-
- int32_t openSerail(const char *file);
- int32_t setTermios(int32_t fd, const SerialInfo *serialInfo);
- speed_t getBaudRate(const int32_t rate);
- void setDataBit(unsigned char bit, struct termios *setting);
- void setParity( unsigned char *str, struct termios *setting);
- void setStopBit(unsigned char bit, struct termios *setting);
-
- #endif
scanDevice.c代码如下:
- #include <unistd.h>
- #include <string.h>
- #include <errno.h>
-
- #include "scanDevice.h"
-
- // 设置获取FD
- int32_t SetGetFD(int32_t rate, const char *file)
- {
- int32_t fd = 0;
- if ((fd = openSerail(file)) == -1)
- {
- return -1;
- }
-
- SerialInfo serialInfo = {'8', '1', getBaudRate(rate)};
- setTermios(fd, (const SerialInfo *)&serialInfo);
-
- return fd;
- }
-
- // 从FD读数据
- bool Read(int32_t fd, void *msg, int32_t msgSize)
- {
- if (msgSize < MSG_SIZE_MIN || msgSize > MSG_SIZE_MAX)
- {
- return false;
- }
-
- int32_t offset = 0;
- while(true)
- {
- int32_t ret = read(fd, (unsigned char *)msg + offset, msgSize);
- if (ret == -1) // 读取失败, 比如关闭FD
- {
- return false;
- }
-
- if (strstr((unsigned char *)msg, "\r\n") != NULL) // 此扫码枪会在数据的结尾增加\r\n, 我以此为判断条件
- {
- return true;
- }
- offset += ret;
- }
- }
-
- // 关闭FD
- void CloseFD(int32_t fd)
- {
- close(fd);
- }
-
- int32_t openSerail(const char *file)
- {
- return open(file, O_RDWR|O_NOCTTY);
- }
-
- int32_t setTermios(int32_t fd, const SerialInfo *serialInfo)
- {
- struct termios setting;
- tcgetattr(fd, &setting);
-
- //设置波特率
- cfsetispeed(&setting, serialInfo->rate);
- cfsetospeed(&setting, serialInfo->rate);
- cfmakeraw(&setting);
-
- setDataBit(serialInfo->databit, &setting);
- setParity("none", &setting);
- setStopBit(serialInfo->stopbit, &setting);
-
- tcflush(fd, TCIFLUSH);
-
- setting.c_cc[VTIME] = 0;
- setting.c_cc[VMIN] = 1;
- tcsetattr(fd, TCSANOW, &setting);
-
- return 0;
- }
-
-
- // getBaudRate 获取波特率
- speed_t getBaudRate(const int32_t rate)
- {
- switch (rate)
- {
- case 4800:
- return B4800;
- case 9600:
- return B9600;
- case 19200:
- return B19200;
- case 38400:
- return B38400;
- case 57600:
- return B57600;
- case 115200:
- return B115200;
- default:
- return B115200;
- }
- }
-
- // setDataBit 设置数据位
- void setDataBit(unsigned char bit, struct termios *setting)
- {
- switch (bit)
- {
- case '8':
- setting->c_cflag |= CS8;
- break;
- case '7':
- setting->c_cflag |= CS7;
- break;
- case '6':
- setting->c_cflag |= CS6;
- break;
- case '5':
- setting->c_cflag |= CS5;
- break;
- default:
- setting->c_cflag |= CS8;
- break;
- }
- }
-
- // setParity 设置parity
- void setParity( unsigned char *str, struct termios *setting)
- {
- if (strcmp("odd",(char *)str) == 0)
- {
- setting->c_cflag |= (PARODD | PARENB);
- setting->c_iflag |= INPCK;
- }
- else if (strcmp("even",(char *)str) == 0)
- {
- setting->c_cflag |= PARENB;
- setting->c_cflag &= ~PARODD;
- setting->c_iflag |= INPCK;
- }
- else // 默认, 可以填写str为"none"
- {
- setting->c_cflag &= ~PARENB;
- setting->c_iflag &= ~INPCK;
- }
- }
-
- // setStopBit 设置停止位
- void setStopBit(unsigned char bit, struct termios *setting)
- {
- switch (bit)
- {
- case '1':
- setting->c_cflag &= ~CSTOPB;
- break;
- case '2':
- setting->c_cflag |= CSTOPB;
- break;
- default:
- setting->c_cflag &= ~CSTOPB;
- break;
- }
- }
-
scandevice.go代码如下:
- package cdep
-
- /*
- #include <stdlib.h>
- #include "scanDevice.h"
-
- #cgo CFLAGS: -I./
- */
- import "C"
- import (
- "reflect"
- "unsafe"
- )
-
- // SetGetFD ..
- func SetGetFD(rate int32, file string) int32 {
- filePtr := C.CString(file)
- defer C.free(unsafe.Pointer(filePtr))
-
- return int32(C.SetGetFD(C.int(rate), filePtr))
- }
-
- // ReadFD ..
- func ReadFD(fd int32, msg []byte, msgSize int32) bool {
- return bool(C.Read(C.int(fd), unsafe.Pointer(reflect.ValueOf(msg).Pointer()), C.int(msgSize)))
- }
-
- // CloseFD ..
- func CloseFD(fd int32) {
- C.CloseFD(C.int(fd))
- }
这部分golang代码, 有一点需要注意: 在调用C.CString()函数的时候, 会调用c的malloc函数, 记得用C.free释放.
scan.go代码主要是调用cdep的包, 如下:
- package armscan
-
- import (
- "log"
-
- "armscan/cdep"
- )
-
- // MacroMsgSize 宏定义
- const MacroMsgSize = 1024
-
- // Scan ..
- func Scan() {
- file := "/dev/ttymxc6"
-
- fd := cdep.SetGetFD(9600, file)
- if fd == -1 {
- log.Println("SetGetFD failed.")
- return
- }
- log.Println("SetGetFD success.")
- defer cdep.CloseFD(fd)
-
- for {
- var msg = make([]byte, MacroMsgSize)
- if !cdep.ReadFD(fd, msg, int32(MacroMsgSize)) {
- log.Fatal("err")
- }
-
- log.Println(string(msg))
- }
- }
main.go就一行代码, 调用包armscan里的Scan()函数, 这里不再展示.
测试展示:
在支付宝上打开了KFC会员卡, 扫码结果跟实际的卡号一致, 如下:
结束.
c代码里的read函数可能需要根据你的需求来更改, 让它更趋于完善.
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。