-module(escpos@printer). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/escpos/printer.gleam"). -export([device/1, connect/2, print/2, disconnect/1]). -export_type([command_buffer/0, printer/0, printer_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC( " Functions for connecting to and communicating with ESC/POS printers.\n" "\n" " Supports both USB (device file) and network (TCP socket) connections.\n" "\n" " ## Example\n" "\n" " ```gleam\n" " // USB printer\n" " let assert Ok(printer) = printer.device(\"/dev/usb/lp0\")\n" "\n" " // Network printer\n" " let assert Ok(printer) = printer.connect(\"192.168.1.100\", 9100)\n" "\n" " escpos.new()\n" " |> escpos.writeln(\"Hello!\")\n" " |> escpos.cut()\n" " |> printer.print(printer)\n" "\n" " // Close network printer socket\n" " printer.disconnect(printer)\n" " ```\n" ). -type command_buffer() :: {command_buffer, bitstring()}. -opaque printer() :: {network_printer, mug:socket()} | {usb_printer, binary()}. -type printer_error() :: {connection_failed, mug:connect_error()} | {disconnection_failed, mug:error()} | {transmission_error, mug:error()} | {network_print_error, mug:error()} | {usb_print_error, simplifile:file_error()} | {usb_device_error, simplifile:file_error()}. -file("src/escpos/printer.gleam", 51). ?DOC( " Opens a USB printer by its device file path (e.g. `/dev/usb/lp0`) and writes\n" " the initialization command.\n" ). -spec device(binary()) -> {ok, printer()} | {error, printer_error()}. device(Path) -> case simplifile_erl:file_info(Path) of {ok, _} -> gleam@result:'try'( begin _pipe = simplifile_erl:write_bits(Path, <<(27), "@"/utf8>>), gleam@result:map_error( _pipe, fun(Field@0) -> {usb_device_error, Field@0} end ) end, fun(_) -> {ok, {usb_printer, Path}} end ); {error, Err} -> {error, {usb_device_error, Err}} end. -file("src/escpos/printer.gleam", 66). ?DOC(" Connects to a network printer over TCP and sends the initialization command.\n"). -spec connect(binary(), integer()) -> {ok, printer()} | {error, printer_error()}. connect(Ip, Port) -> gleam@result:'try'( begin _pipe = mug:new(Ip, Port), _pipe@1 = mug:timeout(_pipe, 1000), _pipe@2 = mug:connect(_pipe@1), gleam@result:map_error( _pipe@2, fun(Field@0) -> {connection_failed, Field@0} end ) end, fun(Socket) -> gleam@result:'try'( begin _pipe@3 = mug:send(Socket, <<(27), "@"/utf8>>), gleam@result:map_error( _pipe@3, fun(Field@0) -> {transmission_error, Field@0} end ) end, fun(_) -> {ok, {network_printer, Socket}} end ) end ). -file("src/escpos/printer.gleam", 86). ?DOC( " Sends a command buffer to the printer.\n" "\n" " For network printers this writes to the TCP socket. For USB printers\n" " this writes directly to the device file.\n" ). -spec print(command_buffer(), printer()) -> {ok, nil} | {error, printer_error()}. print(Cb, Printer) -> case Printer of {network_printer, Socket} -> _pipe = mug:send(Socket, erlang:element(2, Cb)), gleam@result:map_error( _pipe, fun(Field@0) -> {network_print_error, Field@0} end ); {usb_printer, Device} -> _pipe@1 = simplifile_erl:write_bits(Device, erlang:element(2, Cb)), gleam@result:map_error( _pipe@1, fun(Field@0) -> {usb_print_error, Field@0} end ) end. -file("src/escpos/printer.gleam", 98). ?DOC(" Closes the connection to a network printer. For USB printers this is a no-op.\n"). -spec disconnect(printer()) -> {ok, nil} | {error, printer_error()}. disconnect(Printer) -> case Printer of {network_printer, Socket} -> _pipe = mug_ffi:shutdown(Socket), gleam@result:map_error( _pipe, fun(Field@0) -> {disconnection_failed, Field@0} end ); {usb_printer, _} -> {ok, nil} end.