Skip to content

Instantly share code, notes, and snippets.

@GOROman
Last active November 20, 2024 15:20
Show Gist options
  • Save GOROman/6881b1ef30364a584c37eb66fd605395 to your computer and use it in GitHub Desktop.
Save GOROman/6881b1ef30364a584c37eb66fd605395 to your computer and use it in GitHub Desktop.
ALIENTEK DP100 を C言語からコントロールするサンプル 無保証・自己責任で
// Alientek DP100 Control Test
// @GOROman
// for MacOS
// > brew install hidapi
// > gcc -o dp100 dp100.c -I/opt/homebrew/include/ -L/opt/homebrew/lib -lhidapi
#include <stdio.h>
#include <stdint.h>
#include <string.h>
#include <unistd.h> // sleep関数のため
#include <hidapi/hidapi.h>
#define VENDOR_ID 0x2e3c // ALIENTEK
#define PRODUCT_ID 0xaf01 // DP100
#define PACKET_SIZE 64
// DeviceInfo構造体
typedef struct {
uint8_t dev_type[16]; // デバイス名
uint16_t hdw_ver;
uint16_t app_ver;
uint16_t boot_ver;
uint16_t run_area;
uint8_t dev_sn[12]; // 16進数シリアルナンバー
// 製造年この辺は値がおかしい
uint16_t year;
uint8_t moon;
uint8_t day;
} DeviceInfo;
// BasicSet構造体
typedef struct {
uint8_t index;
uint8_t state; // 0:off 1:on
uint16_t vo_set;
uint16_t io_set;
uint16_t ovp_set;
uint16_t ocp_set;
} BasicSet;
#define INDEX_FLAG_SET 0x20
#define INDEX_FLAG_ACTIVE 0x80
// BasicInfo構造体
typedef struct {
uint16_t vin; // 単位: mV
uint16_t vout; // 単位: mV
uint16_t iout; // ?
uint16_t vo_max; // 単位: mV
uint16_t temp1; // 単位: 100m度C
int16_t temp2; // 単位: 100m度C
uint16_t dc_5v; // 単位: mV
uint8_t out_mode;
uint8_t work_st;
} BasicInfo;
typedef enum {
OpCode_None = 0x00,
OpCode_DeviceInfo = 0x10,
OpCode_BasicInfo = 0x30,
OpCode_BasicSet = 0x35,
OpCode_SystemInfo = 0x40,
OpCode_ScanOut = 0x50,
OpCode_SerialOut = 0x55,
OpCode_Invalid = 0xFF
} OpCode;
// CRC-16/MODBUS 計算関数
uint16_t calculate_crc16(const uint8_t *data, size_t length) {
uint16_t crc = 0xFFFF; // 初期値
for (size_t i = 0; i < length; i++) {
crc ^= data[i];
for (uint8_t j = 0; j < 8; j++) {
if (crc & 1)
crc = (crc >> 1) ^ 0xA001; // 多項式: 0xA001
else
crc >>= 1;
}
}
return crc; // 計算結果(リトルエンディアン形式)
}
int send_frame(hid_device* handle, OpCode op_code, const uint8_t* data, size_t length) {
printf("Sending OpCode: 0x%02X\n", op_code);
printf("Data length: %zu\n", length);
uint8_t frame[PACKET_SIZE] = {0};
frame[0] = 0xfb; // direction
frame[1] = op_code; // OpCode
frame[2] = 0x00; // reserved
frame[3] = length; // データ長
if (data) {
memcpy(frame + 4, data, length);
}
uint16_t crc = calculate_crc16(frame, length + 4);
frame[length + 4] = crc & 0xFF; // CRC16(リトルエンディアン)
frame[length + 5] = crc >> 8; // CRC16(リトルエンディアン)
// 送信
int res = hid_write(handle, frame, sizeof(frame));
if (res < 0) {
fprintf(stderr, "Error writing to device: %ls\n", hid_error(handle));
return -1;
} else {
printf("Sent %d bytes to the device:\n", res);
for (int i = 0; i < res; i++) {
printf("%02x ", frame[i]);
}
printf("\n");
}
return 0;
}
int recv_frame(hid_device* handle, void* data, size_t size) {
int res;
uint8_t buf[PACKET_SIZE] = {0};
printf("Waiting for response...\n");
// 応答を受信
memset(buf, 0, sizeof(buf));
res = hid_read(handle, buf, sizeof(buf));
if (res < 0) {
fprintf(stderr, "Error reading from device: %ls\n", hid_error(handle));
return -1;
}
printf("Received %d bytes from the device:\n", res);
for (int i = 0; i < res; i++) {
printf("%02x ", buf[i]);
}
printf("\n");
uint8_t len = buf[3];
// CRC16の検証
uint16_t recv_crc = buf[4+ len] | (buf[5+len] << 8);
uint16_t calc_crc = calculate_crc16(buf, len+4);
if (recv_crc != calc_crc) {
fprintf(stderr, "CRC mismatch: calculated 0x%04X, received 0x%04X\n", calc_crc, recv_crc);
}
// データ部
memcpy(data, buf + 4, size);
return 0;
}
// DP100 デバイス情報取得
void print_DeviceInfo(hid_device* handle)
{
send_frame(handle, OpCode_DeviceInfo, NULL, 0);
DeviceInfo info;
if ( recv_frame(handle, &info, sizeof(DeviceInfo)) >= 0 ) {
// 受信成功
printf("\tdev_type: %s\n", info.dev_type);
printf("\thdw_ver: %d\n", info.hdw_ver);
printf("\tapp_ver: %d\n", info.app_ver);
printf("\tboot_ver: %d\n", info.boot_ver);
printf("\trun_area: %d\n", info.run_area);
printf("\tdev_sn: ");
for(int i = 0; i < 12; i++) {
printf("%02X", info.dev_sn[i]);
}
printf("\n");
}
}
void print_BasicInfo(hid_device* handle)
{
send_frame(handle, OpCode_BasicInfo, NULL, 0);
BasicInfo info;
if ( recv_frame(handle, &info, sizeof(BasicInfo)) >= 0 ) {
// 受信成功
printf("\tvin: %4.3fV\n", info.vin/1000.0f);
printf("\tvout: %4.3fV\n", info.vout/1000.0f);
printf("\tiout: %4.3fA\n", info.iout/1000.0f);
printf("\tvo_max: %4.3fV\n", info.vo_max/1000.0f);
printf("\ttemp1: %3.1f 'C\n", info.temp1 / 10.0f);
printf("\ttemp2: %3.1f 'C\n", info.temp2 / 10.0f);
printf("\tdc_5v: %4.3fV\n", info.dc_5v / 1000.0f);
printf("\tout_mode: %d\n", info.out_mode);
printf("\twork_st: %d\n", info.work_st);
}
}
void get_BasicSet(hid_device* handle, uint8_t index, BasicSet* info)
{
uint8_t data = index;
send_frame(handle, OpCode_BasicSet, (uint8_t*)&data, sizeof(data));
recv_frame(handle, info, sizeof(BasicSet));
}
void set_BasicSet(hid_device* handle, BasicSet* set)
{
send_frame(handle, OpCode_BasicSet, (uint8_t*)set, sizeof(BasicSet));
uint8_t result = 0;
recv_frame(handle, &result, sizeof(result));
}
int main() {
hid_device *handle;
unsigned char buf[PACKET_SIZE] = {0};
int res;
// hidapiの初期化
if (hid_init()) {
fprintf(stderr, "Failed to initialize hidapi.\n");
return -1;
}
// デバイスをオープン
handle = hid_open(VENDOR_ID, PRODUCT_ID, NULL);
if (!handle) {
fprintf(stderr, "Failed to open HID device (VID: 0x%04x, PID: 0x%04x).\n", VENDOR_ID, PRODUCT_ID);
hid_exit();
return -1;
}
// DP100 デバイス情報取得
print_DeviceInfo(handle);
// DP100 基本情報取得
print_BasicInfo(handle);
// DP100 基本設定をクエリ
BasicSet set;
get_BasicSet(handle, INDEX_FLAG_ACTIVE, &set); // 0x80 == current
printf("index: %d\n", set.index);
printf("state: 0x%02x\n", set.state);
printf("vo_set: %4.3fV\n", set.vo_set/1000.0f);
printf("io_set: %4.3fA\n", set.io_set/1000.0f);
printf("ovp_set: %4.3fV\n", set.ovp_set/1000.0f);
printf("ocp_set: %4.3fA\n", set.ocp_set/1000.0f);
sleep(2);
// 電圧と電流を設定する
set.vo_set = 1500; // 1.5V
set.io_set = 100; // 0.1A
for (int i=0;i<10;i++) {
// DP100 基本設定をセット
int index = 0;
set.vo_set += 100;
set.state = (i % 2) ? 0x01 : 0x00; // Lチカ
set.index = INDEX_FLAG_SET | index;
printf("-> index: %d\n", set.index);
printf("-> state: 0x%02x\n", set.state);
printf("-> vo_set: %4.3fV\n", set.vo_set/1000.0f);
set_BasicSet(handle, &set);
usleep(1000*50);
get_BasicSet(handle, INDEX_FLAG_ACTIVE, &set); // 0x80 == current
printf("index: 0x%02x\n", set.index);
printf("state: 0x%02x\n", set.state);
printf("vo_set: %4.3fV\n", set.vo_set/1000.0f);
printf("io_set: %4.3fA\n", set.io_set/1000.0f);
printf("ovp_set: %4.3fV\n", set.ovp_set/1000.0f);
printf("ocp_set: %4.3fA\n", set.ocp_set/1000.0f);
usleep(1000*200);
}
// デバイスを閉じる
hid_close(handle);
// hidapiの終了
hid_exit();
return 0;
}
@GOROman
Copy link
Author

GOROman commented Nov 20, 2024

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment