We're switching to a system where our shippers need to put barcodes with our article IDs on the products they're sending henceforth. Our management is willing to lend them Brother TD-4100N label printers under the condition that they do not use it for other purposes other than printing our barcodes, and now I'm tasked with programming an interface that allows them to print our barcodes.
Their core competency however lies in shipping management, not IT administration, and so I have to keep things simple and platform-independent - or at least as platform-independent as possible. The idea here is to be able to plug in one of those printers via ethernet without any kind of setup - as simple as possible. No drivers, no nothing, keep it simple, stupid. An ethernet port and sockets is all I wanna use. And with this specific model having an ethernet port and accepting ESC/P codes that shouldn't be so hard, right?
After spending a week with one test machine I've learnt enough about the ESC/P codes and Brother's proprietary extensions (at least they claim them to be) to write a little framework in C. Printing barcodes in the required format (Code128) doesn't pose a problem in and of itself, but the bookkeeping around it does; I'm at my third manual at this point that claims that simply sending the command "\x1B\x69\x53" (ESC i S) should cause the printer to send me a 32-byte record of its current status, but for some reason the printer simply doesn't want to send me how it's doing:
char buffer_send[] = "x1B\x69\x53";
send(sock_jet,buffer_send,sizeof(buffer_send) - 1,0);
char buffer[32];
memset(buffer,0,sizeof(buffer));
recv(sock_jet,buffer,sizeof(buffer),0);
fprintf
(
stderr,
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
buffer[0],buffer[1],buffer[2],buffer[3],buffer[4],buffer[5],buffer[6],buffer[7]
);
fprintf
(
stderr,
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
buffer[8],buffer[9],buffer[10],buffer[11],buffer[12],buffer[13],buffer[14],buffer[15]
);
fprintf
(
stderr,
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
buffer[16],buffer[17],buffer[18],buffer[19],buffer[20],buffer[21],buffer[22],buffer[23]
);
fprintf
(
stderr,
"%02x%02x%02x%02x%02x%02x%02x%02x\n",
buffer[24],buffer[25],buffer[26],buffer[27],buffer[28],buffer[29],buffer[30],buffer[31]
);
This code simply stalls for some time until timeout hits or whatever, and recv
doesn't write any data into my buffer:
0000000000000000
0000000000000000
0000000000000000
0000000000000000
And I'm apparently not the only one with such a problem. This Ruby Python package (https://pypi.org/project/brotherprint/#files) claims to be specifically catered for Brother printers, but I never see them receive any data (in brotherprint/brotherprint.py
at least). In fact I don't even see them spelling "receive" correctly.
On SO (operating printer with php socket programming) someone tried to do the same in PHP I'm trying to do in C - and they had the exact same problem as I'm having, with the printer refusing to give them status data. The solution seems to involve switching from port 9100 to port 515 and using a different protocol, and while I've seen port 515 to be open on the printer I've never seen any output from that printer, on paper or on the socket. At this point I'd contact the Brother support, but I'm already having another ticket open because another printer of their's does seem to have major problems sending status reports back to CUPS.
I've tried adding a NUL byte at the end of my payload, in case the printer is waiting for a page feed, but that didn't do the trick either. Again: printing barcodes to the damn thing works, so IP, port, and connection work at least to a degree - but receiving a status report doesn't.
The strace
from my program:
connect(3, {sa_family=AF_INET, sin_port=htons(9100), sin_addr=inet_addr("192.168.XXX.XXX")}, 16) = 0
sendto(3, "\33iS", 3, 0, NULL, 0) = 3
recvfrom(3, <blocks here for minutes> "", 32, 0, NULL, NULL) = 0
write(2, "0000000000000000\n", 170000000000000000
) = 17
write(2, "0000000000000000\n", 170000000000000000
) = 17
write(2, "0000000000000000\n", 170000000000000000
) = 17
write(2, "0000000000000000\n", 170000000000000000
) = 17
close(3)
And the main manual that I'm using: https://download.brother.com/welcome/docp000579/cv_td4000_eng_escp_120.pdf (search for "ESC i S").