嵌入式linux之go语言开发(二)c动态库驱动调用

时间:2022-07-22
本文章向大家介绍嵌入式linux之go语言开发(二)c动态库驱动调用,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

c的代码及动态库调用:

最终需要完成的封装有:串口驱动,扫码模块,语音播放库,UI显示库,卡库...

一、串口及扫码模块驱动:

linux上的串口驱动,这个较简单,有标准的模块可用。操作的是标准的设备文件。如:ttys0等。

在B503机器上,串口和二维码扫码模块。都用到了标准的linux串口。只不过二维码模块的供电需要先开启IO口

这个已经验证,串口和二维码的串口都是ok了。可以使用。

func exec_shell(s string) {
	cmd := exec.Command("/bin/bash", "-c", s)
	var out bytes.Buffer

	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", out.String())
}
func Initserial() {
	fmt.Println("init serial...")
	exec_shell("./enGPIO.sh")
	//cmd := exec.Command("ls")
	//开启二维码模块电源
	d := `echo "1"   > "/sys/class/gpio/gpio121/value"`
	cmd := exec.Command("sh", "-c", d)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Printf("failed to exec cmd")
		log.Printf(err.Error())
	} else {
		log.Println(out.String())
	}
	fmt.Println("init serial ok")

}
    //设置串口编号
	c := new(serial.Config)
	c.Name = "/dev/ttymxc5"
	c.Baud = 115200
	c.ReadTimeout = 0
	//打开串口
	s, err := serial.OpenPort(c)
	if err != nil {
		log.Printf("failed to open serial port")
		log.Fatal(err)
	}
	fmt.Println("open serial port ok! ")

root@b503_lcd:/app/city_app/opt# ./serial Hello Go

shell exec open... shell exec over. 2018/11/03 11:48:18 press any key to continue:

open serial port ok! 2018/11/03 11:48:20 <-waite for receive.. monitorLoop..modeb(1) sim card is not exist,please put in sim card!!! 2018/11/03 11:48:50 <-收到串口信息,len=21 2018/11/03 11:48:50 363232373239323838383932303636343737320d0a 2018/11/03 11:48:52 <-收到串口信息,len=21

二、语音模块驱动

语音模块涉及到的头文件为pcm-ctrl.h,动态库为libpcmctrl.so

调用demo:

package main

/*

#cgo CFLAGS: -Iinclude

#cgo LDFLAGS: -Llib -lpcmctl -lasound

#include "pcm-ctl.h"

*/
import "C"

import (
	"bytes"
	"fmt"
	"log"
	"os/exec"
)

func exec_shell(s string) {
	cmd := exec.Command("/bin/bash", "-c", s)
	var out bytes.Buffer

	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Fatal(err)
	}
	fmt.Printf("%s", out.String())
}
func InitSys() {
	fmt.Println("init sys...")
	exec_shell("./enGPIO.sh")
	//cmd := exec.Command("ls")
	//开启二维码模块电源
	d := `echo "1"   > "/sys/class/gpio/gpio121/value"`
	cmd := exec.Command("sh", "-c", d)
	var out bytes.Buffer
	cmd.Stdout = &out
	err := cmd.Run()
	if err != nil {
		log.Printf("failed to exec cmd")
		log.Printf(err.Error())
	} else {
		log.Println(out.String())
	}
	fmt.Println("init sys ok")

}
func PlayVoice(name string) int {
	cmd := C.CString(name)
	ret := C.play_wav(cmd, 5)
	if ret == 0 {
		log.Printf("play voice ok")
	} else {
		log.Printf("play voice err")
	}
	return int(ret)
}

func main() {
	fmt.Println("Hello Go")
	InitSys()
	PlayVoice("./Welcome.wav")
	name := ""
	fmt.Println("over!press any key to continue: ")
	fmt.Scanln(&name)
}

root@b503_lcd:/app/city_app/opt# ./voice Hello Go init sys... shell exec open... shell exec over. 2018/11/03 12:23:13 init sys ok 2018/11/03 12:23:14 play voice ok over!press any key to continue:

三、界面显示模块调用:

界面模块调用libucgui.so,其中遇到了一些问题,最后也一一解决了,比如如何向go传递结构体等,

UTF8汉字编码转gbk

其中uf8转gbk,使用libiconv和七牛的iconv-go都报错,不能转换成功。

一开始以为是板子上没有libconv所致,找了份libconv的源码交叉编译后放心去还不行,仍是提示:

iconv.Open failed! iconv.Open failed!

打开源码看看他里面有什么,

github.comqiniuiconv,

//
// iconv.go
//
package iconv

// #cgo darwin  LDFLAGS: -liconv
// #cgo freebsd LDFLAGS: -liconv
// #cgo windows LDFLAGS: -liconv
// #include <iconv.h>
// #include <stdlib.h>
// #include <errno.h>
//
// size_t bridge_iconv(iconv_t cd,
//		       char *inbuf, size_t *inbytesleft,
//                     char *outbuf, size_t *outbytesleft) {
//   return iconv(cd, &inbuf, inbytesleft, &outbuf, outbytesleft);
// }
import "C"

import (
	"bytes"
	"io"
	"syscall"
	"unsafe"
)

var EILSEQ = syscall.Errno(C.EILSEQ)
var E2BIG = syscall.Errno(C.E2BIG)

const DefaultBufSize = 4096

type Iconv struct {
	Handle C.iconv_t
}

// Open returns a conversion descriptor cd, cd contains a conversion state and can not be used in multiple threads simultaneously.
func Open(tocode string, fromcode string) (cd Iconv, err error) {

	tocode1 := C.CString(tocode)
	defer C.free(unsafe.Pointer(tocode1))

	fromcode1 := C.CString(fromcode)
	defer C.free(unsafe.Pointer(fromcode1))

	ret, err := C.iconv_open(tocode1, fromcode1)
	if err != nil {
		return
	}
	cd = Iconv{ret}
	return
}

func (cd Iconv) Close() error {

	_, err := C.iconv_close(cd.Handle)
	return err
}

func (cd Iconv) Conv(b []byte, outbuf []byte) (out []byte, inleft int, err error) {

	outn, inleft, err := cd.Do(b, len(b), outbuf)
	if err == nil || err != E2BIG {
		out = outbuf[:outn]
		return
	}

	w := bytes.NewBuffer(nil)
	w.Write(outbuf[:outn])

	inleft, err = cd.DoWrite(w, b[len(b)-inleft:], inleft, outbuf)
	if err != nil {
		return
	} else {
		out = w.Bytes()
	}
	return
}

func (cd Iconv) ConvString(s string) string {
	var outbuf [512]byte
	if s1, _, err := cd.Conv([]byte(s), outbuf[:]); err != nil {
		return ""
	} else {
		return string(s1)
	}
}

func (cd Iconv) Do(inbuf []byte, in int, outbuf []byte) (out, inleft int, err error) {

	if in == 0 {
		return
	}

	inbytes := C.size_t(in)
	inptr := &inbuf[0]

	outbytes := C.size_t(len(outbuf))
	outptr := &outbuf[0]
	_, err = C.bridge_iconv(cd.Handle,
		(*C.char)(unsafe.Pointer(inptr)), &inbytes,
		(*C.char)(unsafe.Pointer(outptr)), &outbytes)

	out = len(outbuf) - int(outbytes)
	inleft = int(inbytes)
	return
}

func (cd Iconv) DoWrite(w io.Writer, inbuf []byte, in int, outbuf []byte) (inleft int, err error) {

	if in == 0 {
		return
	}

	inbytes := C.size_t(in)
	inptr := &inbuf[0]

	for inbytes > 0 {
		outbytes := C.size_t(len(outbuf))
		outptr := &outbuf[0]
		_, err = C.bridge_iconv(cd.Handle,
			(*C.char)(unsafe.Pointer(inptr)), &inbytes,
			(*C.char)(unsafe.Pointer(outptr)), &outbytes)
		w.Write(outbuf[:len(outbuf)-int(outbytes)])
		if err != nil && err != E2BIG {
			return int(inbytes), err
		}
	}

	return 0, nil
}

