3

I have a special label printer (GoDEX RT863i) connected to a Mac. It uses the CUPS system and is configured through a PPD file. Printing through the macOS print system generally works.

Now, I need to send some special commands to the printer via its xxPL (EZPL, GZPL, GEPL, GDPL) communication interface.

The manufacturer provides a framework for talking to the printer, but that's fairly buggy and thus not suitable (e.g. I cannot send arbitrary byte data because the framework uses NSString instead of NSData, making it impossible to send certain byte sequences).

So I want to talk to the printer directly. How would I accomplish that?

  • Does CUPS provide a channel that lets me send commands to the printer?
  • How would I go about talking to the printer's USB ports? Here's what ioreg -r -c IOUSBHostDevice -l prints about it:
 +-o RT863i@00442000  <class IOUSBHostDevice, id 0x100126a4c, registered, matched, active, busy 0 (3 ms), retain 20>
   | {
   |   "sessionID" = 8582230593430921
   |   "USBSpeed" = 3
   |   "IOServiceLegacyMatchingRegistryID" = 4296174158
   |   "idProduct" = 1
   |   "IOReportLegendPublic" = Yes
   |   "IOPowerManagement" = {"PowerOverrideOn"=Yes,"CapabilityFlags"=32768,"MaxPowerState"=2,"DevicePowerState"=2,"ChildrenPowerState"=1,"DriverPowerState"=0,"CurrentPowerState"=2}
   |   "bcdDevice" = 1
   |   "bDeviceClass" = 0
   |   "USB Product Name" = "RT863i"
   |   "AppleUSBAlternateServiceRegistryID" = 4296174158
   |   "locationID" = 4464640
   |   "kUSBSerialNumberString" = "195003FF"
   |   "bDeviceSubClass" = 0
   |   "kUSBCurrentConfiguration" = 1
   |   "IOCFPlugInTypes" = {"9dc7b780-9ec0-11d4-a54f-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
   |   "bDeviceProtocol" = 0
   |   "USBPortType" = 0
   |   "USB Vendor Name" = "GODEX INTERNATIONAL CO."
   |   "idVendor" = 6495
   |   "USB Serial Number" = "195003FF"
   |   "IOGeneralInterest" = "IOCommand is not serializable"
   |   "IOReportLegend" = ({"IOReportGroupName"="Power","IOReportChannels"=((5795982523037122560,12886081538)),"IOReportChannelInfo"={"IOReportChannelUnit"=72058100844068865},"IOReportSubGroupName"="State"},{"IOReportGroupName"="Power","IOReportChannels"=((5288471043487301632,4296146945,"Consensus Idle Policy")),"IOReportChannelInfo"=$
   |   "kUSBVendorString" = "GODEX INTERNATIONAL CO."
   |   "IOClassNameOverride" = "IOUSBDevice"
   | }
   | 
   +-o AppleUSBHostLegacyClient  <class AppleUSBHostLegacyClient, id 0x100126a4f, !registered, !matched, active, busy 0, retain 9>
   |   {
   |     "kUSBHostDeviceForceSuspend" = No
   |     "IOPowerManagement" = {"DevicePowerState"=0,"CurrentPowerState"=1,"CapabilityFlags"=65536,"MaxPowerState"=2,"DriverPowerState"=1}
   |   }
   |   
   +-o AppleUSBHostCompositeDevice  <class AppleUSBHostCompositeDevice, id 0x100126a57, !registered, !matched, active, busy 0, retain 4>
   |   {
   |     "IOProbeScore" = 50000
   |     "CFBundleIdentifier" = "com.apple.driver.usb.AppleUSBHostCompositeDevice"
   |     "IOProviderClass" = "IOUSBHostDevice"
   |     "IOClass" = "AppleUSBHostCompositeDevice"
   |     "bDeviceSubClass" = 0
   |     "IOMatchCategory" = "IODefaultMatchCategory"
   |     "kUSBPreferredConfiguration" = 1
   |     "bDeviceClass" = 0
   |   }
   |   
   +-o Printer@0  <class IOUSBHostInterface, id 0x100126a58, registered, matched, active, busy 0 (1 ms), retain 6>
       {
         "USBPortType" = 0
         "IOCFPlugInTypes" = {"2d9786c6-9ef3-11d4-ad51-000a27052861"="IOUSBFamily.kext/Contents/PlugIns/IOUSBLib.bundle"}
         "bcdDevice" = 1
         "USBSpeed" = 3
         "idProduct" = 1
         "bConfigurationValue" = 1
         "bInterfaceSubClass" = 1
         "locationID" = 4464640
         "IOGeneralInterest" = "IOCommand is not serializable"
         "IOServiceLegacyMatchingRegistryID" = 4296174170
         "IOClassNameOverride" = "IOUSBInterface"
         "AppleUSBAlternateServiceRegistryID" = 4296174170
         "idVendor" = 6495
         "bInterfaceProtocol" = 2
         "bAlternateSetting" = 0
         "bInterfaceNumber" = 0
         "bInterfaceClass" = 7
       }

As you can see, it doesn't automatically install any serial port (to /dev/), so I think I need to use other means, unless it's easy to create an IOKit "driver" that matches the device and automatically installs a serial port (no idea if that's something that IOKit can do without any extra code)?

Thomas Tempelmann
  • 11,045
  • 8
  • 74
  • 149
  • That `IOUSBHostInterface` has no client objects so I assume that gets grabbed by CUPS only when actually printing to it? I unfortunately don't know much about printers & the macOS printing subsystem specifically, but I do work extensively with USB and USB on macOS. If CUPS only grabs the interface intermittently, you should be fine. (as long as you can live with whatever the consequences are when CUPS can't grab the interface because your process has it open) In that case, normal [userspace IOKit USB APIs](https://developer.apple.com/documentation/iokit/iousblib_h?language=objc) will work. – pmdj Oct 29 '20 at 20:12
  • 1
    In fact, you can probably use something like `libusb` which is a little easier to use. However, depending on what you're trying to achieve, you might want to check if you can write a dedicated CUPS plugin or something along those lines - especially if you want to share the printer over the network and control these custom features from network clients as well. – pmdj Oct 29 '20 at 20:14
  • The "serial port" aspect is a little more complex - if you really must have a (virtual?) serial port in `/dev` you'll need to go a layer deeper to DriverKit - but claiming the interface from the DriverKit driver will probably stop CUPS from accessing it directly. – pmdj Oct 29 '20 at 20:17

0 Answers0