0

Background

I am trying to write/print to a serial port on MacOS Mojave. Serial port is connected to a thermal printer with ESC/POS emulation. I have used boost::asio::serial_port from boost 1.67.0 for this task. See the following code:

#define SUCCESS 0
#define FAIL -1

#include <string>
#include <cstdio>
#include <iostream>
#include <boost/asio.hpp>
#include <boost/asio/serial_port.hpp>

int main(int argc, char *argv[]){

    boost::system::error_code ec;
    boost::asio::io_service io;
    boost::asio::serial_port port( io );

    std::string portname="/dev/tty.usbserial-12";

    try{
        port.open(portname.c_str(), ec);

        if (ec) {
            std::cout << "error : port.open() failed... portname=" << portname << ", e=" << ec.message().c_str() << std::endl; 
            return FAIL;
        }
        port.set_option( boost::asio::serial_port_base::baud_rate( 19200 ) );

        unsigned char init[2] = { 27, 64 };
        unsigned char hello[6] = { 'h', 'e', 'l', 'l', 'o', '\0'};
        unsigned char cut[2] = { 29, 86 };

        boost::asio::write(port, boost::asio::buffer(init, sizeof(init)));
        boost::asio::write(port, boost::asio::buffer(hello, sizeof(hello)));
        boost::asio::write(port, boost::asio::buffer(cut, sizeof(cut)));

        port.close();
        return SUCCESS;
    }catch(...){
        return FAIL;
    }
}

EDIT 1

I tried to use FileDescriptor as in the following snippet:

int fd; //Descriptor for the port
fd = open("/dev/tty.usbserial-12", O_RDWR | O_NOCTTY | O_NDELAY);
if (fd == -1) {
    std::cout << "Unable to open port. \n";
    return FAIL;
}

struct termios options;

tcgetattr(fd, &options);
cfsetispeed(&options, B19200);
cfsetospeed(&options, B19200);

options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
options.c_cflag &= ~CSIZE;
options.c_oflag &= ~OPOST;
options.c_cflag |= CS8;
options.c_cflag |= (CLOCAL | CREAD);
tcsetattr(fd, TCSANOW, &options);

std::cout << "Port configured.\n";

unsigned char init[2] = { 27, 64 };
unsigned char hello[6] = { 'h', 'e', 'l', 'l', 'o', '\0'};
unsigned char cut[2] = { 29, 86};

int rv = FAIL;

rv = write(fd, init, 2);
if(rv<SUCCESS){
    std::cout << "could not write" << std::endl;
    return FAIL;
}

rv = write(fd, "hello\n", 6);
if(rv<SUCCESS){
    std::cout << "could not write" << std::endl;
    return FAIL;
}

rv = write(fd, cut, 2);
if(rv<SUCCESS){
    std::cout << "could not write" << std::endl;
    return FAIL;
}

std::cout << "closing FD" << std::endl;
close(fd);
return SUCCESS;

Console output of previous snippet:

Port configured.
closing FD

Unfortunately, there is no error and no output at device side.

EDIT 1 END

I can confirm that MacOS picks up connected serial port by checking output of ls /dev/tty.usbserial* and ls /dev/cu.usbserial* before and after connecting it to my Mac.

Also, if I run screen /dev/tty.usbserial-12 19200 then run my app I get an error stating that resource busy.

While searching online I came across a SimpleSerial implementation with the following comment written at top of file:

IMPORTANT: On Mac OS X boost asio's serial ports have bugs, and the usual implementation of this class does not work. So a workaround class was written temporarily, until asio (hopefully) will fix Mac compatibility for serial ports. Please note that unlike said in the documentation on OS X until asio will be fixed serial port writes are not asynchronous, but at least asynchronous read works. In addition the serial port open ignores the following options: parity, character size, flow, stop bits, and defaults to 8N1 format. I know it is bad but at least it's better than nothing.

I tried to search online in order to confirm that there is a known bug but couldn't find a relevant one.

Issue

The code above executes without any error but, for reasons unknown to me, there is no output at printer. I can "print" using screen /dev/tty.usbserial-12 19200.

Same code does work on Raspberry PI running raspbian and produces desired output at printer.

Questions

Is there anything wrong with my code? Have I missed some steps along the way? How can I resolve this issue?

raidensan
  • 1,099
  • 13
  • 31
  • You know there's a bug in Boost.asio, so you want to know how to work around that? You need to compare the actual system calls being made when `screen` writes to the device, and when Boost.asio writes to the device. You can run them both under `strace` for a start, and turn up detailed logging of buffer contents, ioctl calls, etc. – Useless Oct 03 '18 at 13:34
  • @Useless I don't know if there is a bug as there is no evidence provided at linked file. My web search did not result in any open bug issue either. – raidensan Oct 04 '18 at 07:31
  • **You** quoted a file saying _boost asio's serial ports have bugs_. And, I've told you how to see what screen is doing differently. – Useless Oct 04 '18 at 09:19

0 Answers0