通过源码可以看出,这种转码方案,底层是调的c的库,libconv。那么,它跟环境和系统就有关系了。不太通用。

感觉网上使用libconv库的转码方案,受限于环境,不太好用。没时间再去找原因了,于是换了一种库 最终的解决办法是:使用Mahonia,字符编解码库解决 UTF8转gbk编码问题。

https://github.com/axgle/mahonia

Go中实现的字符集转换库。

Mahonia是Go中实现的字符集转换库。所有数据都被编译成可执行文件; 它不需要任何外部数据文件。

基于http://code.google.com/p/mahonia/

root@b503_lcd:/app/city_app/opt# ./display Hello Go 480, 272, 16

display test ok.... over!press any key to continue:

package drivers

/*

#cgo CFLAGS: -Iinclude/header

#cgo LDFLAGS: -Llib -lucgui -lm
#include <stdlib.h>
#include "GUI.h"
//extern const GUI_FONT GUI_FontHZ12;
extern const GUI_FONT GUI_FontHZ20x20;
extern const GUI_FONT GUI_FontHZ32x32;
extern const GUI_FONT GUI_FontHZ76x76;

extern void GUIcache2fb(void);
extern int setGUIcache(unsigned char sta);
extern unsigned char getGUIcache(void);
*/
import "C"
import "unsafe"
import (
	"github.com/axgle/mahonia"
)

var (
	//GUI_FontHZ12    C.GUI_FONT
	GUI_FontHZ20x20 *C.GUI_FONT
	GUI_FontHZ32x32 *C.GUI_FONT
	GUI_FontHZ76x76 *C.GUI_FONT

	GUI_FONT_8_ASCII *C.GUI_FONT

	GUI_FONT_8_1        *C.GUI_FONT
	GUI_FONT_10S_ASCII  *C.GUI_FONT
	GUI_FONT_10S_1      *C.GUI_FONT
	GUI_FONT_10_ASCII   *C.GUI_FONT
	GUI_FONT_10_1       *C.GUI_FONT
	GUI_FONT_13_ASCII   *C.GUI_FONT
	GUI_FONT_13_1       *C.GUI_FONT
	GUI_FONT_13B_ASCII  *C.GUI_FONT
	GUI_FONT_13B_1      *C.GUI_FONT
	GUI_FONT_13H_ASCII  *C.GUI_FONT
	GUI_FONT_13H_1      *C.GUI_FONT
	GUI_FONT_13HB_ASCII *C.GUI_FONT
	GUI_FONT_13HB_1     *C.GUI_FONT
	GUI_FONT_16_ASCII   *C.GUI_FONT
	GUI_FONT_16_1       *C.GUI_FONT
	GUI_FONT_16_HK      *C.GUI_FONT
	GUI_FONT_16_1HK     *C.GUI_FONT
	GUI_FONT_16B_ASCII  *C.GUI_FONT
	GUI_FONT_16B_1      *C.GUI_FONT
	// GUI_FONT_20_ASCII   *C.GUI_FONT
	// GUI_FONT_20_1       *C.GUI_FONT
	// GUI_FONT_20B_ASCII  *C.GUI_FONT
	// GUI_FONT_20B_1      *C.GUI_FONT
	GUI_FONT_24_ASCII  *C.GUI_FONT
	GUI_FONT_24_1      *C.GUI_FONT
	GUI_FONT_24B_ASCII *C.GUI_FONT
	GUI_FONT_24B_1     *C.GUI_FONT
	GUI_FONT_32_ASCII  *C.GUI_FONT
	GUI_FONT_32_1      *C.GUI_FONT
	GUI_FONT_32B_ASCII *C.GUI_FONT
	GUI_FONT_32B_1     *C.GUI_FONT
)

