libptouch を複数ソースに分割し src/lib に配置
- core / usb / print / status / png と libptouch_internal.h に分割 - 旧単一ファイル src/libptouch.c を削除 - CMake のソース一覧と include パスを更新 - README・libptouch.h の参照パスを追随 Made-with: Cursor
This commit is contained in:
@@ -21,8 +21,16 @@ configure_file(
|
|||||||
@ONLY
|
@ONLY
|
||||||
)
|
)
|
||||||
|
|
||||||
add_library(ptouch STATIC src/libptouch.c)
|
set(LIBPTOUCH_SOURCES
|
||||||
add_library(ptouch_shared SHARED src/libptouch.c)
|
src/lib/libptouch_core.c
|
||||||
|
src/lib/libptouch_usb.c
|
||||||
|
src/lib/libptouch_print.c
|
||||||
|
src/lib/libptouch_status.c
|
||||||
|
src/lib/libptouch_png.c
|
||||||
|
)
|
||||||
|
|
||||||
|
add_library(ptouch STATIC ${LIBPTOUCH_SOURCES})
|
||||||
|
add_library(ptouch_shared SHARED ${LIBPTOUCH_SOURCES})
|
||||||
set_target_properties(ptouch_shared PROPERTIES OUTPUT_NAME ptouch
|
set_target_properties(ptouch_shared PROPERTIES OUTPUT_NAME ptouch
|
||||||
SOVERSION ${PROJECT_VERSION_MAJOR})
|
SOVERSION ${PROJECT_VERSION_MAJOR})
|
||||||
target_include_directories(ptouch PUBLIC
|
target_include_directories(ptouch PUBLIC
|
||||||
@@ -30,11 +38,17 @@ target_include_directories(ptouch PUBLIC
|
|||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
||||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||||
)
|
)
|
||||||
|
target_include_directories(ptouch PRIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib"
|
||||||
|
)
|
||||||
target_include_directories(ptouch_shared PUBLIC
|
target_include_directories(ptouch_shared PUBLIC
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}/include>"
|
||||||
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
"$<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/include>"
|
||||||
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
"$<INSTALL_INTERFACE:${CMAKE_INSTALL_INCLUDEDIR}>"
|
||||||
)
|
)
|
||||||
|
target_include_directories(ptouch_shared PRIVATE
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/src/lib"
|
||||||
|
)
|
||||||
target_link_libraries(ptouch PRIVATE PkgConfig::LIBUSB PNG::PNG)
|
target_link_libraries(ptouch PRIVATE PkgConfig::LIBUSB PNG::PNG)
|
||||||
target_link_libraries(ptouch_shared PRIVATE PkgConfig::LIBUSB PNG::PNG)
|
target_link_libraries(ptouch_shared PRIVATE PkgConfig::LIBUSB PNG::PNG)
|
||||||
if(NOT MSVC)
|
if(NOT MSVC)
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ Brother P-touch シリーズ向けのラベル印刷用 **C コアライブラ
|
|||||||
| パス | 内容 |
|
| パス | 内容 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `include/libptouch.h` | 公開 API |
|
| `include/libptouch.h` | 公開 API |
|
||||||
| `src/libptouch.c` | ライブラリ本体(スタブ) |
|
| `src/lib/libptouch_*.c` | ライブラリ本体(core / usb / print / status / png) |
|
||||||
| `src/cli/main.c` | `ptouch-print` エントリ |
|
| `src/cli/main.c` | `ptouch-print` エントリ |
|
||||||
| `samples/` | 試験用サンプル画像の置き場(PNG 等) |
|
| `samples/` | 試験用サンプル画像の置き場(PNG 等) |
|
||||||
| `ruby/` | Ruby FFI gem(`libptouch`)・コマンド `ptouch-print-png`(PNG のみ)— `ruby/README.md` |
|
| `ruby/` | Ruby FFI gem(`libptouch`)・コマンド `ptouch-print-png`(PNG のみ)— `ruby/README.md` |
|
||||||
@@ -80,7 +80,7 @@ cmake --build build
|
|||||||
## PT-P900W / Linux でのメモ
|
## PT-P900W / Linux でのメモ
|
||||||
|
|
||||||
- 接続は **libusb-1.0** のみ。機種ごとに **VID/PID**(`lsusb` 等)を調べ、`libptouch_open_usb_vid_pid` に渡すか、既定の PT-P900W なら `libptouch_open_usb` を使います。
|
- 接続は **libusb-1.0** のみ。機種ごとに **VID/PID**(`lsusb` 等)を調べ、`libptouch_open_usb_vid_pid` に渡すか、既定の PT-P900W なら `libptouch_open_usb` を使います。
|
||||||
- ラスターコマンドの詳細は **`reference/` の PDF** および Brother 公開資料に沿って `src/libptouch.c` に実装してください。
|
- ラスターコマンドの詳細は **`reference/` の PDF** および Brother 公開資料に沿って `src/lib/libptouch_*.c` に実装してください。
|
||||||
|
|
||||||
### Ubuntu で sudo なしで USB を開く(udev)
|
### Ubuntu で sudo なしで USB を開く(udev)
|
||||||
|
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
/**
|
/**
|
||||||
* libptouch — Brother P-touch ラスター印刷 (USB) 用 C API
|
* libptouch — Brother P-touch ラスター印刷 (USB) 用 C API
|
||||||
*
|
*
|
||||||
* 対象例: PT-P900W(ラスターコマンド)。実装は src/libptouch.c を参照。
|
* 対象例: PT-P900W(ラスターコマンド)。実装は src/lib/libptouch_*.c を参照。
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef LIBPTOUCH_H
|
#ifndef LIBPTOUCH_H
|
||||||
|
|||||||
100
src/lib/libptouch_core.c
Normal file
100
src/lib/libptouch_core.c
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — context, errors, raster validation
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libptouch_internal.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
void ptouch_set_error(libptouch_ctx *ctx, libptouch_err_t code, const char *msg)
|
||||||
|
{
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
ctx->last_code = code;
|
||||||
|
if (msg) {
|
||||||
|
snprintf(ctx->last_msg, sizeof(ctx->last_msg), "%s", msg);
|
||||||
|
} else {
|
||||||
|
ctx->last_msg[0] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ptouch_set_error_usb(libptouch_ctx *ctx, int libusb_err, const char *what)
|
||||||
|
{
|
||||||
|
char buf[256];
|
||||||
|
snprintf(buf, sizeof(buf), "%s: %s", what,
|
||||||
|
libusb_strerror((enum libusb_error)libusb_err));
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_USB, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_ctx *libptouch_create(void)
|
||||||
|
{
|
||||||
|
libptouch_ctx *ctx = calloc(1, sizeof(*ctx));
|
||||||
|
if (!ctx)
|
||||||
|
return NULL;
|
||||||
|
ctx->last_code = LIBPTOUCH_OK;
|
||||||
|
ctx->last_msg[0] = '\0';
|
||||||
|
ctx->usb_open = 0;
|
||||||
|
ctx->usb_ctx = NULL;
|
||||||
|
ctx->usb_handle = NULL;
|
||||||
|
ctx->claimed_interface = -1;
|
||||||
|
ctx->bulk_out_ep = 0;
|
||||||
|
ctx->bulk_in_ep = 0;
|
||||||
|
return ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
void libptouch_destroy(libptouch_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
libptouch_close(ctx);
|
||||||
|
free(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
|
const char *libptouch_strerror(const libptouch_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx)
|
||||||
|
return "(null ctx)";
|
||||||
|
return ctx->last_msg[0] ? ctx->last_msg : "ok";
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_last_error(const libptouch_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx)
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
return ctx->last_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_check_raster(libptouch_ctx *ctx,
|
||||||
|
const uint8_t *data, size_t data_len,
|
||||||
|
const libptouch_raster_params_t *params)
|
||||||
|
{
|
||||||
|
if (!ctx || !params) {
|
||||||
|
if (ctx)
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "null argument");
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
if (!data && data_len > 0) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "data is null but len > 0");
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t row = (params->width_dots + 7u) / 8u;
|
||||||
|
size_t expected = (size_t)params->height_dots * row;
|
||||||
|
if (data_len != expected) {
|
||||||
|
char buf[160];
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"data_len mismatch: got %zu, expected %zu (w=%u h=%u)",
|
||||||
|
data_len, expected, params->width_dots,
|
||||||
|
params->height_dots);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, buf);
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
37
src/lib/libptouch_internal.h
Normal file
37
src/lib/libptouch_internal.h
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — internal declarations (not installed)
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef LIBPTOUCH_INTERNAL_H
|
||||||
|
#define LIBPTOUCH_INTERNAL_H
|
||||||
|
|
||||||
|
#include "libptouch.h"
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
|
||||||
|
struct libptouch_ctx {
|
||||||
|
libptouch_err_t last_code;
|
||||||
|
char last_msg[256];
|
||||||
|
int usb_open;
|
||||||
|
struct libusb_context *usb_ctx;
|
||||||
|
struct libusb_device_handle *usb_handle;
|
||||||
|
int claimed_interface; /* -1 if none */
|
||||||
|
uint8_t bulk_out_ep;
|
||||||
|
uint8_t bulk_in_ep;
|
||||||
|
};
|
||||||
|
|
||||||
|
void ptouch_set_error(libptouch_ctx *ctx, libptouch_err_t code, const char *msg);
|
||||||
|
void ptouch_set_error_usb(libptouch_ctx *ctx, int libusb_err, const char *what);
|
||||||
|
|
||||||
|
int ptouch_bulk_out(libusb_device_handle *h, uint8_t ep, const uint8_t *data,
|
||||||
|
int len, unsigned int timeout_ms);
|
||||||
|
int ptouch_bulk_in_exact(libusb_device_handle *h, uint8_t ep, uint8_t *buf,
|
||||||
|
int len, unsigned int timeout_ms);
|
||||||
|
libptouch_err_t ptouch_bulk_send_job(libptouch_ctx *ctx, const uint8_t *buf,
|
||||||
|
size_t len, const char *what);
|
||||||
|
|
||||||
|
#endif /* LIBPTOUCH_INTERNAL_H */
|
||||||
164
src/lib/libptouch_png.c
Normal file
164
src/lib/libptouch_png.c
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — PNG → 1bit packed raster (libpng)
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libptouch_internal.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include <png.h>
|
||||||
|
|
||||||
|
void libptouch_free_raster(uint8_t *raster)
|
||||||
|
{
|
||||||
|
free(raster);
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_png_file_to_raster(libptouch_ctx *ctx, const char *path,
|
||||||
|
const libptouch_png_options_t *options,
|
||||||
|
uint8_t **out_raster, size_t *out_raster_bytes,
|
||||||
|
libptouch_raster_params_t *out_params)
|
||||||
|
{
|
||||||
|
if (!ctx || !path || !out_raster || !out_raster_bytes || !out_params) {
|
||||||
|
if (ctx)
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "null argument");
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t thr = LIBPTOUCH_PNG_DEFAULT_THRESHOLD;
|
||||||
|
if (options)
|
||||||
|
thr = options->threshold;
|
||||||
|
|
||||||
|
*out_raster = NULL;
|
||||||
|
*out_raster_bytes = 0;
|
||||||
|
out_params->width_dots = 0;
|
||||||
|
out_params->height_dots = 0;
|
||||||
|
out_params->margin_mm = 0;
|
||||||
|
|
||||||
|
FILE *fp = fopen(path, "rb");
|
||||||
|
if (!fp) {
|
||||||
|
char buf[192];
|
||||||
|
snprintf(buf, sizeof(buf), "open %s: %s", path, strerror(errno));
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IO, buf);
|
||||||
|
return LIBPTOUCH_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned char sig[8];
|
||||||
|
if (fread(sig, 1, 8, fp) != 8) {
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "short read (not a PNG?)");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
if (png_sig_cmp(sig, 0, 8) != 0) {
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "not a PNG file");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_structp png_ptr =
|
||||||
|
png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
|
||||||
|
if (!png_ptr) {
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOMEM, "png_create_read_struct failed");
|
||||||
|
return LIBPTOUCH_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
||||||
|
if (!info_ptr) {
|
||||||
|
png_destroy_read_struct(&png_ptr, NULL, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOMEM, "png_create_info_struct failed");
|
||||||
|
return LIBPTOUCH_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (setjmp(png_jmpbuf(png_ptr))) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "PNG decode error");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
png_init_io(png_ptr, fp);
|
||||||
|
png_set_sig_bytes(png_ptr, 8);
|
||||||
|
|
||||||
|
const int transforms = (int)(PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16 |
|
||||||
|
PNG_TRANSFORM_GRAY_TO_RGB);
|
||||||
|
png_read_png(png_ptr, info_ptr, transforms, NULL);
|
||||||
|
|
||||||
|
png_uint_32 width = png_get_image_width(png_ptr, info_ptr);
|
||||||
|
png_uint_32 height = png_get_image_height(png_ptr, info_ptr);
|
||||||
|
int channels = (int)png_get_channels(png_ptr, info_ptr);
|
||||||
|
png_bytepp rows = png_get_rows(png_ptr, info_ptr);
|
||||||
|
|
||||||
|
if (width == 0 || height == 0 || !rows) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "invalid PNG dimensions");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
if (width > 100000u || height > 100000u) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "PNG dimensions too large");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
if (channels != 3 && channels != 4) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "unsupported PNG channel count");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t row_bytes = ((size_t)width + 7u) / 8u;
|
||||||
|
if (height > SIZE_MAX / row_bytes) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IMAGE, "raster size overflow");
|
||||||
|
return LIBPTOUCH_ERR_IMAGE;
|
||||||
|
}
|
||||||
|
size_t total = row_bytes * (size_t)height;
|
||||||
|
uint8_t *out = (uint8_t *)calloc(1, total);
|
||||||
|
if (!out) {
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOMEM, "calloc raster failed");
|
||||||
|
return LIBPTOUCH_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (png_uint_32 y = 0; y < height; y++) {
|
||||||
|
const png_byte *row = rows[y];
|
||||||
|
uint8_t *dst_row = out + (size_t)y * row_bytes;
|
||||||
|
for (png_uint_32 x = 0; x < width; x++) {
|
||||||
|
size_t o = (size_t)x * (size_t)channels;
|
||||||
|
unsigned r = row[o + 0];
|
||||||
|
unsigned g = row[o + 1];
|
||||||
|
unsigned b = row[o + 2];
|
||||||
|
unsigned a = channels == 4 ? row[o + 3] : 255u;
|
||||||
|
if (a < 128u) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
unsigned yv = (77u * r + 150u * g + 29u * b) >> 8;
|
||||||
|
int black = (yv < (unsigned)thr) ? 1 : 0;
|
||||||
|
if (!black)
|
||||||
|
continue;
|
||||||
|
size_t bit = (size_t)x % 8u;
|
||||||
|
size_t byte = (size_t)x / 8u;
|
||||||
|
dst_row[byte] |= (uint8_t)(1u << (7u - bit));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
|
||||||
|
fclose(fp);
|
||||||
|
|
||||||
|
out_params->width_dots = (uint32_t)width;
|
||||||
|
out_params->height_dots = (uint32_t)height;
|
||||||
|
out_params->margin_mm = 0;
|
||||||
|
*out_raster = out;
|
||||||
|
*out_raster_bytes = total;
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
296
src/lib/libptouch_print.c
Normal file
296
src/lib/libptouch_print.c
Normal file
@@ -0,0 +1,296 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — raster layout, transpose, P-touch print job (ESC/P bulk)
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libptouch_internal.h"
|
||||||
|
|
||||||
|
#include <libusb.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/* cv_ptp900_jpn_raster_102.pdf: テープ幅から印刷可能ドット */
|
||||||
|
static libptouch_err_t layout_from_status(uint8_t media_kind, uint8_t media_wbyte,
|
||||||
|
uint16_t *left, uint16_t *print_dots,
|
||||||
|
uint16_t *right)
|
||||||
|
{
|
||||||
|
if (media_kind == 0x11u || media_kind == 0x17u) {
|
||||||
|
switch (media_wbyte) {
|
||||||
|
case 0x06:
|
||||||
|
*left = 244;
|
||||||
|
*print_dots = 56;
|
||||||
|
*right = 260;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x09:
|
||||||
|
*left = 224;
|
||||||
|
*print_dots = 96;
|
||||||
|
*right = 240;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x0C:
|
||||||
|
*left = 206;
|
||||||
|
*print_dots = 132;
|
||||||
|
*right = 222;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x12:
|
||||||
|
*left = 166;
|
||||||
|
*print_dots = 212;
|
||||||
|
*right = 182;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x18:
|
||||||
|
*left = 144;
|
||||||
|
*print_dots = 256;
|
||||||
|
*right = 160;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
switch (media_wbyte) {
|
||||||
|
case 0x04:
|
||||||
|
*left = 248;
|
||||||
|
*print_dots = 48;
|
||||||
|
*right = 264;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x06:
|
||||||
|
*left = 240;
|
||||||
|
*print_dots = 64;
|
||||||
|
*right = 256;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x09:
|
||||||
|
*left = 219;
|
||||||
|
*print_dots = 106;
|
||||||
|
*right = 235;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x0C:
|
||||||
|
*left = 197;
|
||||||
|
*print_dots = 150;
|
||||||
|
*right = 213;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x12:
|
||||||
|
*left = 155;
|
||||||
|
*print_dots = 234;
|
||||||
|
*right = 171;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x18:
|
||||||
|
*left = 112;
|
||||||
|
*print_dots = 320;
|
||||||
|
*right = 128;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
case 0x24:
|
||||||
|
*left = 45;
|
||||||
|
*print_dots = 454;
|
||||||
|
*right = 61;
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
(void)media_kind;
|
||||||
|
return LIBPTOUCH_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* cv_ptp900_jpn_raster_102.pdf: 2.3.5 ラスターライン(全 560 ドット = 70 バイト) */
|
||||||
|
static void pack_line_560(uint8_t line[70], const uint8_t *row, uint32_t width_dots,
|
||||||
|
uint16_t left_dots, uint16_t print_dots)
|
||||||
|
{
|
||||||
|
memset(line, 0, 70u);
|
||||||
|
if (width_dots > (uint32_t)print_dots)
|
||||||
|
return;
|
||||||
|
uint32_t start = (uint32_t)left_dots +
|
||||||
|
((uint32_t)print_dots - width_dots) / 2u;
|
||||||
|
for (uint32_t x = 0; x < width_dots; x++) {
|
||||||
|
uint32_t ubyte = x / 8u;
|
||||||
|
uint32_t ubit = 7u - (x % 8u);
|
||||||
|
if (((row[ubyte] >> ubit) & 1u) == 0)
|
||||||
|
continue;
|
||||||
|
uint32_t dot = start + x;
|
||||||
|
if (dot >= 560u)
|
||||||
|
break;
|
||||||
|
uint32_t b = dot / 8u;
|
||||||
|
uint32_t bi = 7u - (dot % 8u);
|
||||||
|
line[b] |= (uint8_t)(1u << bi);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint8_t *transpose_raster_alloc(const uint8_t *in, uint32_t W, uint32_t H,
|
||||||
|
uint32_t *outW, uint32_t *outH)
|
||||||
|
{
|
||||||
|
*outW = H;
|
||||||
|
*outH = W;
|
||||||
|
size_t old_rb = (W + 7u) / 8u;
|
||||||
|
size_t new_rb = (H + 7u) / 8u;
|
||||||
|
uint8_t *out = (uint8_t *)calloc(new_rb * W, 1);
|
||||||
|
if (!out)
|
||||||
|
return NULL;
|
||||||
|
for (uint32_t y = 0; y < H; y++) {
|
||||||
|
for (uint32_t x = 0; x < W; x++) {
|
||||||
|
size_t ob = (size_t)y * old_rb + x / 8u;
|
||||||
|
int bit = (int)((in[ob] >> (7u - x % 8u)) & 1u);
|
||||||
|
if (!bit)
|
||||||
|
continue;
|
||||||
|
uint32_t nx = y;
|
||||||
|
uint32_t ny = x;
|
||||||
|
size_t nb = (size_t)ny * new_rb + nx / 8u;
|
||||||
|
out[nb] |= (uint8_t)(1u << (7u - nx % 8u));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_print_raster(libptouch_ctx *ctx,
|
||||||
|
const uint8_t *data, size_t data_len,
|
||||||
|
const libptouch_raster_params_t *params)
|
||||||
|
{
|
||||||
|
libptouch_err_t v =
|
||||||
|
libptouch_check_raster(ctx, data, data_len, params);
|
||||||
|
if (v != LIBPTOUCH_OK)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
if (!ctx->usb_open || !ctx->bulk_out_ep) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IO, "not connected");
|
||||||
|
return LIBPTOUCH_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t st[LIBPTOUCH_STATUS_LENGTH];
|
||||||
|
v = libptouch_get_status(ctx, st);
|
||||||
|
if (v != LIBPTOUCH_OK)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
uint8_t media_kind = st[11];
|
||||||
|
uint8_t media_w = st[10];
|
||||||
|
uint16_t left_dots, print_dots, right_dots;
|
||||||
|
v = layout_from_status(media_kind, media_w, &left_dots, &print_dots,
|
||||||
|
&right_dots);
|
||||||
|
if (v != LIBPTOUCH_OK) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_UNSUPPORTED,
|
||||||
|
"tape width/layout not supported for this media "
|
||||||
|
"(check status media bytes)");
|
||||||
|
return LIBPTOUCH_ERR_UNSUPPORTED;
|
||||||
|
}
|
||||||
|
(void)right_dots;
|
||||||
|
|
||||||
|
uint32_t wd = params->width_dots;
|
||||||
|
uint32_t ht = params->height_dots;
|
||||||
|
uint8_t *transposed = transpose_raster_alloc(data, wd, ht, &wd, &ht);
|
||||||
|
if (!transposed) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOMEM,
|
||||||
|
"transpose raster: out of memory");
|
||||||
|
return LIBPTOUCH_ERR_NOMEM;
|
||||||
|
}
|
||||||
|
const uint8_t *src = transposed;
|
||||||
|
|
||||||
|
if (wd > (uint32_t)print_dots) {
|
||||||
|
char buf[160];
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"image width %u dots > printable %u for loaded tape",
|
||||||
|
(unsigned)wd, (unsigned)print_dots);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, buf);
|
||||||
|
free(transposed);
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned margin_dots = 14u;
|
||||||
|
if (params->margin_mm > 0) {
|
||||||
|
margin_dots = (unsigned)((double)params->margin_mm * 360.0 /
|
||||||
|
25.4 +
|
||||||
|
0.5);
|
||||||
|
if (margin_dots < 14u)
|
||||||
|
margin_dots = 14u;
|
||||||
|
if (margin_dots > 1800u)
|
||||||
|
margin_dots = 1800u;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t lines = ht;
|
||||||
|
uint8_t n5 = (uint8_t)(lines & 0xFFu);
|
||||||
|
uint8_t n6 = (uint8_t)((lines >> 8) & 0xFFu);
|
||||||
|
uint8_t n7 = (uint8_t)((lines >> 16) & 0xFFu);
|
||||||
|
uint8_t n8 = (uint8_t)((lines >> 24) & 0xFFu);
|
||||||
|
|
||||||
|
uint8_t n2_paper = 0x09u;
|
||||||
|
if (media_kind == 0x03u)
|
||||||
|
n2_paper = 0x00u;
|
||||||
|
else if (media_kind == 0x11u)
|
||||||
|
n2_paper = 0x11u;
|
||||||
|
else if (media_kind == 0x17u)
|
||||||
|
n2_paper = 0x17u;
|
||||||
|
else if (media_kind == 0x13u)
|
||||||
|
n2_paper = 0x13u;
|
||||||
|
|
||||||
|
uint8_t head[256];
|
||||||
|
size_t pos = 0;
|
||||||
|
memset(head + pos, 0, 200);
|
||||||
|
pos += 200u;
|
||||||
|
static const uint8_t esc_at[] = { 0x1B, 0x40 };
|
||||||
|
memcpy(head + pos, esc_at, sizeof(esc_at));
|
||||||
|
pos += sizeof(esc_at);
|
||||||
|
static const uint8_t raster_mode[] = { 0x1B, 0x69, 0x61, 0x01 };
|
||||||
|
memcpy(head + pos, raster_mode, sizeof(raster_mode));
|
||||||
|
pos += sizeof(raster_mode);
|
||||||
|
|
||||||
|
uint8_t esc_iz[] = { 0x1B, 0x69, 0x7A, 0x0Eu, n2_paper, media_w,
|
||||||
|
0x00u, n5, n6, n7, n8, 0x02u, 0x00u };
|
||||||
|
memcpy(head + pos, esc_iz, sizeof(esc_iz));
|
||||||
|
pos += sizeof(esc_iz);
|
||||||
|
|
||||||
|
static const uint8_t esc_im[] = { 0x1B, 0x69, 0x4D, 0x40 };
|
||||||
|
memcpy(head + pos, esc_im, sizeof(esc_im));
|
||||||
|
pos += sizeof(esc_im);
|
||||||
|
static const uint8_t esc_ia[] = { 0x1B, 0x69, 0x41, 0x01 };
|
||||||
|
memcpy(head + pos, esc_ia, sizeof(esc_ia));
|
||||||
|
pos += sizeof(esc_ia);
|
||||||
|
static const uint8_t esc_ik[] = { 0x1B, 0x69, 0x4B, 0x0C };
|
||||||
|
memcpy(head + pos, esc_ik, sizeof(esc_ik));
|
||||||
|
pos += sizeof(esc_ik);
|
||||||
|
|
||||||
|
uint8_t esc_id[] = {
|
||||||
|
0x1B, 0x69, 0x64,
|
||||||
|
(uint8_t)(margin_dots & 0xFFu),
|
||||||
|
(uint8_t)((margin_dots >> 8) & 0xFFu)
|
||||||
|
};
|
||||||
|
memcpy(head + pos, esc_id, sizeof(esc_id));
|
||||||
|
pos += sizeof(esc_id);
|
||||||
|
|
||||||
|
static const uint8_t mode_m[] = { 0x4D, 0x00 };
|
||||||
|
memcpy(head + pos, mode_m, sizeof(mode_m));
|
||||||
|
pos += sizeof(mode_m);
|
||||||
|
|
||||||
|
v = ptouch_bulk_send_job(ctx, head, pos, "print preamble");
|
||||||
|
if (v != LIBPTOUCH_OK) {
|
||||||
|
free(transposed);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t row_b = ((size_t)wd + 7u) / 8u;
|
||||||
|
uint8_t gbuf[73];
|
||||||
|
static const uint8_t g_hdr[] = { 0x47, 0x46, 0x00 };
|
||||||
|
|
||||||
|
for (uint32_t y = 0; y < lines; y++) {
|
||||||
|
const uint8_t *row = src + (size_t)y * row_b;
|
||||||
|
pack_line_560(gbuf + 3, row, wd, left_dots, print_dots);
|
||||||
|
memcpy(gbuf, g_hdr, sizeof(g_hdr));
|
||||||
|
v = ptouch_bulk_send_job(ctx, gbuf, sizeof(gbuf), "raster line");
|
||||||
|
if (v != LIBPTOUCH_OK) {
|
||||||
|
free(transposed);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t print_end[] = { 0x1A };
|
||||||
|
v = ptouch_bulk_send_job(ctx, print_end, sizeof(print_end), "print end");
|
||||||
|
if (v != LIBPTOUCH_OK) {
|
||||||
|
free(transposed);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t sink[64];
|
||||||
|
int tr = 0;
|
||||||
|
(void)libusb_bulk_transfer(ctx->usb_handle, ctx->bulk_in_ep, sink,
|
||||||
|
(int)sizeof(sink), &tr, 3000);
|
||||||
|
(void)tr;
|
||||||
|
|
||||||
|
free(transposed);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
432
src/lib/libptouch_status.c
Normal file
432
src/lib/libptouch_status.c
Normal file
@@ -0,0 +1,432 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — printer status (ESC i S) and human-readable dump
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libptouch_internal.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_get_status(libptouch_ctx *ctx, uint8_t *status)
|
||||||
|
{
|
||||||
|
if (!ctx || !status) {
|
||||||
|
if (ctx)
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "null argument");
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
if (!ctx->usb_handle || !ctx->bulk_out_ep || !ctx->bulk_in_ep) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_IO,
|
||||||
|
"USB not open or bulk endpoints missing");
|
||||||
|
return LIBPTOUCH_ERR_IO;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_device_handle *h = ctx->usb_handle;
|
||||||
|
static const uint8_t init[] = { 0x1B, 0x40 };
|
||||||
|
static const uint8_t req[] = { 0x1B, 0x69, 0x53 };
|
||||||
|
|
||||||
|
int r = LIBUSB_ERROR_OTHER;
|
||||||
|
for (int attempt = 0; attempt < 2; attempt++) {
|
||||||
|
if (attempt > 0) {
|
||||||
|
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
||||||
|
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
||||||
|
}
|
||||||
|
r = ptouch_bulk_out(h, ctx->bulk_out_ep, init, 2, 5000u);
|
||||||
|
if (r != 0) {
|
||||||
|
ptouch_set_error_usb(ctx, r, "bulk OUT ESC @");
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
r = ptouch_bulk_out(h, ctx->bulk_out_ep, req, 3, 5000u);
|
||||||
|
if (r != 0) {
|
||||||
|
ptouch_set_error_usb(ctx, r, "bulk OUT ESC i S");
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
r = ptouch_bulk_in_exact(h, ctx->bulk_in_ep, status,
|
||||||
|
(int)LIBPTOUCH_STATUS_LENGTH, 5000u);
|
||||||
|
if (r == 0)
|
||||||
|
break;
|
||||||
|
if (r != LIBUSB_ERROR_IO && r != LIBUSB_ERROR_PIPE)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (r != 0) {
|
||||||
|
ptouch_set_error_usb(ctx, r, "bulk IN status");
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprint_model(FILE *fp, uint8_t code)
|
||||||
|
{
|
||||||
|
const char *name = "unknown";
|
||||||
|
switch (code) {
|
||||||
|
case 0x6F:
|
||||||
|
name = "PT-P900W";
|
||||||
|
break;
|
||||||
|
case 0x70:
|
||||||
|
name = "PT-P950NW";
|
||||||
|
break;
|
||||||
|
case 0x71:
|
||||||
|
name = "PT-P900";
|
||||||
|
break;
|
||||||
|
case 0x78:
|
||||||
|
name = "PT-P910BT";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(fp, "機種コード: 0x%02X ('%c') — %s\n", (unsigned)code,
|
||||||
|
(code >= 32 && code < 127) ? (char)code : '?', name);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprint_media_width(FILE *fp, uint8_t w, uint8_t len_byte)
|
||||||
|
{
|
||||||
|
const char *desc = NULL;
|
||||||
|
switch (w) {
|
||||||
|
case 0x00:
|
||||||
|
desc = "テープなし / 未装着";
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
desc = "3.5 mm";
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
desc = "6 mm";
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
desc = "9 mm";
|
||||||
|
break;
|
||||||
|
case 0x0C:
|
||||||
|
desc = "12 mm";
|
||||||
|
break;
|
||||||
|
case 0x12:
|
||||||
|
desc = "18 mm";
|
||||||
|
break;
|
||||||
|
case 0x18:
|
||||||
|
desc = "24 mm";
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
desc = "36 mm";
|
||||||
|
break;
|
||||||
|
case 0x15:
|
||||||
|
desc = "FLe 21 mm 幅(長さはメディア長バイト参照)";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (desc)
|
||||||
|
fprintf(fp, "メディア幅: 0x%02X — %s\n", (unsigned)w, desc);
|
||||||
|
else
|
||||||
|
fprintf(fp, "メディア幅: 0x%02X\n", (unsigned)w);
|
||||||
|
if (w == 0x15 && len_byte != 0)
|
||||||
|
fprintf(fp, "メディア長: 0x%02X (%u mm 相当の表記参照)\n",
|
||||||
|
(unsigned)len_byte, (unsigned)len_byte);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprint_media_kind(FILE *fp, uint8_t k)
|
||||||
|
{
|
||||||
|
const char *desc = NULL;
|
||||||
|
switch (k) {
|
||||||
|
case 0x00:
|
||||||
|
desc = "テープなし";
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
desc = "ラミネートテープ";
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
desc = "ノンラミネートテープ";
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
desc = "ファブリックテープ";
|
||||||
|
break;
|
||||||
|
case 0x11:
|
||||||
|
desc = "ヒートシュリンクチューブ (HS 2:1)";
|
||||||
|
break;
|
||||||
|
case 0x13:
|
||||||
|
desc = "FLe テープ";
|
||||||
|
break;
|
||||||
|
case 0x14:
|
||||||
|
desc = "フレキシブルIDテープ";
|
||||||
|
break;
|
||||||
|
case 0x15:
|
||||||
|
desc = "サテンテープ";
|
||||||
|
break;
|
||||||
|
case 0x17:
|
||||||
|
desc = "ヒートシュリンクチューブ (HS 3:1)";
|
||||||
|
break;
|
||||||
|
case 0xFF:
|
||||||
|
desc = "非対応テープ";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (desc)
|
||||||
|
fprintf(fp, "テープ種類: 0x%02X — %s\n", (unsigned)k, desc);
|
||||||
|
else
|
||||||
|
fprintf(fp, "テープ種類: 0x%02X\n", (unsigned)k);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprint_battery(FILE *fp, uint8_t b)
|
||||||
|
{
|
||||||
|
const char *desc = NULL;
|
||||||
|
switch (b) {
|
||||||
|
case 0x00:
|
||||||
|
desc = "フル";
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
desc = "ハーフ";
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
desc = "ロー";
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
desc = "要充電";
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
desc = "AC アダプター使用中";
|
||||||
|
break;
|
||||||
|
case 0xFF:
|
||||||
|
desc = "不明";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (desc)
|
||||||
|
fprintf(fp, "電池残量: 0x%02X — %s\n", (unsigned)b, desc);
|
||||||
|
else
|
||||||
|
fprintf(fp, "電池残量: 0x%02X (PT-P910BT 等は別表参照)\n",
|
||||||
|
(unsigned)b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprint_tape_color(FILE *fp, uint8_t c)
|
||||||
|
{
|
||||||
|
const char *desc = NULL;
|
||||||
|
switch (c) {
|
||||||
|
case 0x01:
|
||||||
|
desc = "白 (White)";
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
desc = "その他 (Other)";
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
desc = "透明 (Clear)";
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
desc = "赤 (Red)";
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
desc = "青 (Blue)";
|
||||||
|
break;
|
||||||
|
case 0x06:
|
||||||
|
desc = "黄 (Yellow)";
|
||||||
|
break;
|
||||||
|
case 0x07:
|
||||||
|
desc = "緑 (Green)";
|
||||||
|
break;
|
||||||
|
case 0x08:
|
||||||
|
desc = "黒 (Black)";
|
||||||
|
break;
|
||||||
|
case 0x09:
|
||||||
|
desc = "透明(文字白)";
|
||||||
|
break;
|
||||||
|
case 0x20:
|
||||||
|
desc = "白(マット) (Matte White)";
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
desc = "透明(マット) (Matte Clear)";
|
||||||
|
break;
|
||||||
|
case 0x22:
|
||||||
|
desc = "銀(マット) (Matte Silver)";
|
||||||
|
break;
|
||||||
|
case 0x23:
|
||||||
|
desc = "金(サテン) (Satin Gold)";
|
||||||
|
break;
|
||||||
|
case 0x24:
|
||||||
|
desc = "銀(サテン) (Satin Silver)";
|
||||||
|
break;
|
||||||
|
case 0x30:
|
||||||
|
desc = "青(D)";
|
||||||
|
break;
|
||||||
|
case 0x31:
|
||||||
|
desc = "赤(D)";
|
||||||
|
break;
|
||||||
|
case 0x40:
|
||||||
|
desc = "オレンジ(蛍光)";
|
||||||
|
break;
|
||||||
|
case 0x41:
|
||||||
|
desc = "黄(蛍光)";
|
||||||
|
break;
|
||||||
|
case 0x50:
|
||||||
|
desc = "ピンク(S)";
|
||||||
|
break;
|
||||||
|
case 0x51:
|
||||||
|
desc = "グレー(S)";
|
||||||
|
break;
|
||||||
|
case 0x52:
|
||||||
|
desc = "グリーン(S)";
|
||||||
|
break;
|
||||||
|
case 0x60:
|
||||||
|
desc = "イエロー(F)";
|
||||||
|
break;
|
||||||
|
case 0x61:
|
||||||
|
desc = "ピンク(F)";
|
||||||
|
break;
|
||||||
|
case 0x62:
|
||||||
|
desc = "ブルー(F)";
|
||||||
|
break;
|
||||||
|
case 0x70:
|
||||||
|
desc = "白(チューブ)";
|
||||||
|
break;
|
||||||
|
case 0x90:
|
||||||
|
desc = "白(フレキ)";
|
||||||
|
break;
|
||||||
|
case 0x91:
|
||||||
|
desc = "黄(フレキ)";
|
||||||
|
break;
|
||||||
|
case 0xF0:
|
||||||
|
desc = "クリーニング";
|
||||||
|
break;
|
||||||
|
case 0xF1:
|
||||||
|
desc = "ステンシル";
|
||||||
|
break;
|
||||||
|
case 0xFF:
|
||||||
|
desc = "非対応";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (desc)
|
||||||
|
fprintf(fp, "テープ色: 0x%02X — %s\n", (unsigned)c, desc);
|
||||||
|
else
|
||||||
|
fprintf(fp, "テープ色: 0x%02X\n", (unsigned)c);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void fprint_status_kind(FILE *fp, uint8_t s)
|
||||||
|
{
|
||||||
|
const char *desc = NULL;
|
||||||
|
switch (s) {
|
||||||
|
case 0x00:
|
||||||
|
desc = "印刷終了";
|
||||||
|
break;
|
||||||
|
case 0x01:
|
||||||
|
desc = "エラー発生";
|
||||||
|
break;
|
||||||
|
case 0x02:
|
||||||
|
desc = "IF モード終了";
|
||||||
|
break;
|
||||||
|
case 0x03:
|
||||||
|
desc = "パワーオフ(未使用扱い)";
|
||||||
|
break;
|
||||||
|
case 0x04:
|
||||||
|
desc = "通知";
|
||||||
|
break;
|
||||||
|
case 0x05:
|
||||||
|
desc = "フェーズ変更";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (desc)
|
||||||
|
fprintf(fp, "ステータス種類: 0x%02X — %s\n", (unsigned)s, desc);
|
||||||
|
else
|
||||||
|
fprintf(fp, "ステータス種類: 0x%02X\n", (unsigned)s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libptouch_status_fprint(FILE *fp, const uint8_t *status)
|
||||||
|
{
|
||||||
|
if (!fp || !status)
|
||||||
|
return;
|
||||||
|
|
||||||
|
fprintf(fp, "=== P-touch ステータス (32 バイト) ===\n");
|
||||||
|
if (status[0] != 0x80u || status[1] != 0x20u)
|
||||||
|
fprintf(fp,
|
||||||
|
"※ 先頭マーク異常: [0]=0x%02X [1]=0x%02X (通常 80 20)\n",
|
||||||
|
(unsigned)status[0], (unsigned)status[1]);
|
||||||
|
|
||||||
|
fprintf(fp, "ヘッダ: 0x%02X 0x%02X\n", (unsigned)status[0],
|
||||||
|
(unsigned)status[1]);
|
||||||
|
fprintf(fp, "Brother コード: %c (0x%02X)\n",
|
||||||
|
(status[2] >= 32 && status[2] < 127) ? (char)status[2] : '?',
|
||||||
|
(unsigned)status[2]);
|
||||||
|
fprint_model(fp, status[4]);
|
||||||
|
fprintf(fp, "国別コード: %c\n",
|
||||||
|
(status[5] >= 32 && status[5] < 127) ? (char)status[5] : '?');
|
||||||
|
|
||||||
|
fprint_battery(fp, status[6]);
|
||||||
|
|
||||||
|
if (status[7] != 0) {
|
||||||
|
fprintf(fp, "拡張エラー: 0x%02X", (unsigned)status[7]);
|
||||||
|
switch (status[7]) {
|
||||||
|
case 0x10:
|
||||||
|
fprintf(fp, " — FLE のテープエンド");
|
||||||
|
break;
|
||||||
|
case 0x1D:
|
||||||
|
fprintf(fp, " — 高解像度/ドラフト印刷エラー");
|
||||||
|
break;
|
||||||
|
case 0x1E:
|
||||||
|
fprintf(fp, " — アダプター抜き挿しエラー");
|
||||||
|
break;
|
||||||
|
case 0x21:
|
||||||
|
fprintf(fp, " — 非対応メディアエラー");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
fprintf(fp, "\n");
|
||||||
|
} else {
|
||||||
|
fprintf(fp, "拡張エラー: なし (0x00)\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(fp, "エラー情報1: 0x%02X\n", (unsigned)status[8]);
|
||||||
|
if (status[8] & 0x01)
|
||||||
|
fprintf(fp, " - メディア無し\n");
|
||||||
|
if (status[8] & 0x02)
|
||||||
|
fprintf(fp, " - メディア終了\n");
|
||||||
|
if (status[8] & 0x04)
|
||||||
|
fprintf(fp, " - カッタージャム\n");
|
||||||
|
if (status[8] & 0x08)
|
||||||
|
fprintf(fp, " - バッテリー弱\n");
|
||||||
|
if (status[8] & 0x40)
|
||||||
|
fprintf(fp, " - 高圧アダプター\n");
|
||||||
|
|
||||||
|
fprintf(fp, "エラー情報2: 0x%02X\n", (unsigned)status[9]);
|
||||||
|
if (status[9] & 0x01)
|
||||||
|
fprintf(fp, " - メディア交換(メディア違い)\n");
|
||||||
|
if (status[9] & 0x04)
|
||||||
|
fprintf(fp, " - 通信エラー\n");
|
||||||
|
if (status[9] & 0x08)
|
||||||
|
fprintf(fp, " - 通信バッファーフル\n");
|
||||||
|
if (status[9] & 0x10)
|
||||||
|
fprintf(fp, " - カバーオープン\n");
|
||||||
|
if (status[9] & 0x20)
|
||||||
|
fprintf(fp, " - 高温エラー\n");
|
||||||
|
if (status[9] & 0x40)
|
||||||
|
fprintf(fp, " - 先端検出エラー\n");
|
||||||
|
if (status[9] & 0x80)
|
||||||
|
fprintf(fp, " - システムエラー\n");
|
||||||
|
|
||||||
|
fprint_media_width(fp, status[10], status[17]);
|
||||||
|
fprint_media_kind(fp, status[11]);
|
||||||
|
fprintf(fp, "色数: 0x%02X フォント/日本語フォント: 0x%02X / 0x%02X\n",
|
||||||
|
(unsigned)status[12], (unsigned)status[13],
|
||||||
|
(unsigned)status[14]);
|
||||||
|
fprintf(fp, "モード: 0x%02X 濃度: 0x%02X\n", (unsigned)status[15],
|
||||||
|
(unsigned)status[16]);
|
||||||
|
|
||||||
|
fprint_status_kind(fp, status[18]);
|
||||||
|
fprintf(fp, "フェーズ種類: 0x%02X フェーズ番号: %02X %02X\n",
|
||||||
|
(unsigned)status[19], (unsigned)status[20],
|
||||||
|
(unsigned)status[21]);
|
||||||
|
fprintf(fp, "通知番号: 0x%02X\n", (unsigned)status[22]);
|
||||||
|
fprintf(fp, "拡張部バイト数: 0x%02X\n", (unsigned)status[23]);
|
||||||
|
|
||||||
|
fprint_tape_color(fp, status[24]);
|
||||||
|
fprintf(fp, "文字色: 0x%02X\n", (unsigned)status[25]);
|
||||||
|
|
||||||
|
fprintf(fp, "生データ: ");
|
||||||
|
for (unsigned i = 0; i < LIBPTOUCH_STATUS_LENGTH; i++)
|
||||||
|
fprintf(fp, "%02X%s", (unsigned)status[i],
|
||||||
|
i + 1 == LIBPTOUCH_STATUS_LENGTH ? "\n" : " ");
|
||||||
|
}
|
||||||
196
src/lib/libptouch_usb.c
Normal file
196
src/lib/libptouch_usb.c
Normal file
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* libptouch — USB (libusb): open/close, bulk transfers
|
||||||
|
*
|
||||||
|
* Author: knb
|
||||||
|
* Email: knb@artif.org
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "libptouch_internal.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* バルク IN/OUT を両方持つインタフェースを探して claim する。
|
||||||
|
* USB Printer クラス (bInterfaceClass==7) を優先する。
|
||||||
|
*/
|
||||||
|
static int claim_interface_with_bulk(libusb_device_handle *h, int *out_iface,
|
||||||
|
uint8_t *out_ep, uint8_t *in_ep)
|
||||||
|
{
|
||||||
|
libusb_device *dev = libusb_get_device(h);
|
||||||
|
struct libusb_config_descriptor *cfg = NULL;
|
||||||
|
int r = libusb_get_active_config_descriptor(dev, &cfg);
|
||||||
|
if (r != 0 || !cfg)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
for (int pass = 0; pass < 2; pass++) {
|
||||||
|
for (int i = 0; i < cfg->bNumInterfaces; i++) {
|
||||||
|
const struct libusb_interface_descriptor *alt =
|
||||||
|
&cfg->interface[i].altsetting[0];
|
||||||
|
if (pass == 0 &&
|
||||||
|
alt->bInterfaceClass != LIBUSB_CLASS_PRINTER)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
uint8_t ep_out = 0, ep_in = 0;
|
||||||
|
for (uint8_t k = 0; k < alt->bNumEndpoints; k++) {
|
||||||
|
const struct libusb_endpoint_descriptor *ep =
|
||||||
|
&alt->endpoint[k];
|
||||||
|
if ((ep->bmAttributes &
|
||||||
|
LIBUSB_TRANSFER_TYPE_MASK) ==
|
||||||
|
LIBUSB_TRANSFER_TYPE_BULK) {
|
||||||
|
if (ep->bEndpointAddress &
|
||||||
|
LIBUSB_ENDPOINT_IN)
|
||||||
|
ep_in = ep->bEndpointAddress;
|
||||||
|
else
|
||||||
|
ep_out = ep->bEndpointAddress;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!ep_out || !ep_in)
|
||||||
|
continue;
|
||||||
|
r = libusb_claim_interface(h, i);
|
||||||
|
if (r == 0) {
|
||||||
|
*out_iface = i;
|
||||||
|
*out_ep = ep_out;
|
||||||
|
*in_ep = ep_in;
|
||||||
|
libusb_free_config_descriptor(cfg);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
libusb_free_config_descriptor(cfg);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_open_usb_vid_pid(libptouch_ctx *ctx, uint16_t vid,
|
||||||
|
uint16_t pid)
|
||||||
|
{
|
||||||
|
if (!ctx) {
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
if (ctx->usb_handle) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_ARG, "USB already open");
|
||||||
|
return LIBPTOUCH_ERR_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
int r = libusb_init(&ctx->usb_ctx);
|
||||||
|
if (r != LIBUSB_SUCCESS) {
|
||||||
|
ptouch_set_error_usb(ctx, r, "libusb_init");
|
||||||
|
ctx->usb_ctx = NULL;
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
|
||||||
|
libusb_device_handle *h =
|
||||||
|
libusb_open_device_with_vid_pid(ctx->usb_ctx, vid, pid);
|
||||||
|
if (!h) {
|
||||||
|
libusb_exit(ctx->usb_ctx);
|
||||||
|
ctx->usb_ctx = NULL;
|
||||||
|
char buf[160];
|
||||||
|
snprintf(buf, sizeof(buf),
|
||||||
|
"no USB device 0x%04x:0x%04x (check cable, power, udev)",
|
||||||
|
(unsigned)vid, (unsigned)pid);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_NOT_FOUND, buf);
|
||||||
|
return LIBPTOUCH_ERR_NOT_FOUND;
|
||||||
|
}
|
||||||
|
ctx->usb_handle = h;
|
||||||
|
|
||||||
|
#if defined(LIBUSB_API_VERSION) && (LIBUSB_API_VERSION >= 0x01000106)
|
||||||
|
(void)libusb_set_auto_detach_kernel_driver(h, 1);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (claim_interface_with_bulk(h, &ctx->claimed_interface,
|
||||||
|
&ctx->bulk_out_ep, &ctx->bulk_in_ep) != 0) {
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_USB,
|
||||||
|
"no bulk IN/OUT interface (permissions or driver?)");
|
||||||
|
libusb_close(h);
|
||||||
|
ctx->usb_handle = NULL;
|
||||||
|
libusb_exit(ctx->usb_ctx);
|
||||||
|
ctx->usb_ctx = NULL;
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
|
||||||
|
(void)libusb_clear_halt(h, ctx->bulk_out_ep);
|
||||||
|
(void)libusb_clear_halt(h, ctx->bulk_in_ep);
|
||||||
|
|
||||||
|
ctx->usb_open = 1;
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_OK, "");
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t libptouch_open_usb(libptouch_ctx *ctx)
|
||||||
|
{
|
||||||
|
return libptouch_open_usb_vid_pid(ctx, LIBPTOUCH_USB_VID_BROTHER,
|
||||||
|
LIBPTOUCH_USB_PID_PTP900W);
|
||||||
|
}
|
||||||
|
|
||||||
|
void libptouch_close(libptouch_ctx *ctx)
|
||||||
|
{
|
||||||
|
if (!ctx)
|
||||||
|
return;
|
||||||
|
if (ctx->usb_handle) {
|
||||||
|
if (ctx->claimed_interface >= 0) {
|
||||||
|
(void)libusb_release_interface(ctx->usb_handle,
|
||||||
|
ctx->claimed_interface);
|
||||||
|
ctx->claimed_interface = -1;
|
||||||
|
}
|
||||||
|
libusb_close(ctx->usb_handle);
|
||||||
|
ctx->usb_handle = NULL;
|
||||||
|
}
|
||||||
|
if (ctx->usb_ctx) {
|
||||||
|
libusb_exit(ctx->usb_ctx);
|
||||||
|
ctx->usb_ctx = NULL;
|
||||||
|
}
|
||||||
|
ctx->bulk_out_ep = 0;
|
||||||
|
ctx->bulk_in_ep = 0;
|
||||||
|
ctx->usb_open = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ptouch_bulk_out(libusb_device_handle *h, uint8_t ep, const uint8_t *data,
|
||||||
|
int len, unsigned int timeout_ms)
|
||||||
|
{
|
||||||
|
int tr = 0;
|
||||||
|
int r = libusb_bulk_transfer(h, ep, (unsigned char *)data, len, &tr,
|
||||||
|
(int)timeout_ms);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
if (tr != len)
|
||||||
|
return LIBUSB_ERROR_IO;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ptouch_bulk_in_exact(libusb_device_handle *h, uint8_t ep, uint8_t *buf,
|
||||||
|
int len, unsigned int timeout_ms)
|
||||||
|
{
|
||||||
|
int got = 0;
|
||||||
|
while (got < len) {
|
||||||
|
int tr = 0;
|
||||||
|
int r = libusb_bulk_transfer(h, ep, buf + got, len - got, &tr,
|
||||||
|
(int)timeout_ms);
|
||||||
|
if (r != 0)
|
||||||
|
return r;
|
||||||
|
if (tr == 0)
|
||||||
|
return LIBUSB_ERROR_IO;
|
||||||
|
got += tr;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
libptouch_err_t ptouch_bulk_send_job(libptouch_ctx *ctx, const uint8_t *buf,
|
||||||
|
size_t len, const char *what)
|
||||||
|
{
|
||||||
|
int tr = 0;
|
||||||
|
int r = libusb_bulk_transfer(ctx->usb_handle, ctx->bulk_out_ep,
|
||||||
|
(unsigned char *)buf, (int)len, &tr,
|
||||||
|
120000);
|
||||||
|
if (r != 0) {
|
||||||
|
ptouch_set_error_usb(ctx, r, what);
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
if ((size_t)tr != len) {
|
||||||
|
char msg[96];
|
||||||
|
snprintf(msg, sizeof(msg), "%s: short write %d/%zu", what, tr,
|
||||||
|
len);
|
||||||
|
ptouch_set_error(ctx, LIBPTOUCH_ERR_USB, msg);
|
||||||
|
return LIBPTOUCH_ERR_USB;
|
||||||
|
}
|
||||||
|
return LIBPTOUCH_OK;
|
||||||
|
}
|
||||||
1164
src/libptouch.c
1164
src/libptouch.c
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user