From cbe18da5981655e13d6c61ee3b9682a34162aa60 Mon Sep 17 00:00:00 2001 From: Ignacio Rivero Date: Fri, 6 Feb 2026 13:47:06 -0300 Subject: [PATCH] New daemon architecture --- LICENSE | 18 + LICENSE.gplv3 | 674 ++++++++++++++++++++++++++++++++ LICENSE.mit | 21 + Makefile | 104 +++++ README.md | 96 +++++ bleh.jpg | Bin 0 -> 32508 bytes cmd/bleh/main.go | 346 ++++++++++++++++ cmd/blehd/main.go | 424 ++++++++++++++++++++ demo.jpg | Bin 0 -> 117685 bytes dist/INSTALL.md | 85 ++++ dist/openrc/blehd | 17 + dist/systemd/blehd-root.service | 27 ++ go.mod | 19 + internal/imageproc/imageproc.go | 189 +++++++++ internal/ipc/jsonl.go | 55 +++ internal/ipc/protocol.go | 22 ++ internal/mxw01/mxw01.go | 282 +++++++++++++ internal/mxw01/print.go | 56 +++ 18 files changed, 2435 insertions(+) create mode 100644 LICENSE create mode 100644 LICENSE.gplv3 create mode 100644 LICENSE.mit create mode 100644 Makefile create mode 100644 README.md create mode 100644 bleh.jpg create mode 100644 cmd/bleh/main.go create mode 100644 cmd/blehd/main.go create mode 100644 demo.jpg create mode 100644 dist/INSTALL.md create mode 100644 dist/openrc/blehd create mode 100644 dist/systemd/blehd-root.service create mode 100644 go.mod create mode 100644 internal/imageproc/imageproc.go create mode 100644 internal/ipc/jsonl.go create mode 100644 internal/ipc/protocol.go create mode 100644 internal/mxw01/mxw01.go create mode 100644 internal/mxw01/print.go diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..cf1d577 --- /dev/null +++ b/LICENSE @@ -0,0 +1,18 @@ +Bleh!: Go driver for Cat Thermal Printer MXW01 +Copyright (C) 2025 Ignacio Rivero + +This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along with this program. If not, see . + +See LICENSE.gplv3 for details. + +--- + +**Portions of this code are adapted from:** +CatPrinterBLE (C#), Copyright (c) 2025 MaikelChan +Distributed under the MIT License (see LICENSE.mit for details) +https://github.com/MaikelChan/CatPrinterBLE + \ No newline at end of file diff --git a/LICENSE.gplv3 b/LICENSE.gplv3 new file mode 100644 index 0000000..e72bfdd --- /dev/null +++ b/LICENSE.gplv3 @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. \ No newline at end of file diff --git a/LICENSE.mit b/LICENSE.mit new file mode 100644 index 0000000..0aeba95 --- /dev/null +++ b/LICENSE.mit @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2025 MaikelChan + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c19fa64 --- /dev/null +++ b/Makefile @@ -0,0 +1,104 @@ +PREFIX ?= /usr/local +BINDIR ?= $(PREFIX)/bin +SYSCONFDIR ?= /etc +DESTDIR ?= + +GO ?= go +GOFLAGS ?= + +BIN_DIR := bin +BLEH := $(BIN_DIR)/bleh +BLEHD := $(BIN_DIR)/blehd + +.PHONY: all build clean install uninstall setcap install-systemd uninstall-systemd install-openrc uninstall-openrc + +all: build + +build: + @mkdir -p $(BIN_DIR) + $(GO) build $(GOFLAGS) -o $(BLEH) ./cmd/bleh + $(GO) build $(GOFLAGS) -o $(BLEHD) ./cmd/blehd + +clean: + rm -rf $(BIN_DIR) + +# SETCAP: +# - auto (default): apply setcap when installing as root and setcap is available +# - 1: force setcap (fails if not root / setcap missing) +# - 0: never apply setcap +SETCAP ?= auto + +install: + @test -x $(BLEH) || (echo "Missing $(BLEH). Run: make build"; exit 1) + @test -x $(BLEHD) || (echo "Missing $(BLEHD). Run: make build"; exit 1) + install -Dm755 $(BLEH) $(DESTDIR)$(BINDIR)/bleh + install -Dm755 $(BLEHD) $(DESTDIR)$(BINDIR)/blehd + @case "$(SETCAP)" in \ + auto) \ + if [ "$$(id -u)" = "0" ] && command -v setcap >/dev/null 2>&1; then \ + echo "Applying capabilities to blehd (cap_net_raw,cap_net_admin)..."; \ + setcap cap_net_raw,cap_net_admin=eip $(DESTDIR)$(BINDIR)/blehd; \ + else \ + echo "(Skipping setcap: not root or setcap not found; run 'sudo make setcap' if needed)"; \ + fi \ + ;; \ + 1) \ + echo "Applying capabilities to blehd (cap_net_raw,cap_net_admin)..."; \ + setcap cap_net_raw,cap_net_admin=eip $(DESTDIR)$(BINDIR)/blehd \ + ;; \ + 0) \ + echo "(Skipping setcap: SETCAP=0)" \ + ;; \ + *) \ + echo "Unknown SETCAP=$(SETCAP) (use auto|1|0)"; exit 2 \ + ;; \ + esac + @if [ "$$(id -u)" = "0" ]; then \ + echo "Tip: to install a service: make install-systemd (or install-openrc)"; \ + fi + +uninstall: + rm -f $(DESTDIR)$(BINDIR)/bleh + rm -f $(DESTDIR)$(BINDIR)/blehd + +# Give blehd the minimum capabilities it needs so it can run unprivileged. +# (Still recommended to run it with a dedicated group for socket access.) +setcap: install + setcap cap_net_raw,cap_net_admin=eip $(DESTDIR)$(BINDIR)/blehd + +install-systemd: + install -Dm644 dist/systemd/blehd-root.service $(DESTDIR)$(SYSCONFDIR)/systemd/system/blehd.service + @echo "Installed root unit: $(SYSCONFDIR)/systemd/system/blehd.service" + @echo "" + @echo "Optional: create 'bleh' group for socket access:" + @echo " sudo groupadd -r bleh" + @echo " sudo usermod -aG bleh $$USER" + @echo " (then re-login)" + @echo "" + @echo "Now run:" + @echo " systemctl daemon-reload" + @echo " systemctl enable --now blehd.service" + +uninstall-systemd: + systemctl stop blehd.service 2>/dev/null || true + systemctl disable blehd.service 2>/dev/null || true + rm -f $(DESTDIR)$(SYSCONFDIR)/systemd/system/blehd.service + systemctl daemon-reload 2>/dev/null || true + @echo "Removed systemd service: $(SYSCONFDIR)/systemd/system/blehd.service" + +install-openrc: + install -Dm755 dist/openrc/blehd $(DESTDIR)$(SYSCONFDIR)/init.d/blehd + @echo "Installed OpenRC service: $(SYSCONFDIR)/init.d/blehd" + @echo "" + @echo "Optional: create 'bleh' group for socket access:" + @echo " sudo groupadd -r bleh" + @echo " sudo usermod -aG bleh $$USER" + @echo " (then re-login)" + @echo "" + @echo "Now run: rc-update add blehd default && rc-service blehd start" + +uninstall-openrc: + rc-service blehd stop 2>/dev/null || true + rc-update del blehd default 2>/dev/null || true + rm -f $(DESTDIR)$(SYSCONFDIR)/init.d/blehd + @echo "Removed OpenRC service: $(SYSCONFDIR)/init.d/blehd" diff --git a/README.md b/README.md new file mode 100644 index 0000000..597a6b2 --- /dev/null +++ b/README.md @@ -0,0 +1,96 @@ +# Bleh! + +

+ +

+ +**Bleh!** is a command-line utility to print images on the MXW01 Bluetooth thermal printer. +It supports 1-bit (1bpp) and 4-bit (4bpp) printing, various dithering algorithms, PNG preview output, and direct communication with the printer via BLE. + +## Features + +* Print PNG/JPG images (from file or stdin) in 1bpp or 4bpp mode +* Multiple dithering algorithms (Floyd-Steinberg, Bayer, Atkinson, etc.) +* Query printer status, battery, version, and more +* Output a PNG preview instead of printing (for integration or testing) +* Command-line interface with fine-grained options +* Works on Linux using BlueZ (via [go-ble/ble](https://github.com/go-ble/ble)) + +## Compiling + +On a Linux system: + +```sh +make build +``` + +(or `go build ./...` if you prefer) + +## Running (recommended: root daemon + unprivileged CLI) + +Start the daemon as root: + +```sh +sudo ./bin/blehd --socket /run/bleh/blehd.sock --group bleh +``` + +Then run the CLI as your normal user: + +```sh +./bin/bleh -s +./bin/bleh -i 100 ./image.png +``` + +The daemon restricts socket access via the `--group` flag. Add your user to that group: + +```sh +sudo groupadd -r bleh +sudo usermod -aG bleh $USER +# log out and back in +``` + +For a permanent setup, install the systemd service (see `dist/INSTALL.md`). + +## Usage + +```sh +bleh [options] +``` + +### Options + +| Option | Description | +| -------------------- | ----------------------------------------------------------------------------------- | +| `-i`, `--intensity` | Print intensity (0-100) (default: 80) | +| `-m`, `--mode` | Print mode: 1bpp or 4bpp (default: "1bpp") | +| `-d`, `--dither` | Dither method: none, floyd, bayer2x2, bayer4x4, bayer8x8, bayer16x16, atkinson, jjn | +| `-s`, `--status` | Query printer status | +| `-b`, `--battery` | Query battery level | +| `-v`, `--version` | Query printer version | +| `-p`, `--printtype` | Query print type | +| `-q`, `--querycount` | Query internal counter | +| `-E`, `--eject` | Eject paper by N lines | +| `-R`, `--retract` | Retract paper by N lines | +| `-o`, `--output` | Output PNG preview instead of printing. If value is "-", writes PNG to stdout. | +| `` | Path to PNG/JPG image to print, or "-" for stdin | + +### Example + +```sh +bleh -m 4bpp -d floyd ./myimage.png +``` + +## Requirements + +* Go 1.18+ +* BlueZ on Linux (for BLE support) +* Dependencies listed in `go.mod` (see source) + +## License + +This project is licensed under the terms of the GNU General Public License v3.0 or later. +Parts of the code were ported from [CatPrinterBLE](https://github.com/MaikelChan/CatPrinterBLE) and are licensed under the MIT License. +See the [`LICENSE`](./LICENSE) file for details. + +> **Disclaimer:** +> While a license was only added after the project’s initial commits, the current license applies retroactively to all previous commits of this repository. diff --git a/bleh.jpg b/bleh.jpg new file mode 100644 index 0000000000000000000000000000000000000000..e7eb4b46a65b62138cf049f4672ea2920418c19c GIT binary patch literal 32508 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 B!uS9H literal 0 HcmV?d00001 diff --git a/cmd/bleh/main.go b/cmd/bleh/main.go new file mode 100644 index 0000000..105f044 --- /dev/null +++ b/cmd/bleh/main.go @@ -0,0 +1,346 @@ +package main + +import ( + "bufio" + "encoding/base64" + "encoding/json" + "flag" + "fmt" + "image" + "io" + "log" + "net" + "os" + "time" + + "bleh/internal/imageproc" + "bleh/internal/ipc" + "bleh/internal/mxw01" + + "github.com/disintegration/imaging" +) + +const defaultSock = "/run/bleh/blehd.sock" + +var ( + intensity int + mode string + ditherType string + getStatus bool + getBattery bool + getVersion bool + getPrintType bool + getQueryCount bool + ejectPaper uint + retractPaper uint + outputPath string + address string + socketPath string + jsonOutput bool + version = "dev" +) + +func init() { + flag.IntVar(&intensity, "intensity", 80, "Print intensity (0-100)") + flag.IntVar(&intensity, "i", 80, "Print intensity (0-100)") + + flag.StringVar(&mode, "mode", "1bpp", "Print mode: 1bpp or 4bpp") + flag.StringVar(&mode, "m", "1bpp", "Print mode: 1bpp or 4bpp") + + flag.StringVar(&ditherType, "dither", "none", "Dither method: none, floyd, bayer2x2, bayer4x4, bayer8x8, bayer16x16, atkinson, jjn") + flag.StringVar(&ditherType, "d", "none", "Dither method: none, floyd, bayer2x2, bayer4x4, bayer8x8, bayer16x16, atkinson, jjn") + + flag.BoolVar(&getStatus, "status", false, "Query printer status") + flag.BoolVar(&getStatus, "s", false, "Query printer status") + + flag.BoolVar(&getBattery, "battery", false, "Query battery level") + flag.BoolVar(&getBattery, "b", false, "Query battery level") + + flag.BoolVar(&getVersion, "version", false, "Query printer version") + flag.BoolVar(&getVersion, "v", false, "Query printer version") + + flag.BoolVar(&getPrintType, "printtype", false, "Query print type") + flag.BoolVar(&getPrintType, "p", false, "Query print type") + + flag.BoolVar(&getQueryCount, "querycount", false, "Query internal counter") + flag.BoolVar(&getQueryCount, "q", false, "Query internal counter") + + flag.UintVar(&ejectPaper, "eject", 0, "Eject paper by N lines") + flag.UintVar(&ejectPaper, "E", 0, "Eject paper by N lines") + + flag.UintVar(&retractPaper, "retract", 0, "Retract paper by N lines") + flag.UintVar(&retractPaper, "R", 0, "Retract paper by N lines") + + flag.StringVar(&outputPath, "o", "", "Output PNG preview instead of printing (specify output path)") + flag.StringVar(&outputPath, "output", "", "Output PNG preview instead of printing (specify output path)") + + flag.StringVar(&address, "a", "", "Connect to printer by MAC address") + flag.StringVar(&address, "address", "", "Connect to printer by MAC address") + + flag.StringVar(&socketPath, "socket", "", "blehd Unix socket path (default: auto-detect)") + flag.BoolVar(&jsonOutput, "json", false, "Output machine-readable JSON") +} + +func main() { + flag.Parse() + + if outputPath != "-" { + log.Println("Bleh! Cat Printer Utility for MXW01, version", version) + } + + needNotifications := getStatus || getBattery || getVersion || getPrintType || getQueryCount || ejectPaper > 0 || retractPaper > 0 + needPrinter := needNotifications || (flag.NArg() > 0 && outputPath == "") + + if !needPrinter && outputPath == "" { + log.Println("Nothing to do. Use -h for help.") + log.Println("Done!") + return + } + + // Print mode + var printMode mxw01.PrintMode + switch mode { + case "1bpp": + printMode = mxw01.Mode1bpp + case "4bpp": + printMode = mxw01.Mode4bpp + default: + log.Fatalf("Invalid mode. Use '1bpp' or '4bpp'.") + } + + imagePath := flag.Arg(0) + var pixels []byte + var height int + var err error + + if imagePath != "" { + img, err := imageproc.DecodeImage(imagePath) + if err != nil { + log.Fatalf("Failed to load image: %v", err) + } + img = imageproc.PadImageToMinLines(img, mxw01.MinLines) + + switch printMode { + case mxw01.Mode1bpp: + pixels, height, err = imageproc.LoadImageMonoFromImage(img, ditherType) + case mxw01.Mode4bpp: + pixels, height, err = imageproc.LoadImage4BitFromImage(img, ditherType) + } + if err != nil { + log.Fatalf("Image conversion error: %v", err) + } + } + + if outputPath != "" { + writePreview(printMode, pixels, height) + return + } + + c, usedSock, err := dialAuto(socketPath) + if err != nil { + log.Fatalf("Could not connect to blehd: %v\nStart it with: ./blehd --socket %s", err, defaultSock) + } + _ = usedSock + defer c.Close() + + id := 1 + call := func(method string, params map[string]any) *ipc.Response { + req := ipc.Request{ID: fmt.Sprintf("%d", id), Method: method, Params: params} + id++ + if err := ipc.EncodeLine(c, req); err != nil { + log.Fatalf("send failed: %v", err) + } + resp, err := readResp(c) + if err != nil { + log.Fatalf("read failed: %v", err) + } + if !resp.OK { + log.Fatalf("%s failed: %s", method, resp.Error.Message) + } + return resp + } + + params := map[string]any{} + if address != "" { + params["address"] = address + } + + if needNotifications { + if getStatus { + resp := call("printer.status.get", params) + printResult("printer.status.get", resp.Result) + } + if getBattery { + resp := call("printer.battery.get", params) + printResult("printer.battery.get", resp.Result) + } + if getVersion { + resp := call("printer.version.get", params) + printResult("printer.version.get", resp.Result) + } + if getPrintType { + resp := call("printer.printtype.get", params) + printResult("printer.printtype.get", resp.Result) + } + if getQueryCount { + resp := call("printer.querycount.get", params) + printResult("printer.querycount.get", resp.Result) + } + if ejectPaper > 0 { + p := cloneMap(params) + p["lines"] = int(ejectPaper) + resp := call("paper.eject", p) + printResult("paper.eject", resp.Result) + } + if retractPaper > 0 { + p := cloneMap(params) + p["lines"] = int(retractPaper) + resp := call("paper.retract", p) + printResult("paper.retract", resp.Result) + } + } + + if flag.NArg() > 0 { + i := intensity + if i < 0 { + i = 0 + } + if i > 100 { + i = 100 + } + p := cloneMap(params) + p["mode"] = mode + p["intensity"] = i + p["height"] = height + p["pixels_b64"] = base64.StdEncoding.EncodeToString(pixels) + resp := call("print.start", p) + printResult("print.start", resp.Result) + } + + log.Println("Done!") +} + +func writePreview(printMode mxw01.PrintMode, pixels []byte, height int) { + var previewImg image.Image + switch printMode { + case mxw01.Mode1bpp: + previewImg = imageproc.RenderPreviewFrom1bpp(pixels, mxw01.LinePixels, height) + case mxw01.Mode4bpp: + previewImg = imageproc.RenderPreviewFrom4bpp(pixels, mxw01.LinePixels, height) + } + + var out io.Writer + if outputPath == "-" { + out = os.Stdout + } else { + f, err := os.Create(outputPath) + if err != nil { + log.Fatalf("Failed to create output file: %v", err) + } + defer f.Close() + out = bufio.NewWriter(f) + defer func() { _ = out.(*bufio.Writer).Flush() }() + } + + if err := imaging.Encode(out, previewImg, imaging.PNG); err != nil { + log.Fatalf("Failed to write PNG preview: %v", err) + } + if outputPath != "-" { + log.Printf("Preview PNG written to %s\n", outputPath) + } +} + +func dial(sock string) (net.Conn, error) { + return net.DialTimeout("unix", sock, 2*time.Second) +} + +func dialAuto(sock string) (net.Conn, string, error) { + if sock != "" { + c, err := dial(sock) + return c, sock, err + } + + candidates := []string{} + if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" { + candidates = append(candidates, xdg+"/bleh/blehd.sock") + } + candidates = append(candidates, defaultSock) + + var lastErr error + for _, p := range candidates { + c, err := dial(p) + if err == nil { + return c, p, nil + } + lastErr = err + } + if lastErr == nil { + lastErr = fmt.Errorf("no socket candidates") + } + return nil, "", lastErr +} + +func readResp(c net.Conn) (*ipc.Response, error) { + r := bufio.NewReader(c) + line, err := ipc.ReadLine(r) + if err != nil { + return nil, err + } + var resp ipc.Response + if err := jsonUnmarshal(line, &resp); err != nil { + return nil, err + } + return &resp, nil +} + +func cloneMap(m map[string]any) map[string]any { + out := make(map[string]any, len(m)+1) + for k, v := range m { + out[k] = v + } + return out +} + +func jsonUnmarshal(b []byte, v any) error { + // Small helper to avoid importing encoding/json at top-level with name conflicts. + return json.Unmarshal(b, v) +} + +func jsonPretty(v any) ([]byte, error) { + return json.MarshalIndent(v, "", " ") +} + +func printResult(method string, result any) { + if result == nil { + return + } + if jsonOutput { + b, _ := jsonPretty(result) + fmt.Println(string(b)) + return + } + + m, _ := result.(map[string]any) + switch method { + case "printer.status.get": + fmt.Printf("Status: %v (%s), Battery: %v, Temp: %v\n", + m["ok"], m["state"], m["battery"], m["temp"]) + case "printer.battery.get": + fmt.Printf("Battery level: %v\n", m["battery"]) + case "printer.version.get": + fmt.Printf("Version: %v, Print type: %v\n", m["version"], m["printType"]) + case "printer.printtype.get": + fmt.Printf("Print type: %v\n", m["printType"]) + case "printer.querycount.get": + fmt.Printf("Query count: %v\n", m["queryCount"]) + case "paper.eject": + fmt.Printf("Ejecting paper (%v lines)...\n", m["eject"]) + case "paper.retract": + fmt.Printf("Retracting paper (%v lines)...\n", m["retract"]) + case "print.start": + fmt.Println("Printed.") + default: + b, _ := jsonPretty(result) + fmt.Println(string(b)) + } +} diff --git a/cmd/blehd/main.go b/cmd/blehd/main.go new file mode 100644 index 0000000..be43144 --- /dev/null +++ b/cmd/blehd/main.go @@ -0,0 +1,424 @@ +package main + +import ( + "bufio" + "context" + "encoding/base64" + "encoding/json" + "errors" + "flag" + "fmt" + "log" + "net" + "os" + "os/signal" + "path/filepath" + "strconv" + "sync" + "syscall" + "time" + + "bleh/internal/ipc" + "bleh/internal/mxw01" + + ble "github.com/go-ble/ble" + "github.com/go-ble/ble/linux" + "os/user" +) + +const ( + defaultSock = "/run/bleh/blehd.sock" +) + +func autoSocketPath(explicit string) (string, error) { + if explicit != "" { + return explicit, nil + } + if xdg := os.Getenv("XDG_RUNTIME_DIR"); xdg != "" { + return filepath.Join(xdg, "bleh", "blehd.sock"), nil + } + return defaultSock, nil +} + +var printerMu sync.Mutex + +func main() { + var socketPath string + var groupName string + flag.StringVar(&socketPath, "socket", "", "Unix socket path (default: auto-detect)") + flag.StringVar(&groupName, "group", "bleh", "Group name to own the socket") + flag.Parse() + + resolvedSock, err := autoSocketPath(socketPath) + if err != nil { + log.Fatalf("Failed to resolve socket path: %v", err) + } + socketPath = resolvedSock + + ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) + defer stop() + + // Init BLE device once. + d, err := linux.NewDevice() + if err != nil { + log.Printf("Failed to open BLE device: %v", err) + log.Printf("Hint: blehd needs CAP_NET_RAW and CAP_NET_ADMIN. Example:") + log.Printf(" sudo setcap cap_net_raw,cap_net_admin=eip $(which blehd)") + log.Fatalf("Exiting.") + } + ble.SetDefaultDevice(d) + + if err := os.MkdirAll(filepath.Dir(socketPath), 0o755); err != nil { + log.Fatalf("Failed to create socket dir: %v", err) + } + // Remove stale socket. + _ = os.Remove(socketPath) + + ln, err := net.Listen("unix", socketPath) + if err != nil { + log.Fatalf("Listen failed: %v", err) + } + defer ln.Close() + + // Set group ownership + perms. + if err := setSocketPerms(socketPath, groupName); err != nil { + log.Printf("Warning: failed to set socket permissions: %v", err) + log.Printf("Hint: if running unprivileged, prefer an XDG runtime socket (set $XDG_RUNTIME_DIR)") + } + + log.Printf("blehd listening on %s", socketPath) + + go func() { + <-ctx.Done() + _ = ln.Close() + _ = os.Remove(socketPath) + }() + + for { + c, err := ln.Accept() + if err != nil { + if errors.Is(err, net.ErrClosed) || ctx.Err() != nil { + return + } + log.Printf("accept error: %v", err) + continue + } + go handleConn(ctx, c) + } +} + +func setSocketPerms(path, group string) error { + grp, err := user.LookupGroup(group) + if err != nil { + return err + } + gid, err := strconv.Atoi(grp.Gid) + if err != nil { + return err + } + // Keep uid unchanged, set gid. + if err := os.Chown(path, -1, gid); err != nil { + return err + } + return os.Chmod(path, 0o660) +} + +func handleConn(ctx context.Context, c net.Conn) { + defer c.Close() + r := bufio.NewReader(c) + w := bufio.NewWriter(c) + defer w.Flush() + + for { + line, err := ipc.ReadLine(r) + if err != nil { + return + } + req, err := ipc.DecodeRequestLine(line) + if err != nil { + _ = ipc.EncodeLine(w, ipc.Response{OK: false, Error: &ipc.Error{Code: "EBADJSON", Message: err.Error()}}) + _ = w.Flush() + continue + } + + resp := dispatch(ctx, req) + _ = ipc.EncodeLine(w, resp) + _ = w.Flush() + } +} + +func dispatch(ctx context.Context, req *ipc.Request) ipc.Response { + if req.ID == "" { + req.ID = "-" + } + method := req.Method + + // Serialize access to the printer to avoid concurrent BLE sessions stomping each other. + // (This can be relaxed later if the printer/stack supports it reliably.) + printerMu.Lock() + defer printerMu.Unlock() + + switch method { + case "printer.status.get": + st, err := doQuery(ctx, req.Params, 0xA1) + if err != nil { + return fail(req.ID, err) + } + s, err := mxw01.DecodeStatusNotification(st) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, s) + + case "printer.battery.get": + b, err := doQuery(ctx, req.Params, 0xAB) + if err != nil { + return fail(req.ID, err) + } + pct, err := mxw01.DecodeBatteryNotification(b) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, map[string]any{"battery": pct}) + + case "printer.version.get": + b, err := doQuery(ctx, req.Params, 0xB1) + if err != nil { + return fail(req.ID, err) + } + v, err := mxw01.DecodeVersionNotification(b) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, v) + + case "printer.printtype.get": + b, err := doQuery(ctx, req.Params, 0xB0) + if err != nil { + return fail(req.ID, err) + } + t, err := mxw01.DecodePrintTypeNotification(b) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, map[string]any{"printType": t}) + + case "printer.querycount.get": + b, err := doQuery(ctx, req.Params, 0xA7) + if err != nil { + return fail(req.ID, err) + } + qc, err := mxw01.DecodeQueryCountNotification(b) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, map[string]any{"queryCount": fmt.Sprintf("% X", qc)}) + + case "paper.eject": + lines, _ := getInt(req.Params, "lines") + err := doLineCommand(ctx, req.Params, 0xA3, uint(lines)) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, map[string]any{"eject": lines}) + + case "paper.retract": + lines, _ := getInt(req.Params, "lines") + err := doLineCommand(ctx, req.Params, 0xA4, uint(lines)) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, map[string]any{"retract": lines}) + + case "print.start": + err := doPrint(ctx, req.Params) + if err != nil { + return fail(req.ID, err) + } + return ok(req.ID, map[string]any{"printed": true}) + + default: + return ipc.Response{ID: req.ID, OK: false, Error: &ipc.Error{Code: "ENOIMPL", Message: "unknown method"}} + } +} + +func ok(id string, result any) ipc.Response { + return ipc.Response{ID: id, OK: true, Result: result} +} + +func fail(id string, err error) ipc.Response { + return ipc.Response{ID: id, OK: false, Error: &ipc.Error{Code: "EFAIL", Message: err.Error()}} +} + +func getString(m map[string]any, key string) (string, bool) { + v, ok := m[key] + if !ok { + return "", false + } + s, ok := v.(string) + return s, ok +} + +func getInt(m map[string]any, key string) (int, bool) { + v, ok := m[key] + if !ok { + return 0, false + } + switch t := v.(type) { + case float64: + return int(t), true + case int: + return t, true + case json.Number: + i, err := t.Int64() + return int(i), err == nil + default: + return 0, false + } +} + +func doQuery(ctx context.Context, params map[string]any, cmd byte) ([]byte, error) { + addr, _ := getString(params, "address") + + cctx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + + adv, err := mxw01.FindPrinter(cctx, addr) + if err != nil { + return nil, err + } + + client, err := ble.Dial(cctx, adv.Addr()) + if err != nil { + return nil, err + } + defer client.CancelConnection() + + mtu, err := client.ExchangeMTU(100) + if err == nil { + _ = mtu + } + + printChr, notifyChr, _, err := mxw01.DiscoverChars(client) + if err != nil { + return nil, err + } + if notifyChr == nil { + return nil, fmt.Errorf("missing notification characteristic") + } + + notifs := make(chan []byte, 8) + _, _ = client.DiscoverDescriptors(nil, notifyChr) + err = client.Subscribe(notifyChr, false, func(b []byte) { + select { + case notifs <- append([]byte{}, b...): + default: + } + }) + if err != nil { + return nil, err + } + + if err := mxw01.SendSimpleCommand(client, printChr, cmd); err != nil { + return nil, err + } + + deadline := time.NewTimer(2 * time.Second) + defer deadline.Stop() + for { + select { + case b := <-notifs: + c, _, perr := mxw01.ParseNotification(b) + if perr == nil && c == cmd { + return b, nil + } + case <-deadline.C: + return nil, fmt.Errorf("timeout waiting for notification 0x%02X", cmd) + case <-cctx.Done(): + return nil, cctx.Err() + } + } +} + +func doLineCommand(ctx context.Context, params map[string]any, cmd byte, lines uint) error { + addr, _ := getString(params, "address") + + cctx, cancel := context.WithTimeout(ctx, 15*time.Second) + defer cancel() + + adv, err := mxw01.FindPrinter(cctx, addr) + if err != nil { + return err + } + client, err := ble.Dial(cctx, adv.Addr()) + if err != nil { + return err + } + defer client.CancelConnection() + + printChr, _, _, err := mxw01.DiscoverChars(client) + if err != nil { + return err + } + return mxw01.SendLineCommand(client, printChr, cmd, lines) +} + +func doPrint(ctx context.Context, params map[string]any) error { + addr, _ := getString(params, "address") + modeStr, _ := getString(params, "mode") + intensity, _ := getInt(params, "intensity") + height, _ := getInt(params, "height") + pixelsB64, _ := getString(params, "pixels_b64") + + if height <= 0 { + return fmt.Errorf("invalid height") + } + pixels, err := base64.StdEncoding.DecodeString(pixelsB64) + if err != nil { + return fmt.Errorf("decode pixels: %v", err) + } + + pm := mxw01.Mode1bpp + switch modeStr { + case "1bpp": + pm = mxw01.Mode1bpp + case "4bpp": + pm = mxw01.Mode4bpp + default: + return fmt.Errorf("invalid mode") + } + if intensity < 0 { + intensity = 0 + } + if intensity > 100 { + intensity = 100 + } + + cctx, cancel := context.WithTimeout(ctx, 60*time.Second) + defer cancel() + + adv, err := mxw01.FindPrinter(cctx, addr) + if err != nil { + return err + } + client, err := ble.Dial(cctx, adv.Addr()) + if err != nil { + return err + } + defer client.CancelConnection() + + mtu, err := client.ExchangeMTU(100) + if err != nil { + mtu = 23 + } + + printChr, _, dataChr, err := mxw01.DiscoverChars(client) + if err != nil { + return err + } + if printChr == nil || dataChr == nil { + return fmt.Errorf("missing required characteristics") + } + + return mxw01.SendImageBufferToPrinter(client, dataChr, printChr, pixels, height, pm, byte(intensity), mtu) +} diff --git a/demo.jpg b/demo.jpg new file mode 100644 index 0000000000000000000000000000000000000000..385940527de0c64fc927a2c93725641c882f578a GIT binary patch literal 117685 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 KUmEf1ng7`gl%~@F literal 0 HcmV?d00001 diff --git a/dist/INSTALL.md b/dist/INSTALL.md new file mode 100644 index 0000000..4ce1b8b --- /dev/null +++ b/dist/INSTALL.md @@ -0,0 +1,85 @@ +# bleh / blehd install notes + +## Recommended model + +- `bleh` is unprivileged. +- `blehd` runs as **root** (recommended). It owns the BLE device, and exposes a Unix socket for `bleh` to use. +- Access to that socket can be restricted with `--group` (recommended). + +## Build + +```sh +make build +``` + +## Install (system) + +```sh +sudo make install PREFIX=/usr/local +``` + +By default (`SETCAP=auto`), `make install` will apply capabilities to `blehd` when run as root. + +If you plan to run `blehd` as a **root system service** (recommended), you can skip capabilities: + +```sh +sudo make install SETCAP=0 +``` + +## Group access (optional) + +If you want group-based access to the socket: + +```sh +sudo groupadd -r bleh || true +sudo usermod -aG bleh $USER +# then re-login +``` + +Then run blehd with `--group bleh`. + +## systemd service (recommended) + +Install the unit: + +```sh +sudo make install-systemd +``` + +Enable it: + +```sh +sudo systemctl daemon-reload +sudo systemctl enable --now blehd.service +``` + +This will run `blehd` as root, listening on: + +- `/run/bleh/blehd.sock` + +To uninstall: + +```sh +sudo make uninstall-systemd +``` + +## OpenRC service + +Install the init script: + +```sh +sudo make install-openrc +``` + +Enable it: + +```sh +sudo rc-update add blehd default +sudo rc-service blehd start +``` + +To uninstall: + +```sh +sudo make uninstall-openrc +``` diff --git a/dist/openrc/blehd b/dist/openrc/blehd new file mode 100644 index 0000000..a4faa75 --- /dev/null +++ b/dist/openrc/blehd @@ -0,0 +1,17 @@ +#!/sbin/openrc-run + +name="blehd" +description="Bleh MXW01 privileged helper daemon" + +command="/usr/local/bin/blehd" +command_args="--socket /run/bleh/blehd.sock --group bleh" +command_background=true +pidfile="/run/${name}.pid" + +start_pre() { + checkpath -d -m 0755 /run/bleh +} + +depend() { + after bluetooth +} diff --git a/dist/systemd/blehd-root.service b/dist/systemd/blehd-root.service new file mode 100644 index 0000000..e200d79 --- /dev/null +++ b/dist/systemd/blehd-root.service @@ -0,0 +1,27 @@ +[Unit] +Description=Bleh MXW01 helper daemon (root) +After=network.target + +[Service] +Type=simple +ExecStart=/usr/local/bin/blehd --socket /run/bleh/blehd.sock --group bleh +Restart=on-failure +RestartSec=1 + +RuntimeDirectory=bleh +RuntimeDirectoryMode=0755 + +# Hardening (still useful even as root) +NoNewPrivileges=true +PrivateTmp=true +ProtectSystem=strict +ProtectHome=true +ProtectKernelTunables=true +ProtectKernelModules=true +ProtectControlGroups=true +RestrictSUIDSGID=true +LockPersonality=true +MemoryDenyWriteExecute=true + +[Install] +WantedBy=multi-user.target diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..a130cf5 --- /dev/null +++ b/go.mod @@ -0,0 +1,19 @@ +module bleh + +go 1.22 + +require ( + github.com/disintegration/imaging v1.6.2 + github.com/go-ble/ble v0.0.0-20240122180141-8c5522f54333 + github.com/makeworld-the-better-one/dither v1.0.0 +) + +require ( + github.com/mattn/go-colorable v0.1.6 // indirect + github.com/mattn/go-isatty v0.0.12 // indirect + github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect + github.com/mgutz/logxi v0.0.0-20161027140823-aebf8a7d67ab // indirect + github.com/pkg/errors v0.8.1 // indirect + golang.org/x/image v0.0.0-20191009234506-e7c1f5e7dbb8 // indirect + golang.org/x/sys v0.0.0-20211204120058-94396e421777 // indirect +) diff --git a/internal/imageproc/imageproc.go b/internal/imageproc/imageproc.go new file mode 100644 index 0000000..e7a4cc9 --- /dev/null +++ b/internal/imageproc/imageproc.go @@ -0,0 +1,189 @@ +package imageproc + +import ( + "fmt" + "image" + "image/color" + _ "image/gif" + _ "image/jpeg" + _ "image/png" + "io" + "os" + + "github.com/disintegration/imaging" + dither "github.com/makeworld-the-better-one/dither" + + "bleh/internal/mxw01" +) + +// DecodeImage loads an image from a given path or stdin ("-"). +func DecodeImage(path string) (image.Image, error) { + if path == "-" { + return DecodeImageFromReader(os.Stdin) + } + img, err := imaging.Open(path, imaging.AutoOrientation(true)) + if err != nil { + return nil, fmt.Errorf("failed to open image %q: %v", path, err) + } + return img, nil +} + +func DecodeImageFromReader(r io.Reader) (image.Image, error) { + img, _, err := image.Decode(r) + if err != nil { + return nil, fmt.Errorf("decode error: %v", err) + } + return img, nil +} + +func PadImageToMinLines(img image.Image, minLines int) image.Image { + bounds := img.Bounds() + if bounds.Dy() >= minLines { + return img + } + dst := imaging.New(bounds.Dx(), minLines, color.White) + dst = imaging.Paste(dst, img, image.Pt(0, 0)) + return dst +} + +func LoadImageMonoFromImage(img image.Image, ditherType string) ([]byte, int, error) { + b := img.Bounds() + if b.Dx() <= 0 || b.Dy() <= 0 { + return nil, 0, fmt.Errorf("invalid image bounds: %v", b) + } + ratio := float64(b.Dx()) / float64(b.Dy()) + height := int(float64(mxw01.LinePixels) / ratio) + if height <= 0 { + return nil, 0, fmt.Errorf("computed invalid height: %d", height) + } + + img = imaging.Resize(img, mxw01.LinePixels, height, imaging.Lanczos) + img = imaging.Grayscale(img) + + if ditherType != "none" { + palette := []color.Color{color.Black, color.White} + d := dither.NewDitherer(palette) + switch ditherType { + case "floyd": + d.Matrix = dither.FloydSteinberg + case "bayer2x2": + d.Mapper = dither.Bayer(2, 2, 1.0) + case "bayer4x4": + d.Mapper = dither.Bayer(4, 4, 1.0) + case "bayer8x8": + d.Mapper = dither.Bayer(8, 8, 1.0) + case "bayer16x16": + d.Mapper = dither.Bayer(16, 16, 1.0) + case "atkinson": + d.Matrix = dither.Atkinson + case "jjn": + d.Matrix = dither.JarvisJudiceNinke + default: + return nil, 0, fmt.Errorf("unknown dither type: %s", ditherType) + } + img = d.DitherCopy(img) + } else { + img = imaging.AdjustContrast(img, 10) + } + + pixels := make([]byte, (mxw01.LinePixels*height)/8) + for y := 0; y < height; y++ { + for x := 0; x < mxw01.LinePixels; x++ { + gray := color.GrayModel.Convert(img.At(x, y)).(color.Gray) + if gray.Y < 128 { + idx := (y*mxw01.LinePixels + x) / 8 + pixels[idx] |= 1 << (x % 8) + } + } + } + + return pixels, height, nil +} + +func LoadImage4BitFromImage(img image.Image, ditherType string) ([]byte, int, error) { + b := img.Bounds() + if b.Dx() <= 0 || b.Dy() <= 0 { + return nil, 0, fmt.Errorf("invalid image bounds: %v", b) + } + ratio := float64(b.Dx()) / float64(b.Dy()) + height := int(float64(mxw01.LinePixels) / ratio) + if height <= 0 { + return nil, 0, fmt.Errorf("computed invalid height: %d", height) + } + + img = imaging.Resize(img, mxw01.LinePixels, height, imaging.Lanczos) + img = imaging.Grayscale(img) + + palette := make([]color.Color, 16) + for i := 0; i < 16; i++ { + v := uint8(i * 17) + palette[i] = color.Gray{Y: 255 - v} + } + + if ditherType != "none" { + d := dither.NewDitherer(palette) + switch ditherType { + case "floyd": + d.Matrix = dither.FloydSteinberg + case "bayer2x2": + d.Mapper = dither.Bayer(2, 2, 0.2) + case "bayer4x4": + d.Mapper = dither.Bayer(4, 4, 0.2) + case "bayer8x8": + d.Mapper = dither.Bayer(8, 8, 0.2) + case "bayer16x16": + d.Mapper = dither.Bayer(16, 16, 0.2) + case "atkinson": + d.Matrix = dither.Atkinson + case "jjn": + d.Matrix = dither.JarvisJudiceNinke + default: + return nil, 0, fmt.Errorf("unknown dither type: %s", ditherType) + } + img = d.DitherCopy(img) + } + + width := mxw01.LinePixels + pixels := make([]byte, (width*height)/2) + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + gray := color.GrayModel.Convert(img.At(x, y)).(color.Gray) + level := (255 - gray.Y) >> 4 + idx := (y*width + x) >> 1 + shift := uint(((x & 1) ^ 1) << 2) + pixels[idx] |= byte(level) << shift + } + } + + return pixels, height, nil +} + +func RenderPreviewFrom1bpp(pixels []byte, width, height int) image.Image { + img := image.NewGray(image.Rect(0, 0, width, height)) + for y := 0; y < height; y++ { + for x := 0; x < width; x++ { + idx := (y*width + x) / 8 + bit := uint(x % 8) + if pixels[idx]&(1<> 1 + shift := uint(((x & 1) ^ 1) << 2) + val := (pixels[idx] >> shift) & 0x0F + gray := 255 - val*17 + img.SetGray(x, y, color.Gray{Y: gray}) + } + } + return img +} diff --git a/internal/ipc/jsonl.go b/internal/ipc/jsonl.go new file mode 100644 index 0000000..5af0fc1 --- /dev/null +++ b/internal/ipc/jsonl.go @@ -0,0 +1,55 @@ +package ipc + +import ( + "bufio" + "bytes" + "encoding/json" + "fmt" + "io" +) + +const ( + // MaxLineBytes is the maximum size of a single JSON line accepted by the JSONL protocol. + // 1 MiB is enough for fairly large base64 pixel payloads while keeping memory bounded. + MaxLineBytes = 1 << 20 +) + +// ReadLine reads a single '\n'-terminated line from r with a hard size limit. +func ReadLine(r *bufio.Reader) ([]byte, error) { + var buf bytes.Buffer + for { + chunk, isPrefix, err := r.ReadLine() + if err != nil { + if err == io.EOF && buf.Len() > 0 { + return buf.Bytes(), nil + } + return nil, err + } + buf.Write(chunk) + if buf.Len() > MaxLineBytes { + return nil, fmt.Errorf("jsonl line too large (> %d bytes)", MaxLineBytes) + } + if !isPrefix { + break + } + } + return buf.Bytes(), nil +} + +func EncodeLine(w io.Writer, v any) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + b = append(b, '\n') + _, err = w.Write(b) + return err +} + +func DecodeRequestLine(line []byte) (*Request, error) { + var req Request + if err := json.Unmarshal(line, &req); err != nil { + return nil, err + } + return &req, nil +} diff --git a/internal/ipc/protocol.go b/internal/ipc/protocol.go new file mode 100644 index 0000000..8d22cea --- /dev/null +++ b/internal/ipc/protocol.go @@ -0,0 +1,22 @@ +package ipc + +// JSONL request/response protocol shared by bleh and blehd. + +type Request struct { + ID string `json:"id"` + Method string `json:"method"` + Params map[string]any `json:"params,omitempty"` +} + +type Error struct { + Code string `json:"code"` + Message string `json:"message"` +} + +type Response struct { + ID string `json:"id,omitempty"` + OK bool `json:"ok"` + Result any `json:"result,omitempty"` + Error *Error `json:"error,omitempty"` + Event string `json:"event,omitempty"` +} diff --git a/internal/mxw01/mxw01.go b/internal/mxw01/mxw01.go new file mode 100644 index 0000000..f6b649f --- /dev/null +++ b/internal/mxw01/mxw01.go @@ -0,0 +1,282 @@ +package mxw01 + +import ( + "context" + "errors" + "fmt" + "time" + + ble "github.com/go-ble/ble" +) + +var ( + MainServiceUUID = ble.MustParse("ae30") + PrintCharacteristic = ble.MustParse("ae01") + NotifyCharacteristic = ble.MustParse("ae02") + DatCharacteristic = ble.MustParse("ae03") + TargetPrinterName = "MXW01" + ScanTimeout = 10 * time.Second + PrintCommandHeader = []byte{0x22, 0x21} + PrintCommandFooter = byte(0xFF) +) + +type PrintMode byte + +const ( + Mode1bpp PrintMode = 0x00 + Mode4bpp PrintMode = 0x02 +) + +const ( + LinePixels = 384 + MinLines = 86 // firmware refuses to print anything shorter + DefaultSleep = 6 * time.Millisecond +) + +type Status struct { + OK bool `json:"ok"` + State string `json:"state"` + BatteryPct int `json:"battery"` + TempC int `json:"temp"` +} + +type Version struct { + Version string `json:"version"` + PrintType string `json:"printType"` +} + +func FindPrinter(ctx context.Context, address string) (ble.Advertisement, error) { + var addr ble.Addr + var adv ble.Advertisement + + if address != "" { + addr = ble.NewAddr(address) + } + + ctxScan, cancel := context.WithTimeout(ctx, ScanTimeout) + defer cancel() + + err := ble.Scan(ctxScan, false, func(a ble.Advertisement) { + if address != "" { + if a.Addr().String() == addr.String() { + adv = a + cancel() + } + return + } + if a.LocalName() == TargetPrinterName { + adv = a + cancel() + } + }, nil) + if err != nil && !errors.Is(err, context.Canceled) { + return nil, fmt.Errorf("scan error: %w", err) + } + if adv == nil { + return nil, fmt.Errorf("printer not found") + } + return adv, nil +} + +func DiscoverChars(client ble.Client) (printChr, notifyChr, dataChr *ble.Characteristic, err error) { + services, err := client.DiscoverServices([]ble.UUID{MainServiceUUID}) + if err != nil || len(services) == 0 { + return nil, nil, nil, fmt.Errorf("service discovery failed: %v", err) + } + svc := services[0] + chars, err := client.DiscoverCharacteristics(nil, svc) + if err != nil { + return nil, nil, nil, fmt.Errorf("characteristic discovery failed: %v", err) + } + for _, c := range chars { + switch c.UUID.String() { + case PrintCharacteristic.String(): + printChr = c + case NotifyCharacteristic.String(): + notifyChr = c + case DatCharacteristic.String(): + dataChr = c + } + } + return printChr, notifyChr, dataChr, nil +} + +func BuildCommand(cmdId byte, payload []byte) []byte { + cmd := append([]byte{}, PrintCommandHeader...) + cmd = append(cmd, cmdId) + cmd = append(cmd, 0x00) // reserved + cmd = append(cmd, byte(len(payload)&0xFF), byte(len(payload)>>8)) + cmd = append(cmd, payload...) + cmd = append(cmd, CalculateCRC8(payload)) + cmd = append(cmd, PrintCommandFooter) + return cmd +} + +func SendSimpleCommand(client ble.Client, printChr *ble.Characteristic, cmdId byte) error { + cmd := BuildCommand(cmdId, []byte{0x00}) + return client.WriteCharacteristic(printChr, cmd, true) +} + +func SendLineCommand(client ble.Client, printChr *ble.Characteristic, cmdId byte, lines uint) error { + param := []byte{byte(lines & 0xFF), byte(lines >> 8)} + cmd := BuildCommand(cmdId, param) + return client.WriteCharacteristic(printChr, cmd, true) +} + +func ParseNotification(data []byte) (cmd byte, payloadLen int, err error) { + if len(data) < 6 { + return 0, 0, fmt.Errorf("malformed notification (too short)") + } + if data[0] != 0x22 || data[1] != 0x21 { + return 0, 0, fmt.Errorf("invalid notification header") + } + cmd = data[2] + payloadLen = int(data[4]) | int(data[5])<<8 + return cmd, payloadLen, nil +} + +func DecodeStatusNotification(data []byte) (*Status, error) { + _, _, err := ParseNotification(data) + if err != nil { + return nil, err + } + if len(data) < 14 { + return nil, fmt.Errorf("malformed status notification") + } + battery := int(data[9]) + temp := int(data[10]) + statusOk := data[12] == 0 + statusCode := data[6] + errCode := data[13] + + statusMsg := "Unknown" + if statusOk { + switch statusCode { + case 0x0: + statusMsg = "Standby" + case 0x1: + statusMsg = "Printing" + case 0x2: + statusMsg = "Feeding paper" + case 0x3: + statusMsg = "Ejecting paper" + } + } else { + switch errCode { + case 0x1, 0x9: + statusMsg = "No paper" + case 0x4: + statusMsg = "Overheated" + case 0x8: + statusMsg = "Low battery" + } + } + + return &Status{OK: statusOk, State: statusMsg, BatteryPct: battery, TempC: temp}, nil +} + +func DecodeBatteryNotification(data []byte) (int, error) { + _, _, err := ParseNotification(data) + if err != nil { + return 0, err + } + if len(data) < 7 { + return 0, fmt.Errorf("malformed battery notification") + } + return int(data[6]), nil +} + +func DecodePrintTypeNotification(data []byte) (string, error) { + _, _, err := ParseNotification(data) + if err != nil { + return "", err + } + if len(data) < 7 { + return "", fmt.Errorf("malformed printtype notification") + } + switch data[6] { + case 0x01: + return "High pressure", nil + case 0xFF: + return "Unknown", nil + default: + return "Low pressure", nil + } +} + +func DecodeVersionNotification(data []byte) (*Version, error) { + _, dataLen, err := ParseNotification(data) + if err != nil { + return nil, err + } + if len(data) < 15 { + return nil, fmt.Errorf("malformed version notification (too short)") + } + if len(data) < 14+dataLen { + return nil, fmt.Errorf("malformed version notification") + } + ver := string(data[6 : 6+dataLen]) + pt := "Unknown" + switch data[14] { + case 0x32: + pt = "High pressure" + case 0x31: + pt = "Low pressure" + } + return &Version{Version: ver, PrintType: pt}, nil +} + +func DecodeQueryCountNotification(data []byte) ([]byte, error) { + _, _, err := ParseNotification(data) + if err != nil { + return nil, err + } + if len(data) < 12 { + return nil, fmt.Errorf("malformed querycount notification") + } + out := make([]byte, 6) + copy(out, data[6:12]) + return out, nil +} + +func CalculateCRC8(data []byte) byte { + table := [256]byte{ + 0x00, 0x07, 0x0e, 0x09, 0x1c, 0x1b, 0x12, 0x15, + 0x38, 0x3f, 0x36, 0x31, 0x24, 0x23, 0x2a, 0x2d, + 0x70, 0x77, 0x7e, 0x79, 0x6c, 0x6b, 0x62, 0x65, + 0x48, 0x4f, 0x46, 0x41, 0x54, 0x53, 0x5a, 0x5d, + 0xe0, 0xe7, 0xee, 0xe9, 0xfc, 0xfb, 0xf2, 0xf5, + 0xd8, 0xdf, 0xd6, 0xd1, 0xc4, 0xc3, 0xca, 0xcd, + 0x90, 0x97, 0x9e, 0x99, 0x8c, 0x8b, 0x82, 0x85, + 0xa8, 0xaf, 0xa6, 0xa1, 0xb4, 0xb3, 0xba, 0xbd, + 0xc7, 0xc0, 0xc9, 0xce, 0xdb, 0xdc, 0xd5, 0xd2, + 0xff, 0xf8, 0xf1, 0xf6, 0xe3, 0xe4, 0xed, 0xea, + 0xb7, 0xb0, 0xb9, 0xbe, 0xab, 0xac, 0xa5, 0xa2, + 0x8f, 0x88, 0x81, 0x86, 0x93, 0x94, 0x9d, 0x9a, + 0x27, 0x20, 0x29, 0x2e, 0x3b, 0x3c, 0x35, 0x32, + 0x1f, 0x18, 0x11, 0x16, 0x03, 0x04, 0x0d, 0x0a, + 0x57, 0x50, 0x59, 0x5e, 0x4b, 0x4c, 0x45, 0x42, + 0x6f, 0x68, 0x61, 0x66, 0x73, 0x74, 0x7d, 0x7a, + 0x89, 0x8e, 0x87, 0x80, 0x95, 0x92, 0x9b, 0x9c, + 0xb1, 0xb6, 0xbf, 0xb8, 0xad, 0xaa, 0xa3, 0xa4, + 0xf9, 0xfe, 0xf7, 0xf0, 0xe5, 0xe2, 0xeb, 0xec, + 0xc1, 0xc6, 0xcf, 0xc8, 0xdd, 0xda, 0xd3, 0xd4, + 0x69, 0x6e, 0x67, 0x60, 0x75, 0x72, 0x7b, 0x7c, + 0x51, 0x56, 0x5f, 0x58, 0x4d, 0x4a, 0x43, 0x44, + 0x19, 0x1e, 0x17, 0x10, 0x05, 0x02, 0x0b, 0x0c, + 0x21, 0x26, 0x2f, 0x28, 0x3d, 0x3a, 0x33, 0x34, + 0x4e, 0x49, 0x40, 0x47, 0x52, 0x55, 0x5c, 0x5b, + 0x76, 0x71, 0x78, 0x7f, 0x6a, 0x6d, 0x64, 0x63, + 0x3e, 0x39, 0x30, 0x37, 0x22, 0x25, 0x2c, 0x2b, + 0x06, 0x01, 0x08, 0x0f, 0x1a, 0x1d, 0x14, 0x13, + 0xae, 0xa9, 0xa0, 0xa7, 0xb2, 0xb5, 0xbc, 0xbb, + 0x96, 0x91, 0x98, 0x9f, 0x8a, 0x8d, 0x84, 0x83, + 0xde, 0xd9, 0xd0, 0xd7, 0xc2, 0xc5, 0xcc, 0xcb, + 0xe6, 0xe1, 0xe8, 0xef, 0xfa, 0xfd, 0xf4, 0xf3, + } + crc := byte(0) + for _, b := range data { + crc = table[crc^b] + } + return crc +} diff --git a/internal/mxw01/print.go b/internal/mxw01/print.go new file mode 100644 index 0000000..5ed7251 --- /dev/null +++ b/internal/mxw01/print.go @@ -0,0 +1,56 @@ +package mxw01 + +import ( + "fmt" + "time" + + ble "github.com/go-ble/ble" +) + +func SendImageBufferToPrinter(client ble.Client, dataChr, printChr *ble.Characteristic, pixels []byte, height int, mode PrintMode, intensity byte, attMTU int) error { + cmd := BuildCommand(0xA2, []byte{intensity}) + if err := client.WriteCharacteristic(printChr, cmd, true); err != nil { + return fmt.Errorf("intensity set failed: %v", err) + } + + param := []byte{byte(height & 0xFF), byte(height >> 8), 0x30, byte(mode)} + cmd = BuildCommand(0xA9, param) + if err := client.WriteCharacteristic(printChr, cmd, true); err != nil { + return fmt.Errorf("print command failed: %v", err) + } + + bytesPerLine := LinePixels / 8 + if mode == Mode4bpp { + bytesPerLine = LinePixels / 2 + } + + // ATT_MTU includes 3 bytes of ATT overhead for Write Command/Request. + payloadMTU := 20 + if attMTU > 3 { + payloadMTU = attMTU - 3 + } + if payloadMTU < 1 { + payloadMTU = 1 + } + + for y := 0; y < height; y++ { + slice := pixels[y*bytesPerLine : (y+1)*bytesPerLine] + for offset := 0; offset < len(slice); offset += payloadMTU { + end := offset + payloadMTU + if end > len(slice) { + end = len(slice) + } + chunk := slice[offset:end] + if err := client.WriteCharacteristic(dataChr, chunk, true); err != nil { + return fmt.Errorf("line %d chunk write failed: %v", y, err) + } + time.Sleep(DefaultSleep) + } + } + + cmd = BuildCommand(0xAD, []byte{0x00}) + if err := client.WriteCharacteristic(printChr, cmd, true); err != nil { + return fmt.Errorf("flush failed: %v", err) + } + return nil +}