const (
	//================
	GUI_TEXTMODE_NORMAL C.int = C.GUI_TEXTMODE_NORMAL
	GUI_TEXTMODE_XOR    C.int = C.GUI_TEXTMODE_XOR
	GUI_TEXTMODE_TRANS  C.int = C.GUI_TEXTMODE_TRANS
	GUI_TEXTMODE_REV    C.int = C.GUI_TEXTMODE_REV
	GUI_TM_NORMAL       C.int = C.GUI_TM_NORMAL
	GUI_TM_XOR          C.int = C.GUI_TM_XOR
	GUI_TM_TRANS        C.int = C.GUI_TM_TRANS
	GUI_TM_REV          C.int = C.GUI_TM_REV

	//===================

	GUI_BLUE         C.uint = C.GUI_BLUE
	GUI_GREEN        C.uint = C.GUI_GREEN
	GUI_RED          C.uint = C.GUI_RED
	GUI_CYAN         C.uint = C.GUI_CYAN
	GUI_MAGENTA      C.uint = C.GUI_MAGENTA
	GUI_YELLOW       C.uint = C.GUI_YELLOW
	GUI_LIGHTBLUE    C.uint = C.GUI_LIGHTBLUE
	GUI_LIGHTGREEN   C.uint = C.GUI_LIGHTGREEN
	GUI_LIGHTRED     C.uint = C.GUI_LIGHTRED
	GUI_LIGHTCYAN    C.uint = C.GUI_LIGHTCYAN
	GUI_LIGHTMAGENTA C.uint = C.GUI_LIGHTMAGENTA
	GUI_LIGHTYELLOW  C.uint = C.GUI_LIGHTYELLOW
	GUI_DARKBLUE     C.uint = C.GUI_DARKBLUE
	GUI_DARKGREEN    C.uint = C.GUI_DARKGREEN
	GUI_DARKRED      C.uint = C.GUI_DARKRED
	GUI_DARKCYAN     C.uint = C.GUI_DARKCYAN
	GUI_DARKMAGENTA  C.uint = C.GUI_DARKMAGENTA
	GUI_DARKYELLOW   C.uint = C.GUI_DARKYELLOW
	GUI_WHITE        C.uint = C.GUI_WHITE
	GUI_LIGHTGRAY    C.uint = C.GUI_LIGHTGRAY
	GUI_GRAY         C.uint = C.GUI_GRAY
	GUI_DARKGRAY     C.uint = C.GUI_DARKGRAY
	GUI_BLACK        C.uint = C.GUI_BLACK
	GUI_BROWN        C.uint = C.GUI_BROWN
	GUI_ORANGE       C.uint = C.GUI_ORANGE
	GUI_TRANSPARENT  C.uint = C.GUI_TRANSPARENT

	TOP_BAR_COLOR C.uint = 0x501f08
)

