jerrywu75的笔记 https://bbs.21ic.com/?62511 [收藏] [复制] [RSS]

日志

嵌入式linux应用开发-USB接口的ESC/POS打印机

已有 1652 次阅读2015-9-14 11:11 |个人分类:嵌入式开发|系统分类:嵌入式系统| linux, 嵌入式, USB接口, 开发

    最近在做一个嵌入式linux下的应用程序驱动打印机的工作,打印机是58mm的热敏票据打印机,供应商说是免驱动的。

    linux开发最不愿意听到的就是免驱。免驱动的意思就是linux下,你自己看着办吧!!!

    在网上查了半天,看样子只能使用libusb来自己直接控制打印机了,还好打印机是ESC/POS指令集的,这个东西比较容易找到。另外现在linux默认是UTF-8编码,这个编码不被手头的ESC/POS打印机支持,所以还需要一个将UTF-8转换为GBK的软件包libiconvlibiconv比较简单,就不再本文中多说。

    首先下载libusb,配置并编译。在www.libusb.org官网下在最新版本的源代码,目前是libusb 1.0.9

    编辑一个setconf.sh文件,用于对libusb进行编译设置:

    #!/bin/sh

    ./configure --host=arm-linux-gnueabihf \

    --prefix=/opt/libusb/ \

    CC="arm-linux-gnueabihf-gcc -ldl -fPIC" \

     CXX="arm-linux-gnueabihf-g++ -ldl -fPIC"

    然后make -j4,编译libusb,成功后make install,将库安装到计算机的/opt/libusb目录中,手动将/opt/libusb目录拷贝到嵌入式linuxnfs文件夹中的相同目录中。

    编写一个测试程序,用于测试是否能够通过libusb控制打印机。

    首先对libusb初始化,并获取设备列表,然后遍历设备列表,寻找指定的打印机设备:

    #define VenderID   0x1cbe

    #define ProduceID  0x0a03

     libusb_context *ctx = NULL;

    struct libusb_device_handle *dev_handle=NULL;

    unsigned int uInterfaceNum;

    unsigned char ucEpIn=0,ucEpOut=0;

    rtn=libusb_init(&ctx); //初始化libusb

    if(rtn!=0){

       printf("Can't init the libusb.\n");

       return 1;

    } else {

       printf("Open the libusb sucess, rnt code is %d.\n",rtn);

    }

    cnt=libusb_get_device_list(ctx,&devs); //获取libusb的设备列表

    if (cnt<0){

        printf("Can't get the USB device list.\n");

        return 1;

    }

    while((dev=devs[i++])!=NULL){ //遍历设备列表,寻找指定的USB打印机设备

        struct libusb_device_descriptor desc;

       struct libusb_config_descriptor *config_desc;

       uint8_t bus_number=libusb_get_bus_number(dev);

       uint8_t device_address=libusb_get_device_address(dev);

       rtn=libusb_get_device_descriptor(dev,&desc);

       if(rtn<0){

            printf("Failed to get device descriptor for %d/%d.\n",bus_number,device_address);

           continue;

       }

       printf("Bus number=%u,Device address=0x%x\n",bus_number,device_address);

       printf("Vender ID=0x%x,Product ID=0x%x\n",desc.idVendor,desc.idProduct);

        if((VenderID==desc.idVendor)&&(ProduceID==desc.idProduct)&&(dev_handle==NULL)){ //比较是否是指定的设备

            printf("Find a ESC/POS printer, open it.\n");

            rtn=libusb_open(dev,&dev_handle);

            if(rtn<0){

                printf("Can't open the USB printer, rtn code is %d.\n",rtn);

                dev_handle=NULL;

            } else {

                 rtn=libusb_get_active_config_descriptor(dev,&config_desc);

                 if(rtn<0){

                     (void)libusb_close(dev_handle);

                     dev_handle=NULL;

                     printf("Can't get config descriptor.\n");

                 } else {

                      printf("Open the USB printer sucess.\n");

                      usbPrinter=dev;

                      for(j=0;j<config_desc->bNumInterfaces;j++){ //已经找到指定设备,访问该设备的描述表,找到interface,endpoint

                         for(t=0;t<config_desc->interface[j].num_altsetting;t++){

                              if(config_desc->interface[j].altsetting[t].bInterfaceClass==0x07){

                                           printf("It is a USB printer.\n");

                                          uInterfaceNum=j;       

                                          for(m=0;m<config_desc->interface[j].altsetting[t].bNumEndpoints;m++){

                                                 if(config_desc->interface[j].altsetting[t].endpoint[m].bmAttributes==0x02){

                                                       if(config_desc->interface[j].altsetting[t].endpoint[m].bEndpointAddress&0x80){ //输入endpoint

                                                               ucEpIn=config_desc->interface[j].altsetting[t].endpoint[m].bEndpointAddress;

                                                        } else { //输出endpoint

                                                               ucEpOut=config_desc->interface[j].altsetting[t].endpoint[m].bEndpointAddress;

                                                        }

                                                 }

    .........

    }
    libusb_free_device_list(devs,1);

    上面的程序通过获取device_list,并遍历list,然后比较venderIDproduceID,寻找指定的USB打印机。如果找到指定的打印机,使用libusb_open打开设备。

    当成功打开指定的USB打印机后,保存打开的设备句柄,然后遍历已经打开的打印机的设备描述表,获取interface以及endpoint

    手头的ESC/POS打印机只有1interface,这个interface包含2endpoint,一个输入,一个输出。

    打开打印机,并获得interfaceendpoint后,下一步通过libusb_claim认领interface

      rtn=libusb_claim_interface(dev_handle,uInterfaceNum);

      if(rtn<0){

           printf("Can't claim the interface.\n");

      }

    到这里,就已经获得打印机的控制,可以向打印机发送ESC/POS指令,进行打印操作了。例如控制打印机回车换行并切纸:

     ucBuf[0]=0x0d;

     ucBuf[1]=0x0a;

     ucBuf[2]=0x1b;

     ucBuf[3]='i';

     rtn=libusb_bulk_transfer(dev_handle,ucEpOut,ucBuf,4,&iLen,USB_WRITE_TIMEOUT);

     if(rtn<0){

         printf("Can't write cmd, rtn code is %d.\n",rtn);

     } else {

         printf("Write cmd sucess, real len is %u.\n",iLen);

     }

    最后关闭打印机并退出libusb

     rtn=libusb_release_interface(dev_handle,uInterfaceNum);

     if(rtn<0){

         printf("Can't release the interface,rtn code is %d.\n",rtn);

     } else {

         printf("Release the interface sucess.\n");

     }

     (void)libusb_close(dev_handle);

     if(ctx!=NULL){

         libusb_exit(ctx);

         ctx=NULL;

     }



路过

鸡蛋

鲜花

握手

雷人

评论 (0 个评论)