Was ist das für Code?

Diese Seite verwendet Cookies. Durch die Nutzung unserer Seite erklären Sie sich damit einverstanden, dass wir Cookies setzen. Weitere Informationen

  • Was ist das für Code?

    Hallo,

    ich möchte gerne einen Epson ESC/POS Drucker in meine App integrieren. Dazu habe ich dieses Projekt gefunden:

    github.com/KevinGong2013/Printer

    Ich habe mir das Projekt per Cocoa Pods eingebunden und mir eine Function gebaut die nun auch schon Bons aus dem Drucker lockt. Ich habe nur ein Verständnisproblem mit dem Code für den Inhalt:

    Quellcode

    1. public struct bonSpeisenStruct {
    2. var name:String
    3. var bemerkung:String
    4. var preis:Double
    5. }
    6. public func printBon(speisen:[bonSpeisenStruct]){
    7. if globalBondruckerVerwenden {
    8. let host:NWEndpoint.Host = .init(globalBondruckerIP)
    9. let port:NWEndpoint.Port = .init(integerLiteral: UInt16(globalBondruckerPort) ?? 9100)
    10. let dateFormatter = DateFormatter()
    11. dateFormatter.dateFormat = "dd.MM.yy HH:mm:ss"
    12. dateFormatter.timeZone = TimeZone(identifier: "Europe/Berlin")
    13. let date:String = dateFormatter.string(from: Date())
    14. let speisenBon = Receipt(.init(maxWidthDensity: 500, fontDensity: 12, encoding: .utf8))
    15. <<~ .style(.initialize)
    16. <<~ .page(.printAndFeed(lines: 10))
    17. <<~ .layout(.justification(.center))
    18. <<< Dividing.default()
    19. <<~ .style(.underlineMode(.enable2dot))
    20. <<< "Speisen"
    21. <<< Dividing.default()
    22. <<~ .style(.underlineMode(.enable2dot))
    23. <<< KVItem(speisen[0].name, "\(speisen[0].preis)")
    24. <<< KVItem(speisen[1].name, "\(speisen[1].preis)")
    25. <<< KVItem(speisen[2].name, "\(speisen[2].preis)")
    26. <<< KVItem("", "\((speisen[0].preis + speisen[1].preis + speisen[2].preis))")
    27. <<~ .style(.initialize)
    28. <<~ .page(.printAndFeed(lines: 1))
    29. <<~ .layout(.justification(.center))
    30. <<< Dividing.default()
    31. <<~ .style(.underlineMode(.enable2dot))
    32. <<< speisen[2].bemerkung
    33. <<~ .style(.clear)
    34. <<~ .page(.printAndFeed(lines: 10))
    35. <<~ .page(.partialCut)
    36. let tcp = NWProtocolTCP.Options.init()
    37. tcp.noDelay = true
    38. let params = NWParameters.init(tls: nil, tcp: tcp)
    39. let connection = NWConnection(to: NWEndpoint.hostPort(host: host, port: port), using: params)
    40. connection.stateUpdateHandler = { newState in
    41. switch newState {
    42. case .ready:
    43. print("[MyDebug] Socket State: Ready")
    44. print("[MyDebug] send data")
    45. let content: Data = Data(speisenBon.data)
    46. connection.send(content: content, contentContext: .defaultMessage, completion: NWConnection.SendCompletion.contentProcessed(({ NWError in
    47. if (NWError == nil) {
    48. print("[MyDebug] Data was sent to TCP destination ")
    49. connection.cancel()
    50. } else {
    51. print("[MyDebug] ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
    52. }
    53. })))
    54. case .failed(let error):
    55. print("[MyDebug] Fatal connection error", error.localizedDescription)
    56. default:
    57. break
    58. }
    59. }
    60. connection.start(queue: DispatchQueue.main)
    61. }
    62. }
    Alles anzeigen
    1. Was bedeutet dieses <<< in <<< KVItem(speisen[0].name, "\(speisen[0].preis)")
    2. Was bedeutet dieses <<~ in <<~ .page(.printAndFeed(lines: 10))
    3. Wie kann ich durch ein Array einzelner Speisen iterieren und dabei mehrere <<< KVItem()") gernerieren wie z.B. hier?

    Quellcode

    1. <<< "Speisen"
    2. <<< Dividing.default()
    3. <<~ .style(.underlineMode(.enable2dot))
    4. for s in speisen {
    5. <<< KVItem(s.name, "\(s.preis)")
    6. summe += s.preis
    7. }
    8. <<< KVItem("", "\(summe)")
    9. <<~ .style(.initialize)
    10. <<~ .page(.printAndFeed(lines: 1))
    Xcode mag es zumindest schon mal überhaupt nicht:
    Bildschirmfoto 2024-01-22 um 18.03.44.png


    Ich wette ja ihr wisst das alles und hoffe ihr könnt mich erhellen :saint:

    Vielen Dank im voraus.

    Dirk
  • Qvex23 schrieb:

    hast du auch eine Idee wie ich die Daten aus dem Array nun in den Bon bekomme?
    Ehrlich gesagt, nein - und mir erschliesst sich auch das ganze Prozedere mit eigenen Operatoren und dem Struct KVItem nicht wirklich. Lesbar finde ich es nicht und würde mir an Deiner Stelle überlegen, ob ich wirklich einen Code einbinden möchte, der aus fremder Feder stammt und nicht 100% verstanden ist. Vielleicht macht es mehr Sinn, die essentielle Vorgehensweise aus dem Repository zu lernen und dann in eigenem Code abzubilden?

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.
  • Ja, ich verstehe schon...... jetzt kommt halt das berühmte ABER:

    Dieser Code ermöglicht es mit eine Art Tabelle zu erzeugen, wie man das von Kassenbons kennt:
    Ich habe schon mal mit diesen Druckern zu tun gehabt und mir damals was selbst gebastelt, aber eine Tabelle konnte das nie:


    Quellcode

    1. let ESC = "\u{1b}"
    2. let GS = "\u{1d}"
    3. let char0 = Character(UnicodeScalar(0))
    4. let char1 = Character(UnicodeScalar(1))
    5. let char2 = Character(UnicodeScalar(2))
    6. let char19 = Character(UnicodeScalar(19))
    7. let char48 = Character(UnicodeScalar(48))
    8. bon = "\(ESC)@\(ESC)t\(char19)\(ESC)R\(char2)\(GS)!\(char1)\(ESC)a\(char1)\(ESC)E\(char1)\(ESC)d\(char1)\(ESC)d\(char1)\(date)\(ESC)d\(char1)\nFoo Blah\n\(ESC)E\(char0)\(ESC)d\(char1)Menü: \(someVar)\(ESC)d\(char1)Dessert: \(boolEncoder(value: somebool))\(ESC)d\(char1)\(ESC)E\(char1)\(someOtherVar)\(ESC)d\(char1)\(someotherOtherVar)\(ESC)E\(char0)\(ESC)d\(char1)\n\(name)\n\n\n\n\n\n\n\n\(ESC)d\(char1)\(GS)V\(char48)"

    Leider kann ich auch anhand des Codes nicht herausfinden wie dieses KVItem zusammengebaut wird, so das ich mir den Code dort klauen könnte und die Drucker Dokumentation verstehe ich auch nicht. Ist irgendwie zu nah an der Hardware mit diesen Chars und ESC Codes.....

    Grüße

    Dirk
  • MyMattes schrieb:

    Qvex23 schrieb:

    hast du auch eine Idee wie ich die Daten aus dem Array nun in den Bon bekomme?
    Ehrlich gesagt, nein - und mir erschliesst sich auch das ganze Prozedere mit eigenen Operatoren und dem Struct KVItem nicht wirklich. Lesbar finde ich es nicht und würde mir an Deiner Stelle überlegen, ob ich wirklich einen Code einbinden möchte, der aus fremder Feder stammt und nicht 100% verstanden ist. Vielleicht macht es mehr Sinn, die essentielle Vorgehensweise aus dem Repository zu lernen und dann in eigenem Code abzubilden?
    Mattes
    Ich komme der Sache näher. Meine Lösung für den Code ist diese:

    Quellcode

    1. let speisenBon = Receipt(.init(maxWidthDensity: 500, fontDensity: 12, encoding: .utf8))
    2. <<~ .style(.initialize)
    3. <<~ .layout(.justification(.center))
    4. <<< Dividing.default()
    5. <<~ .page(.printAndFeed(lines: 1))
    6. <<< KVItem("Speisen", "")
    7. <<~ .style(.clear)
    8. <<~ .style(.initialize)
    9. <<~ .layout(.justification(.center))
    10. <<~ .page(.printAndFeed(lines: 1))
    11. <<< Dividing.default()
    12. <<~ .style(.underlineMode(.enable2dot))
    13. <<< KVItem("Artikel", "")
    14. <<~ .style(.emphasis(enable: true))
    15. <<< Dividing.default()
    16. <<~ .style(.underlineMode(.enable2dot))
    17. for s in speisen {
    18. speisenBon <<< KVItem(s.name, "")
    19. bemerkung = s.bemerkung
    20. }
    21. speisenBon <<~ .page(.printAndFeed(lines: 2))
    22. <<~ .style(.initialize)
    23. <<< Dividing.default()
    24. <<~ .style(.underlineMode(.enable2dot))
    25. <<~ .page(.printAndFeed(lines: 1))
    26. <<< KVItem("", bemerkung)
    27. <<~ .style(.initialize)
    28. <<~ .page(.printAndFeed(lines: 1))
    29. <<~ .layout(.justification(.center))
    30. <<< Dividing.default()
    31. <<~ .style(.underlineMode(.enable2dot))
    32. <<~ .page(.printAndFeed(lines: 1))
    33. <<< "\(date)"
    34. <<~ .style(.initialize)
    35. <<~ .page(.printAndFeed(lines: 1))
    36. <<~ .layout(.justification(.center))
    37. <<< Dividing.default()
    38. <<~ .style(.underlineMode(.enable2dot))
    39. <<~ .style(.clear)
    40. <<~ .page(.printAndFeed(lines: 10))
    41. <<~ .page(.partialCut)
    Alles anzeigen
    so klappts auch in der Schleife. Jetzt müsste ich nur noch dahinter kommen, wie man den Bon richtig gestaltet. Wann gilt für was diesed <<~.style(.underlineMode(.enable2dor)) oder <<~ .layout(.justification(.center)) und wo oder wie hört das auf zu gelten.

    Grüße

    Dirk
  • Ok. nun habe ich es:


    Quellcode

    1. let receipt = Receipt(.init(maxWidthDensity: 500, fontDensity: 12, encoding: .windowsCP1252))
    2. <<~ .style(.clear)
    3. <<~ .style(.initialize)
    4. <<~ .layout(.justification(.center))
    5. <<< umlautConverter(text: globalAddress)
    6. <<~ .page(.printAndFeed(lines: 1))
    7. <<< Dividing.default()
    8. <<~ .page(.printAndFeed(lines: 1))
    9. <<< "\(date)"
    10. <<~ .page(.printAndFeed(lines: 1))
    11. <<< Dividing.default()
    12. for g in getraenke {
    13. receipt <<< KVItem(umlautConverter(text: g.name), String(format: "%.2f", g.preis) + " Eur")
    14. summe = summe + g.preis
    15. }
    16. for s in speisen {
    17. receipt <<< KVItem(umlautConverter(text: s.name), String(format: "%.2f", s.preis) + " Eur")
    18. summe = summe + s.preis
    19. }
    20. receipt <<< Dividing.default()
    21. <<~ .page(.printAndFeed(lines: 1))
    22. <<< KVItem("Gesamt", String(format: "%.2f", summe) + " Eur")
    23. <<~ .page(.printAndFeed(lines: 1))
    24. <<< Dividing.default()
    25. <<~ .page(.printAndFeed(lines: 5))
    26. <<~ .style(.clear)
    27. <<~ .page(.partialCut)
    Alles anzeigen
    Aber leider kommen die Umlaute oder "ß" noch falsch raus, egal welches encoding ich einstelle.
    Wenn hier noch jemand einen Rat weis, gerne her damit.

    Grüße

    Dirk
  • Qvex23 schrieb:



    Dieser Code ermöglicht es mit eine Art Tabelle zu erzeugen, wie man das von Kassenbons kennt:
    Ich bin bei dem Thema gänzlich neu, aber hier mal die Frage - du willst einfach nur eine Tabelle mit den Werten erzeugen, oder? Also bspw. Name, Preis, Menge, Summe...
    Geht das nicht leichter?

    Also rein visuell kommt mir da eine Table in den Sinn (developer.apple.com/documentation/swiftui/table).
    Und die musst du dann auf deinen Bon schreiben und ausdrucken. Wie gesagt, ich bin völlig fernab von dem Thema, aber ist das so ein dealbreaker, dass Ding dann auf deinen Bon zu bekommen, dass du SwiftUis Table nciht verwenden kannst?
  • ashtari schrieb:

    Qvex23 schrieb:

    Dieser Code ermöglicht es mit eine Art Tabelle zu erzeugen, wie man das von Kassenbons kennt:
    Ich bin bei dem Thema gänzlich neu, aber hier mal die Frage - du willst einfach nur eine Tabelle mit den Werten erzeugen, oder? Also bspw. Name, Preis, Menge, Summe... Geht das nicht leichter?

    Also rein visuell kommt mir da eine Table in den Sinn (developer.apple.com/documentation/swiftui/table).
    Und die musst du dann auf deinen Bon schreiben und ausdrucken. Wie gesagt, ich bin völlig fernab von dem Thema, aber ist das so ein dealbreaker, dass Ding dann auf deinen Bon zu bekommen, dass du SwiftUis Table nciht verwenden
    wenn es so einfach gewesen wäre hätte ich es gemacht, aber die Drucker haben ihre eigenen Steuercodes für fett, kursiv, Zeilenvorschub, Papierschneiden uvm.
  • Qvex23 schrieb:

    Aber leider kommen die Umlaute oder "ß" noch falsch raus, egal welches encoding ich einstelle.
    Mal in's Blaue geschossen: Müsstest Du nicht auf dem Drucker die entsprechende Codepage einstellen? Ich könnte mir vorstellen, dass der normal nur 7-Bit ASCII nimmt und z. B. mit der Codepage 437 den erweiterten Zeichensatz verwenden würde. Wenn Du dann Strings entsprechend encoded sendet, sollte das klappen.

    Zumindest lässt das Enum im o. g. Code die Unterstützung verschiedener Codepages vermuten und hier war auch ein entsprechender Issue auf GitHub - wenngleich mit einem Windows-Zeichensatz. Hier ist vermutlich etwas Try & Error nötig.

    Die Codepage erinnert mich noch an alte config.sys-Konfigurationen :)

    Mattes

    Edit: Hier findet sich auf SO auch ein Hinweis auf entsprechendes Encoding...
    Diese Seite bleibt aus technischen Gründen unbedruckt.

    Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von MyMattes ()

  • MyMattes schrieb:

    Qvex23 schrieb:

    Aber leider kommen die Umlaute oder "ß" noch falsch raus, egal welches encoding ich einstelle.
    Mal in's Blaue geschossen: Müsstest Du nicht auf dem Drucker die entsprechende Codepage einstellen? Ich könnte mir vorstellen, dass der normal nur 7-Bit ASCII nimmt und z. B. mit der Codepage 437 den erweiterten Zeichensatz verwenden würde. Wenn Du dann Strings entsprechend encoded sendet, sollte das klappen.
    Zumindest lässt das Enum im o. g. Code die Unterstützung verschiedener Codepages vermuten und hier war auch ein entsprechender Issue auf GitHub - wenngleich mit einem Windows-Zeichensatz. Hier ist vermutlich etwas Try & Error nötig.

    Die Codepage erinnert mich noch an alte config.sys-Konfigurationen :)

    Mattes

    Edit: Hier findet sich auf SO auch ein Hinweis auf entsprechendes Encoding...
    Das selbe habe ich auch gedacht und sämtliche Varianten durchprobiert, keine bringt Umlaute korrekt raus.
  • MyMattes schrieb:

    Qvex23 schrieb:

    Aber leider kommen die Umlaute oder "ß" noch falsch raus, egal welches encoding ich einstelle.
    Mal in's Blaue geschossen: Müsstest Du nicht auf dem Drucker die entsprechende Codepage einstellen? Ich könnte mir vorstellen, dass der normal nur 7-Bit ASCII nimmt und z. B. mit der Codepage 437 den erweiterten Zeichensatz verwenden würde. Wenn Du dann Strings entsprechend encoded sendet, sollte das klappen.
    Zumindest lässt das Enum im o. g. Code die Unterstützung verschiedener Codepages vermuten und hier war auch ein entsprechender Issue auf GitHub - wenngleich mit einem Windows-Zeichensatz. Hier ist vermutlich etwas Try & Error nötig.

    Die Codepage erinnert mich noch an alte config.sys-Konfigurationen :)

    Mattes

    Edit: Hier findet sich auf SO auch ein Hinweis auf entsprechendes Encoding...
    Ich habe das so versucht:

    Quellcode

    1. let receipt = Receipt(.init(maxWidthDensity: 500, fontDensity: 12, encoding: .windowsCP1252))

    und auch mit anderen encodings, aber nichts half.

    Nun gibt es ja noch den Teil im Code der das dann per Network Soket sendet:

    Quellcode

    1. connection.stateUpdateHandler = { newState in
    2. switch newState {
    3. case .ready:
    4. print("[MyDebug] Socket State: Ready")
    5. print("[MyDebug] send data")
    6. let content: Data = Data(receipt.data)
    7. connection.send(content: content, contentContext: .defaultMessage, completion: NWConnection.SendCompletion.contentProcessed(({ NWError in
    8. if (NWError == nil) {
    9. print("[MyDebug] Data was sent to TCP destination ")
    10. connection.cancel()
    11. } else {
    12. print("[MyDebug] ERROR! Error when data (Type: Data) sending. NWError: \n \(NWError!)")
    13. }
    14. })))
    15. case .failed(let error):
    16. print("[MyDebug] Fatal connection error", error.localizedDescription)
    17. default:
    18. break
    19. }
    20. }
    21. connection.start(queue: DispatchQueue.main)
    Alles anzeigen
    Kann/Muss ich an dieser Stelle let content: Data = Data(receipt.data) nochmal ein encoding angeben? Und wenn ja.... Tipps wie und welches?

    Danke.

    Gruß

    Dirk
  • Qvex23 schrieb:

    Kann/Muss ich an dieser Stelle let content: Data = Data(receipt.data) nochmal ein encoding angeben? Und wenn ja.... Tipps wie und welches?
    Jetzt mal zwei Schritte zurück, so wird das nix!
    • Grundsätzlich ist die Angabe eines Encodings für Bytes > 127 notwendig, weil ein einheitlicher Standard nur für die mit 7 Bit codierten Zeichen vorliegt. Andere Zeichen wie zum Beispiel Umlaute können - je nach Encoding - durch unterschiedliche Werte repräsentiert werden.
    • Dieses Encoding / diese Codepage muss zwischen Sender und Empfänger übereinstimmen, sonst gibt’s Quark:
      • Wenn aus einem Zeichen die entsprechende Bitfolge generiert wird - das passiert bei Dir im „Receipt“.
      • Auf dem Drucker, wenn dieser mit der Bitfolge ein Zeichen seines Zeichensatzes identifiziert.
      • Der Transportschicht ist es vollkommen egal, was der übertragene Bitstream repräsentiert.
    Also musst Du neben dem Encoding beim Erstellen des Bons den Drucker auf die gleiche Codepage umstellen. Üblicherweise geschieht dies durch ESC-Sequenzen (z. B. durch Hersteller-Tools oder zu Beginn des Druckauftrags) oder durch hardware-seitige Konfiguration.

    Ich sehe drei Optionen:
    1. Du findest im Code auf GitHub heraus, wie man den Drucker auf eine Codepage umstellen kann - evt. auch durch Fragen an die Contributors
    2. Du nutzt ein externes Tool, um die Konfiguration vorzunehmen - so hatte ich die von mir zitierte Diskussion aus dem GitHub-Repository verstanden
    3. Du kontaktierst den Druckerhersteller und fragst, wie man (idealerweise softwareseitig) die Konfiguration vornehmen kann. Eigentlich sollte diese Info in der Dokumentation zu finden sein, Stichwort Escape-Sequenzen
    Von meiner Seite aus gibt es nichts mehr, was ich beitragen könnte, sorry…

    Mattes
    Diese Seite bleibt aus technischen Gründen unbedruckt.