Added source code
Ver 0.5
This commit is contained in:
31
Makefile
Normal file
31
Makefile
Normal file
@@ -0,0 +1,31 @@
|
||||
CC = gcc
|
||||
CFLAGS = -Wall -Wextra -O2 `pkg-config --cflags hidapi-hidraw`
|
||||
LDFLAGS = `pkg-config --libs hidapi-hidraw`
|
||||
|
||||
SRC_DIR = src
|
||||
BUILD_DIR = .build
|
||||
BIN_DIR = bin
|
||||
OUT = $(BIN_DIR)/annepro2_flasher_c
|
||||
|
||||
SRCS = $(wildcard $(SRC_DIR)/*.c)
|
||||
OBJS = $(patsubst $(SRC_DIR)/%.c,$(BUILD_DIR)/%.o,$(SRCS))
|
||||
|
||||
PREFIX ?= /usr/local
|
||||
BINDIR = $(PREFIX)/bin
|
||||
|
||||
all: $(BIN_DIR) $(BUILD_DIR) $(OUT)
|
||||
|
||||
$(BUILD_DIR)/%.o: $(SRC_DIR)/%.c
|
||||
$(CC) $(CFLAGS) -c $< -o $@
|
||||
|
||||
$(OUT): $(OBJS)
|
||||
$(CC) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
$(BIN_DIR) $(BUILD_DIR):
|
||||
mkdir -p $@
|
||||
|
||||
install: $(OUT)
|
||||
install -Dm755 $(OUT) $(BINDIR)/annepro2_tools_c
|
||||
|
||||
clean:
|
||||
rm -rf $(BUILD_DIR) $(BIN_DIR)
|
||||
192
src/annepro2.c
Normal file
192
src/annepro2.c
Normal file
@@ -0,0 +1,192 @@
|
||||
#include "annepro2.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <time.h>
|
||||
|
||||
#define ANNEPRO2_VID 0x04d9
|
||||
#define PID_C15 0x8008
|
||||
#define PID_C18 0x8009
|
||||
|
||||
static int write_to_target(hid_device *handle, AP2Target target, const uint8_t *payload, size_t payload_len);
|
||||
|
||||
static const char *flash_error_msgs[] = {
|
||||
"No device found",
|
||||
"Multiple devices found",
|
||||
"USB error",
|
||||
"Erase error",
|
||||
"Flash error",
|
||||
"Unknown error"
|
||||
};
|
||||
|
||||
const char* get_flash_error_msg(AP2FlashError err) {
|
||||
if (err < 0 || err >= OtherError) return flash_error_msgs[OtherError];
|
||||
return flash_error_msgs[err];
|
||||
}
|
||||
|
||||
int flash_firmware(AP2Target target, uint32_t base, FILE *file, int boot) {
|
||||
hid_device *handle = NULL;
|
||||
struct hid_device_info *devices = NULL, *dev = NULL;
|
||||
|
||||
// Первый поиск
|
||||
devices = hid_enumerate(ANNEPRO2_VID, 0);
|
||||
for (dev = devices; dev; dev = dev->next) {
|
||||
if ((dev->product_id == PID_C15 && dev->interface_number == 1) ||
|
||||
dev->product_id == PID_C18) {
|
||||
handle = hid_open_path(dev->path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hid_free_enumeration(devices);
|
||||
|
||||
// Ожидание устройства
|
||||
if (!handle) {
|
||||
printf("Please put your keyboard into IAP mode (hold ESC while plugging it in).\n");
|
||||
for (int i = 10; i > 0; i--) {
|
||||
sleep(1);
|
||||
devices = hid_enumerate(ANNEPRO2_VID, 0);
|
||||
for (dev = devices; dev; dev = dev->next) {
|
||||
if ((dev->product_id == PID_C15 && dev->interface_number == 1) ||
|
||||
dev->product_id == PID_C18) {
|
||||
handle = hid_open_path(dev->path);
|
||||
break;
|
||||
}
|
||||
}
|
||||
hid_free_enumeration(devices);
|
||||
if (handle) break;
|
||||
printf("Waiting... %ds remaining\r", i);
|
||||
fflush(stdout);
|
||||
}
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
if (!handle) {
|
||||
fprintf(stderr, "No compatible device found after waiting. Ensure the keyboard is in IAP mode.\n");
|
||||
return NoDeviceFound;
|
||||
}
|
||||
|
||||
// Стирание
|
||||
uint8_t erase_cmd[6] = {
|
||||
0x02, 0x43,
|
||||
base & 0xFF, (base >> 8) & 0xFF,
|
||||
(base >> 16) & 0xFF, (base >> 24) & 0xFF
|
||||
};
|
||||
if (write_to_target(handle, target, erase_cmd, sizeof(erase_cmd)) < 0) {
|
||||
fprintf(stderr, "Error erasing device memory.\n");
|
||||
hid_close(handle);
|
||||
return EraseError;
|
||||
}
|
||||
|
||||
// Получение размера прошивки
|
||||
fseek(file, 0, SEEK_END);
|
||||
size_t total_size = ftell(file);
|
||||
rewind(file);
|
||||
|
||||
uint8_t chunk[48];
|
||||
size_t read_size;
|
||||
uint32_t current_addr = base;
|
||||
size_t total_written = 0;
|
||||
time_t start = time(NULL);
|
||||
|
||||
while ((read_size = fread(chunk, 1, sizeof(chunk), file)) > 0) {
|
||||
uint8_t flash_cmd[6 + 48] = {
|
||||
0x02, 0x31,
|
||||
current_addr & 0xFF, (current_addr >> 8) & 0xFF,
|
||||
(current_addr >> 16) & 0xFF, (current_addr >> 24) & 0xFF
|
||||
};
|
||||
memcpy(flash_cmd + 6, chunk, read_size);
|
||||
|
||||
if (write_to_target(handle, target, flash_cmd, 6 + read_size) < 0) {
|
||||
fprintf(stderr, "\nError flashing memory at address 0x%08x.\n", current_addr);
|
||||
hid_close(handle);
|
||||
return FlashError;
|
||||
}
|
||||
|
||||
total_written += read_size;
|
||||
current_addr += read_size;
|
||||
|
||||
float percent = (float)total_written / total_size;
|
||||
int bars = (int)(percent * 30);
|
||||
time_t now = time(NULL);
|
||||
int elapsed = (int)difftime(now, start);
|
||||
|
||||
printf("\r[");
|
||||
for (int i = 0; i < 30; i++) {
|
||||
if (i < bars) printf("=");
|
||||
else printf(" ");
|
||||
}
|
||||
printf("] %3.0f%% | %zu/%zu bytes | %ds elapsed", percent * 100, total_written, total_size, elapsed);
|
||||
fflush(stdout);
|
||||
}
|
||||
|
||||
printf("\nFlash complete: %zu bytes written in %lds.\n", total_written, time(NULL) - start);
|
||||
|
||||
// Установка AP-флага
|
||||
uint8_t ap_flag_cmd[3] = {0x02, 0x32, 0x02};
|
||||
if (write_to_target(handle, McuMain, ap_flag_cmd, sizeof(ap_flag_cmd)) < 0) {
|
||||
fprintf(stderr, "Error writing AP flag.\n");
|
||||
hid_close(handle);
|
||||
return FlashError;
|
||||
}
|
||||
|
||||
|
||||
// Рестарт устройства, если нужно
|
||||
if (boot) {
|
||||
/*
|
||||
uint8_t boot_cmd[] = {
|
||||
0x00, 0x7b, 0x10, 0x31,
|
||||
0x10, 0x03, 0x00, 0x00,
|
||||
0x7d, 0x02, 0x01, 0x02
|
||||
};
|
||||
if (hid_write(handle, boot_cmd, sizeof(boot_cmd)) < 0) {
|
||||
fprintf(stderr, "Error booting device.\n");
|
||||
hid_close(handle);
|
||||
return FlashError;
|
||||
}
|
||||
*/
|
||||
uint8_t boot_cmd[] = {
|
||||
0x00, 0x7b, 0x10, 0x31,
|
||||
0x10, 0x03, 0x00, 0x00,
|
||||
0x7d, 0x02, 0x01, 0x02
|
||||
};
|
||||
if (hid_write(handle, boot_cmd, sizeof(boot_cmd)) < 0) {
|
||||
fprintf(stderr, "Error booting device.\n");
|
||||
hid_close(handle);
|
||||
return FlashError;
|
||||
}
|
||||
}
|
||||
|
||||
hid_close(handle);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int write_to_target(hid_device *handle, AP2Target target, const uint8_t *payload, size_t payload_len) {
|
||||
uint8_t buffer[64] = {0};
|
||||
buffer[1] = 0x7b;
|
||||
buffer[2] = 0x10;
|
||||
buffer[3] = ((target & 0x0F) << 4) | UsbHost;
|
||||
buffer[4] = 0x10;
|
||||
buffer[5] = (uint8_t)payload_len;
|
||||
buffer[6] = 0x00;
|
||||
buffer[7] = 0x00;
|
||||
buffer[8] = 0x7d;
|
||||
memcpy(buffer + 9, payload, payload_len);
|
||||
|
||||
// Padding
|
||||
memset(buffer + 9 + payload_len, 0, 64 - 9 - payload_len);
|
||||
|
||||
if (hid_write(handle, buffer, sizeof(buffer)) < 0) {
|
||||
fprintf(stderr, "HID write error.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
uint8_t response[64] = {0};
|
||||
if (hid_read(handle, response, sizeof(response)) < 0) {
|
||||
fprintf(stderr, "HID read error.\n");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
30
src/annepro2.h
Normal file
30
src/annepro2.h
Normal file
@@ -0,0 +1,30 @@
|
||||
// annepro2.h
|
||||
#ifndef ANNEPRO2_H
|
||||
#define ANNEPRO2_H
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include "hidapi.h"
|
||||
|
||||
typedef enum {
|
||||
UsbHost = 1,
|
||||
BleHost = 2,
|
||||
McuMain = 3,
|
||||
McuLed = 4,
|
||||
McuBle = 5
|
||||
} AP2Target;
|
||||
|
||||
typedef enum {
|
||||
NoDeviceFound,
|
||||
MultipleDeviceFound,
|
||||
USBError,
|
||||
EraseError,
|
||||
FlashError,
|
||||
OtherError
|
||||
} AP2FlashError;
|
||||
|
||||
int flash_firmware(AP2Target target, uint32_t base, FILE *file, int boot);
|
||||
const char* get_flash_error_msg(AP2FlashError err);
|
||||
|
||||
#endif
|
||||
|
||||
79
src/main.c
Normal file
79
src/main.c
Normal file
@@ -0,0 +1,79 @@
|
||||
// main.c
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <stdint.h>
|
||||
#include "annepro2.h"
|
||||
|
||||
uint32_t parse_hex(const char *str) {
|
||||
if (strncmp(str, "0x", 2) == 0 || strncmp(str, "0X", 2) == 0) {
|
||||
return (uint32_t)strtoul(str + 2, NULL, 16);
|
||||
}
|
||||
return (uint32_t)strtoul(str, NULL, 16);
|
||||
}
|
||||
|
||||
void print_usage(const char *prog) {
|
||||
printf("Usage: %s [--base <hex>] [--boot] [-t <target>] <file>\n", prog);
|
||||
printf("Targets: main, led, ble\n");
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
uint32_t base = 0x4000;
|
||||
int boot = 0;
|
||||
const char *target_str = "main";
|
||||
const char *file_path = NULL;
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--base") == 0 && i + 1 < argc) {
|
||||
base = parse_hex(argv[++i]);
|
||||
} else if (strcmp(argv[i], "--boot") == 0) {
|
||||
boot = 1;
|
||||
} else if ((strcmp(argv[i], "-t") == 0 || strcmp(argv[i], "--target") == 0) && i + 1 < argc) {
|
||||
target_str = argv[++i];
|
||||
} else if (argv[i][0] != '-') {
|
||||
file_path = argv[i];
|
||||
} else {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!file_path) {
|
||||
print_usage(argv[0]);
|
||||
return 1;
|
||||
}
|
||||
|
||||
AP2Target target;
|
||||
if (strcasecmp(target_str, "main") == 0) {
|
||||
target = McuMain;
|
||||
} else if (strcasecmp(target_str, "led") == 0) {
|
||||
target = McuLed;
|
||||
} else if (strcasecmp(target_str, "ble") == 0) {
|
||||
target = McuBle;
|
||||
} else {
|
||||
fprintf(stderr, "Invalid target: %s\n", target_str);
|
||||
return 1;
|
||||
}
|
||||
|
||||
FILE *f = fopen(file_path, "rb");
|
||||
if (!f) {
|
||||
perror("Failed to open file");
|
||||
return 1;
|
||||
}
|
||||
|
||||
int result = flash_firmware(target, base, f, boot);
|
||||
fclose(f);
|
||||
|
||||
if (result == 0) {
|
||||
printf("Flash complete\n");
|
||||
if (boot) {
|
||||
printf("Booting Keyboard\n");
|
||||
}
|
||||
} else {
|
||||
fprintf(stderr, "Flash error: %s\n", get_flash_error_msg(result));
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user