5

Arduino (Uno rev 3) とサーマル プリンター (このモデルhttps://www.sparkfun.com/products/10438 )をいじって楽しんでいます。Arduino は 10 秒ごとにローカル マシンに (イーサネット シールドを介して) 要求を送信し、応答 (200 の場合) を SD カードに保存します。次に、このライブラリhttps://github.com/adafruit/Adafruit-Thermal-Printer-Libraryを使用してこれを出力します。

これまでのところ、基本的なテキストのポーリング、保存、印刷を正しく行っていますが、より高度なコマンド (下線、反転など) を使用しようとしています。私の最終的な目標は、画像を送信し、サーバー ala http://printer.gofreerange.com/ですべてのレンダリングを処理することです。

問題は、送信しているコマンドがテキスト文字として出力されていることです。一部のコマンドは機能しますが (改行)、文字化けするものもあります。Arduino コードとそれが呼び出している基本的な PHP スクリプトの両方を添付しました。何か助けはありますか?

アルドゥイーノ:

#include <SPI.h>
#include <Ethernet.h>
#include <SD.h>
#include <SoftwareSerial.h>
#include "Adafruit_Thermal.h"

byte mac[] = { 0xDE, 0xAD, 0xBE, 0xEF, 0xFE, 0xED };
const char host[] = "192.168.1.100";
char cacheFilename[] = "TMP";

const byte printer_RX_Pin = 8; // this is the green wire
const byte printer_TX_Pin = 9; // this is the yellow wire
const byte SD_Pin = 4;         // the SD Card SPI pin

bool downloadWaiting = false;
bool statusOk = false;
unsigned long content_length = 0;

EthernetClient client;
Adafruit_Thermal printer(printer_RX_Pin, printer_TX_Pin);


void die(unsigned int times) {
  while(true);
}


void checkForDownload() {

  Serial.println("checkForDownload");

  content_length = 0;
  statusOk = false;
  unsigned long length = 0;

  if (SD.exists(cacheFilename)) {
    if (!SD.remove(cacheFilename)) {
      die(4);
    }
  }
  File cache = SD.open(cacheFilename, FILE_WRITE);

  if(client.connect(host, 80)) {

    client.println("GET /printer.php HTTP/1.1");
    client.print("Host: "); client.println(host);
    client.println("User-Agent: arduino-ethernet");
    client.println("Connection: close");
    client.println();

    bool parsingHeader = true;

    while(client.connected()) {
      while(client.available()) {

        if (parsingHeader) {

          client.find((char*)"HTTP/1.1 ");
          char statusCode[] = "000";
          client.readBytes(statusCode, 3);
          statusOk = (strcmp(statusCode, "200") == 0);

          client.find((char*)"Content-Length: ");
          char c;
          while (isdigit(c = client.read())) {
            content_length = (content_length * 10) + (c - '0');
          }

          client.find((char*)"\n\r\n");
          parsingHeader = false;

        } else {
          if(length < content_length) {
            cache.write((byte)client.read());
            length++;
          } else {
              client.read();
          }
        }

      }
    }

    client.stop();
    cache.seek(0);

    if (statusOk && content_length > 0 && (content_length == length) && (content_length == cache.size())) {
      downloadWaiting = true;
    }

  } else {
    client.stop();
  }

  cache.close();

}


void printFromDownload() {

  Serial.println("printFromDownload");

  File cache = SD.open(cacheFilename);
  byte b;

  while (content_length--) {
    printer.write((byte)cache.read());
  }

  printer.feed();

  cache.close();
  downloadWaiting = false;

}


void setup(){

  pinMode(SD_Pin, OUTPUT);
  if (!SD.begin(SD_Pin)) {
    die(2);
  }

  if (Ethernet.begin(mac) == 0) {
    die(3);
  }

  Serial.begin(9600);
  printer.begin(255);

  delay(1000);

}


void loop() {
  if (downloadWaiting) {
    printFromDownload();
    delay(5000);
  } else {
    checkForDownload();
    if (!downloadWaiting) {
      delay(10000);
    }
  }
}

PHP:

<?php

ob_start();


// Turn on Inverse mode
// Doesn't work
echo pack('S', 29);
echo pack('S', 66);
echo pack('S', 1);

$string = 'Testing 1, 2, 3';

foreach(str_split($string) as $char) {
  echo pack('S', ord($char)); // works
}

// Turn off Inverse mode
echo pack('S', 29);
echo pack('S', 66);
echo pack('S', 0);

// Line feed
echo pack('S', 10); // works

$content = ob_get_clean();
$length = strlen($content);
header("Content-Length: $length");

echo $content;
4

1 に答える 1

0

ビットマップデータを直接printer.write()で印刷できないようです。プリンターは、printBitmap() メソッドでわかるように、ビットマップ印刷モードをオンにする特殊なバイトを想定しています。(writeBytes(18、42、chunkHeight、rowBytesClipped))

void Adafruit_Thermal::printBitmap(
 int w, int h, const uint8_t *bitmap, bool fromProgMem) {
  int rowBytes, rowBytesClipped, rowStart, chunkHeight, x, y, i;

  rowBytes        = (w + 7) / 8; // Round up to next byte boundary
  rowBytesClipped = (rowBytes >= 48) ? 48 : rowBytes; // 384 pixels max width

  for(i=rowStart=0; rowStart < h; rowStart += 255) {
    // Issue up to 255 rows at a time:
    chunkHeight = h - rowStart;
    if(chunkHeight > 255) chunkHeight = 255;

    writeBytes(18, 42, chunkHeight, rowBytesClipped);

    for(y=0; y < chunkHeight; y++) {
      for(x=0; x < rowBytesClipped; x++, i++) {
        PRINTER_PRINT(fromProgMem ? pgm_read_byte(bitmap + i) : *(bitmap+i));
      }
      i += rowBytes - rowBytesClipped;
    }
    timeoutSet(chunkHeight * dotPrintTime);
  }
  prevByte = '\n';
}

スケッチは、PHP からのデータを理解し、printer.write() で個々の文字をバイトとして送信するタイミングと、printer.printBitmap() でバイトを画像として送信するタイミングを知る必要があります。このようにして、プリンターは適切なデータを印刷する準備をするための適切なコマンドを受け取ります。PHP で出力したいものに関するメタデータを作成し、それを Arduino に送信する必要があります。JSON 形式は次のようになります。

{"reciept": [
  {
    "type": "text",
    "style": "bold",
    "value": "Thank you for your purchase"
  },
  {
    "type": "bitmap",
    "pos": "center",
    "value": ".... binary data ..."
  }
]}

これで、Arduino スケッチは、バイトをテキストとして個別に送信するタイミングと、大量のデータをビットマップとして送信するタイミングを理解します。

よりコンパクトな形式では、改行をセグメント間の区切りとして使用する場合があります。

F|bold
T|Thank you for shopping with us\r
P|Center
B|...binary data (with \r escaped)... \r

または、各セグメントでデータ量を送信して、HTTP の Content-Length ヘッダーのようにバイナリ データをエスケープしないようにすることもできます。

F4|boldT32|Thank you for shopping with us\rP6|CenterB3000|...binary data...
于 2013-01-12T23:32:52.343 に答える