func init() {
	//GUI_FontHZ12 = C.GUI_FontHZ12
	GUI_FontHZ20x20 = &C.GUI_FontHZ20x20
	GUI_FontHZ32x32 = &C.GUI_FontHZ32x32
	GUI_FontHZ76x76 = &C.GUI_FontHZ76x76

	GUI_FONT_8_1 = &C.GUI_Font8_1
	GUI_FONT_10S_ASCII = &C.GUI_Font10S_ASCII

	GUI_FONT_10S_1 = &C.GUI_Font10S_1
	GUI_FONT_10_ASCII = &C.GUI_Font10_ASCII
	GUI_FONT_10_1 = &C.GUI_Font10_1
	GUI_FONT_13_ASCII = &C.GUI_Font13_ASCII
	GUI_FONT_13_1 = &C.GUI_Font13_1
	GUI_FONT_13B_ASCII = &C.GUI_Font13B_ASCII
	GUI_FONT_13B_1 = &C.GUI_Font13B_1
	GUI_FONT_13H_ASCII = &C.GUI_Font13H_ASCII
	GUI_FONT_13H_1 = &C.GUI_Font13H_1
	GUI_FONT_13HB_ASCII = &C.GUI_Font13HB_ASCII
	GUI_FONT_13HB_1 = &C.GUI_Font13HB_1
	GUI_FONT_16_ASCII = &C.GUI_Font16_ASCII
	GUI_FONT_16_1 = &C.GUI_Font16_1
	GUI_FONT_16_HK = &C.GUI_Font16_HK
	GUI_FONT_16_1HK = &C.GUI_Font16_1HK
	GUI_FONT_16B_ASCII = &C.GUI_Font16B_ASCII
	GUI_FONT_16B_1 = &C.GUI_Font16B_1
	//GUI_FONT_20_ASCII   = &C.GUI_Font20_ASCII
	//GUI_FONT_20_1       = &C.GUI_Font20_1
	//GUI_FONT_20B_ASCII  = &C.GUI_Font20B_ASCII
	//GUI_FONT_20B_1      = &C.GUI_Font20B_1
	GUI_FONT_24_ASCII = &C.GUI_Font24_ASCII
	GUI_FONT_24_1 = &C.GUI_Font24_1
	GUI_FONT_24B_ASCII = &C.GUI_Font24B_ASCII
	GUI_FONT_24B_1 = &C.GUI_Font24B_1
	GUI_FONT_32_ASCII = &C.GUI_Font32_ASCII
	GUI_FONT_32_1 = &C.GUI_Font32_1
	GUI_FONT_32B_ASCII = &C.GUI_Font32B_ASCII
	GUI_FONT_32B_1 = &C.GUI_Font32B_1

}

func GUI_Init() {
	C.GUI_Init()
}
func GUI_Clear() {
	C.GUI_Clear()
}

func GUI_SetColor(val C.uint) {
	C.GUI_SetColor(C.ulong(val))
}

func GUI_SetBkColor(val C.uint) {
	C.GUI_SetBkColor(C.ulong(val))
}

func GUI_SetFont(val *C.struct_GUI_FONT) {
	C.GUI_SetFont(val)
}

//注:go中的编码为utf-8,GUI显示汉字使用的GB2312
func GUI_DispStringAt(str string, x, y int) {

	enc := mahonia.NewEncoder("gbk")

	gbk := enc.ConvertString(str)
	cs := C.CString(gbk)
	defer C.free(unsafe.Pointer(cs))
	C.GUI_DispStringAt(cs, C.int(x), C.int(y))

}

func GUI_DispStringHCenterAt(str string, x, y int) {
	enc := mahonia.NewEncoder("gbk")

	gbk := enc.ConvertString(str)
	cs := C.CString(gbk)
	defer C.free(unsafe.Pointer(cs))
	C.GUI_DispStringHCenterAt(cs, C.int(x), C.int(y))
}

func GUI_FillRect(x0, y0, x1, y1 int) {
	C.GUI_FillRect(C.int(x0), C.int(y0), C.int(x1), C.int(y1))
}

func GUI_SetTextMode(mode C.int) {
	C.GUI_SetTextMode(mode)
}

func GUIcache2fb() {
	C.GUIcache2fb()
}

func SetGUIcache(sta int) {
	C.setGUIcache(C.uchar(sta))
}

func GetGUIcache() int {
	return int(C.getGUIcache())
}

func main() {
	fmt.Println("Hello Go")
	GUI_Init()
	GUI_SetBkColor(0x954816)
	GUI_Clear()
	GUI_SetFont(&C.GUI_FontHZ20x20)

	GUI_DispStringAt("PRICE", 60, 156)

	GUI_DispStringAt("票价", 60, 120)

	name := ""
	fmt.Println("over!press any key to continue: ")
	fmt.Scanln(&name)
}