mirror of
https://github.com/djhackersdev/bemanitools.git
synced 2024-12-01 01:27:18 +01:00
aciodrv: add PANB support (+ aciotest handler)
add aciodrv-proc module explanation : PANB works differently from other acio devices ; you send one "start auto input" command without expecting a reply, and then the piano keeps spamming "recv poll" commands on the acio bus and never replies to any other commands.. failure to process these messages quickly enough will saturate the serial buffer and cause checksum errors after a while. for this reason, aciodrv-proc module was added in order to create a thread which manages these recv poll commands and keeps the latest known button state in memory so that it can be retrieved easily.
This commit is contained in:
parent
fb593df4a1
commit
4ea1397af2
@ -77,6 +77,7 @@ avsvers_64 := 1700 1603 1601 1509 1508
|
|||||||
imps += avs avs-ea3
|
imps += avs avs-ea3
|
||||||
|
|
||||||
include src/main/aciodrv/Module.mk
|
include src/main/aciodrv/Module.mk
|
||||||
|
include src/main/aciodrv-proc/Module.mk
|
||||||
include src/main/acioemu/Module.mk
|
include src/main/acioemu/Module.mk
|
||||||
include src/main/aciomgr/Module.mk
|
include src/main/aciomgr/Module.mk
|
||||||
include src/main/aciotest/Module.mk
|
include src/main/aciotest/Module.mk
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include "acio/hdxs.h"
|
#include "acio/hdxs.h"
|
||||||
#include "acio/icca.h"
|
#include "acio/icca.h"
|
||||||
#include "acio/kfca.h"
|
#include "acio/kfca.h"
|
||||||
|
#include "acio/panb.h"
|
||||||
|
|
||||||
#define AC_IO_SOF 0xAA
|
#define AC_IO_SOF 0xAA
|
||||||
#define AC_IO_ESCAPE 0xFF
|
#define AC_IO_ESCAPE 0xFF
|
||||||
@ -38,6 +39,7 @@ enum ac_io_node_type {
|
|||||||
AC_IO_NODE_TYPE_KFCA = 0x09060000,
|
AC_IO_NODE_TYPE_KFCA = 0x09060000,
|
||||||
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
|
AC_IO_NODE_TYPE_BI2A = 0x0d060000,
|
||||||
AC_IO_NODE_TYPE_RVOL = 0x09060001,
|
AC_IO_NODE_TYPE_RVOL = 0x09060001,
|
||||||
|
AC_IO_NODE_TYPE_PANB = 0x090E0000,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
@ -78,6 +80,9 @@ struct ac_io_message {
|
|||||||
struct ac_io_kfca_poll_in kfca_poll_in;
|
struct ac_io_kfca_poll_in kfca_poll_in;
|
||||||
struct ac_io_kfca_poll_out kfca_poll_out;
|
struct ac_io_kfca_poll_out kfca_poll_out;
|
||||||
|
|
||||||
|
struct ac_io_panb_poll_in panb_poll_in;
|
||||||
|
struct ac_io_panb_poll_out panb_poll_out;
|
||||||
|
|
||||||
struct ac_io_hdxs_output hdxs_output;
|
struct ac_io_hdxs_output hdxs_output;
|
||||||
};
|
};
|
||||||
} cmd;
|
} cmd;
|
||||||
|
42
src/main/acio/panb.h
Normal file
42
src/main/acio/panb.h
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
#ifndef AC_IO_PANB_H
|
||||||
|
#define AC_IO_PANB_H
|
||||||
|
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#define AC_IO_CMD_PANB_POLL_REPLY 0x0110
|
||||||
|
#define AC_IO_CMD_PANB_SEND_LAMP 0x0111
|
||||||
|
#define AC_IO_CMD_PANB_START_AUTO_INPUT 0x0115
|
||||||
|
|
||||||
|
#define AC_IO_PANB_NUM_NODES 4
|
||||||
|
#define AC_IO_PANB_MAX_KEYS (7*AC_IO_PANB_NUM_NODES)
|
||||||
|
#define AC_IO_PANB_MAX_KEYPAIRS (AC_IO_PANB_MAX_KEYS/2)
|
||||||
|
|
||||||
|
struct ac_io_panb_keypair {
|
||||||
|
uint8_t key2 : 4;
|
||||||
|
uint8_t key1 : 4;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct ac_io_panb_poll_in {
|
||||||
|
/* last received command sequence number (start_auto_input / send_lamp) */
|
||||||
|
uint8_t sub_seq1;
|
||||||
|
/* auto-increment sequence number for autopoll reports */
|
||||||
|
uint8_t sub_seq2;
|
||||||
|
struct ac_io_panb_keypair keypair[AC_IO_PANB_MAX_KEYPAIRS];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
struct ac_io_panb_color {
|
||||||
|
uint8_t red;
|
||||||
|
uint8_t green;
|
||||||
|
uint8_t blue;
|
||||||
|
};
|
||||||
|
|
||||||
|
#pragma pack(push, 1)
|
||||||
|
struct ac_io_panb_poll_out {
|
||||||
|
struct ac_io_panb_color key[AC_IO_PANB_MAX_KEYS];
|
||||||
|
};
|
||||||
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
7
src/main/aciodrv-proc/Module.mk
Normal file
7
src/main/aciodrv-proc/Module.mk
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
libs += aciodrv-proc
|
||||||
|
|
||||||
|
libs_aciodrv-proc := \
|
||||||
|
|
||||||
|
src_aciodrv-proc := \
|
||||||
|
panb.c \
|
||||||
|
|
90
src/main/aciodrv-proc/panb.c
Normal file
90
src/main/aciodrv-proc/panb.c
Normal file
@ -0,0 +1,90 @@
|
|||||||
|
#define LOG_MODULE "aciodrv-proc-panb"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "aciodrv/device.h"
|
||||||
|
#include "aciodrv/panb.h"
|
||||||
|
|
||||||
|
#include "util/thread.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
|
static int auto_poll_proc(void *auto_poll_param);
|
||||||
|
static int auto_poll_threadid;
|
||||||
|
|
||||||
|
static CRITICAL_SECTION keypair_lock;
|
||||||
|
static struct ac_io_panb_keypair _keypair[AC_IO_PANB_MAX_KEYPAIRS];
|
||||||
|
|
||||||
|
static CRITICAL_SECTION auto_poll_stop_lock;
|
||||||
|
static bool auto_poll_stop;
|
||||||
|
|
||||||
|
static int auto_poll_proc(void * param)
|
||||||
|
{
|
||||||
|
struct aciodrv_device_ctx * device = (struct aciodrv_device_ctx *) param;
|
||||||
|
struct ac_io_panb_poll_in poll_in;
|
||||||
|
bool stop;
|
||||||
|
|
||||||
|
do {
|
||||||
|
aciodrv_panb_recv_poll(device, &poll_in);
|
||||||
|
|
||||||
|
EnterCriticalSection(&keypair_lock);
|
||||||
|
memcpy(_keypair, poll_in.keypair, AC_IO_PANB_MAX_KEYPAIRS);
|
||||||
|
LeaveCriticalSection(&keypair_lock);
|
||||||
|
|
||||||
|
EnterCriticalSection(&auto_poll_stop_lock);
|
||||||
|
stop = auto_poll_stop;
|
||||||
|
LeaveCriticalSection(&auto_poll_stop_lock);
|
||||||
|
} while (!stop);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device)
|
||||||
|
{
|
||||||
|
log_assert(device);
|
||||||
|
|
||||||
|
if (!aciodrv_panb_start_auto_input(device, 0, AC_IO_PANB_NUM_NODES)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto_poll_stop = false;
|
||||||
|
InitializeCriticalSection(&keypair_lock);
|
||||||
|
InitializeCriticalSection(&auto_poll_stop_lock);
|
||||||
|
auto_poll_threadid = thread_create(auto_poll_proc, (void *)device, 0x4000, 0);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aciodrv_proc_panb_get_state(uint8_t *button_state)
|
||||||
|
{
|
||||||
|
struct ac_io_panb_keypair keypair[AC_IO_PANB_MAX_KEYPAIRS];
|
||||||
|
|
||||||
|
EnterCriticalSection(&keypair_lock);
|
||||||
|
memcpy(keypair, _keypair, AC_IO_PANB_MAX_KEYPAIRS);
|
||||||
|
LeaveCriticalSection(&keypair_lock);
|
||||||
|
|
||||||
|
/* splice the keypairs into separate button values */
|
||||||
|
for (int i=0; i<AC_IO_PANB_MAX_KEYPAIRS; i++) {
|
||||||
|
uint8_t but1 = keypair[i].key1;
|
||||||
|
uint8_t but2 = keypair[i].key2;
|
||||||
|
button_state[2*i] = but1;
|
||||||
|
button_state[2*i+1] = but2;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void aciodrv_proc_panb_fini(struct aciodrv_device_ctx *device)
|
||||||
|
{
|
||||||
|
EnterCriticalSection(&auto_poll_stop_lock);
|
||||||
|
auto_poll_stop = true;
|
||||||
|
LeaveCriticalSection(&auto_poll_stop_lock);
|
||||||
|
|
||||||
|
thread_join(auto_poll_threadid, NULL);
|
||||||
|
thread_destroy(auto_poll_threadid);
|
||||||
|
|
||||||
|
DeleteCriticalSection(&keypair_lock);
|
||||||
|
DeleteCriticalSection(&auto_poll_stop_lock);
|
||||||
|
|
||||||
|
/* reset is the only way to disable the auto polling on device side */
|
||||||
|
aciodrv_device_reset(device);
|
||||||
|
}
|
32
src/main/aciodrv-proc/panb.h
Normal file
32
src/main/aciodrv-proc/panb.h
Normal file
@ -0,0 +1,32 @@
|
|||||||
|
#ifndef ACIODRV_PROC_PANB_H
|
||||||
|
#define ACIODRV_PROC_PANB_H
|
||||||
|
|
||||||
|
#include "aciodrv/panb.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Initialize a PANB device. This will take care of setting up the auto-poll and processing
|
||||||
|
* the poll messages in a separate thread (this is necessary as failing to process messages
|
||||||
|
* fast enough will cause the device to malfunction).
|
||||||
|
*
|
||||||
|
* @param device Context of opened device
|
||||||
|
* @return True if successful, false on error.
|
||||||
|
* @note This function spawns a thread. Caller must call aciodrv_proc_panb_fini to properly
|
||||||
|
* terminate.
|
||||||
|
*/
|
||||||
|
bool aciodrv_proc_panb_init(struct aciodrv_device_ctx *device);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve latest known button state from the PANB device.
|
||||||
|
*
|
||||||
|
* @param button_state 28 cell array to store button state
|
||||||
|
* (mandatory, upon calling the array contains values between 0 to 15 indicating the keys velocity).
|
||||||
|
* @return True on success, false on error.
|
||||||
|
*/
|
||||||
|
bool aciodrv_proc_panb_get_state(uint8_t *button_state);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Properly terminate the thread and reset the device (this is the only way to stop the auto polling).
|
||||||
|
*/
|
||||||
|
void aciodrv_proc_panb_fini(struct aciodrv_device_ctx *device);
|
||||||
|
|
||||||
|
#endif
|
@ -7,5 +7,6 @@ src_aciodrv := \
|
|||||||
h44b.c \
|
h44b.c \
|
||||||
icca.c \
|
icca.c \
|
||||||
kfca.c \
|
kfca.c \
|
||||||
|
panb.c \
|
||||||
port.c \
|
port.c \
|
||||||
|
|
||||||
|
@ -23,7 +23,7 @@ struct aciodrv_device_ctx {
|
|||||||
uint8_t node_count;
|
uint8_t node_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
static bool aciodrv_device_reset(struct aciodrv_device_ctx *device)
|
bool aciodrv_device_reset(struct aciodrv_device_ctx *device)
|
||||||
{
|
{
|
||||||
uint8_t reset_seq[525] = {0};
|
uint8_t reset_seq[525] = {0};
|
||||||
|
|
||||||
@ -109,7 +109,7 @@ static bool aciodrv_device_send(struct aciodrv_device_ctx *device, const uint8_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AC_IO_MSG_LOG
|
#ifdef AC_IO_MSG_LOG
|
||||||
aciodrv_device_log_buffer("Send (1)", device, buffer, length);
|
aciodrv_device_log_buffer(device, "Send (1)", buffer, length);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
send_buf[send_buf_pos++] = AC_IO_SOF;
|
send_buf[send_buf_pos++] = AC_IO_SOF;
|
||||||
@ -135,7 +135,7 @@ static bool aciodrv_device_send(struct aciodrv_device_ctx *device, const uint8_t
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AC_IO_MSG_LOG
|
#ifdef AC_IO_MSG_LOG
|
||||||
aciodrv_device_log_buffer("Send (2)", device, send_buf, send_buf_pos);
|
aciodrv_device_log_buffer(device, "Send (2)", send_buf, send_buf_pos);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (aciodrv_port_write(device->fd, send_buf, send_buf_pos) != send_buf_pos) {
|
if (aciodrv_port_write(device->fd, send_buf, send_buf_pos) != send_buf_pos) {
|
||||||
@ -209,7 +209,7 @@ static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *bu
|
|||||||
}
|
}
|
||||||
|
|
||||||
#ifdef AC_IO_MSG_LOG
|
#ifdef AC_IO_MSG_LOG
|
||||||
aciodrv_device_log_buffer("Recv (1)", device, recv_buf, recv_size);
|
aciodrv_device_log_buffer(device, "Recv (1)", recv_buf, recv_size);
|
||||||
log_warning("Expected %d got %d", max_resp_size - 6, recv_buf[4]);
|
log_warning("Expected %d got %d", max_resp_size - 6, recv_buf[4]);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
@ -226,7 +226,7 @@ static int aciodrv_device_receive(struct aciodrv_device_ctx *device, uint8_t *bu
|
|||||||
result_size = recv_size - 1;
|
result_size = recv_size - 1;
|
||||||
|
|
||||||
#ifdef AC_IO_MSG_LOG
|
#ifdef AC_IO_MSG_LOG
|
||||||
aciodrv_device_log_buffer("Recv (2)", device, buffer, result_size);
|
aciodrv_device_log_buffer(device, "Recv (2)", buffer, result_size);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
if (checksum != recv_buf[recv_size - 1]) {
|
if (checksum != recv_buf[recv_size - 1]) {
|
||||||
@ -402,7 +402,7 @@ const struct aciodrv_device_node_version *aciodrv_device_get_node_product_versio
|
|||||||
return &device->node_versions[node_id];
|
return &device->node_versions[node_id];
|
||||||
}
|
}
|
||||||
|
|
||||||
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
|
bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg)
|
||||||
{
|
{
|
||||||
msg->cmd.seq_no = device->msg_counter++;
|
msg->cmd.seq_no = device->msg_counter++;
|
||||||
int send_size = offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes;
|
int send_size = offsetof(struct ac_io_message, cmd.raw) + msg->cmd.nbytes;
|
||||||
@ -418,15 +418,31 @@ bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_messa
|
|||||||
if (aciodrv_device_send(device, (uint8_t *) msg, send_size) <= 0) {
|
if (aciodrv_device_send(device, (uint8_t *) msg, send_size) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
uint16_t req_code = msg->cmd.code;
|
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
|
||||||
|
{
|
||||||
#ifdef AC_IO_MSG_LOG
|
#ifdef AC_IO_MSG_LOG
|
||||||
log_info("[%p] Beginning recv: (%d b)", device->fd, max_resp_size);
|
log_info("[%p] Beginning recv: (%d b)", device->fd, max_resp_size);
|
||||||
#endif
|
#endif
|
||||||
if (aciodrv_device_receive(device, (uint8_t *) msg, max_resp_size) <= 0) {
|
if (aciodrv_device_receive(device, (uint8_t *) msg, max_resp_size) <= 0) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size)
|
||||||
|
{
|
||||||
|
if (!aciodrv_send(device, msg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t req_code = msg->cmd.code;
|
||||||
|
|
||||||
|
if (!aciodrv_recv(device, msg, max_resp_size)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (req_code != msg->cmd.code) {
|
if (req_code != msg->cmd.code) {
|
||||||
log_warning(
|
log_warning(
|
||||||
|
@ -74,6 +74,35 @@ const struct aciodrv_device_node_version *aciodrv_device_get_node_product_versio
|
|||||||
*/
|
*/
|
||||||
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
|
bool aciodrv_send_and_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send a message to the ACIO bus.
|
||||||
|
*
|
||||||
|
* @param device Context of opened device
|
||||||
|
* @param msg Msg to send to the bus.
|
||||||
|
* @return True on success, false on error.
|
||||||
|
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for commands which don't trigger a reply.
|
||||||
|
*/
|
||||||
|
bool aciodrv_send(struct aciodrv_device_ctx *device, struct ac_io_message *msg);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read a message from the ACIO bus.
|
||||||
|
*
|
||||||
|
* @param device Context of opened device
|
||||||
|
* @param msg Msg to send to the bus. Make sure that the buffer
|
||||||
|
* is big enough to receive the response.
|
||||||
|
* @return True on success, false on error.
|
||||||
|
* @note Prefer the use of aciodrv_send_and_recv when possible. This is for unsollicited incoming messages.
|
||||||
|
*/
|
||||||
|
bool aciodrv_recv(struct aciodrv_device_ctx *device, struct ac_io_message *msg, int max_resp_size);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reset an opened device.
|
||||||
|
*
|
||||||
|
* @param device Context of opened device
|
||||||
|
* @return Total num of nodes enumerated on the ACIO device.
|
||||||
|
*/
|
||||||
|
bool aciodrv_device_reset(struct aciodrv_device_ctx *device);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Close the previously opened ACIO device.
|
* Close the previously opened ACIO device.
|
||||||
*
|
*
|
||||||
|
80
src/main/aciodrv/panb.c
Normal file
80
src/main/aciodrv/panb.c
Normal file
@ -0,0 +1,80 @@
|
|||||||
|
#define LOG_MODULE "aciodrv-panb"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "aciodrv/device.h"
|
||||||
|
#include "aciodrv/panb.h"
|
||||||
|
|
||||||
|
#include "util/thread.h"
|
||||||
|
#include "util/log.h"
|
||||||
|
|
||||||
|
bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count)
|
||||||
|
{
|
||||||
|
log_assert(device);
|
||||||
|
struct ac_io_message msg;
|
||||||
|
|
||||||
|
/* only the first node is handling the commands */
|
||||||
|
if (node_id != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.addr = node_id + 1;
|
||||||
|
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_START_AUTO_INPUT);
|
||||||
|
msg.cmd.nbytes = 1;
|
||||||
|
msg.cmd.count = node_count;
|
||||||
|
|
||||||
|
if (!aciodrv_send(device, &msg)) {
|
||||||
|
log_warning("Starting auto input failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log_info("Started auto input for %d nodes", node_count);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in)
|
||||||
|
{
|
||||||
|
log_assert(device);
|
||||||
|
struct ac_io_message msg;
|
||||||
|
struct ac_io_panb_poll_in *poll_res = (struct ac_io_panb_poll_in *) &msg.cmd.raw;
|
||||||
|
|
||||||
|
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_POLL_REPLY);
|
||||||
|
msg.cmd.nbytes = sizeof(struct ac_io_panb_poll_in);
|
||||||
|
|
||||||
|
if (!aciodrv_recv(device,
|
||||||
|
&msg, offsetof(struct ac_io_message, cmd.raw) + msg.cmd.nbytes + 1)) {
|
||||||
|
log_warning("Getting state failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (poll_in != NULL){
|
||||||
|
memcpy(poll_in, poll_res, sizeof(struct ac_io_panb_poll_in));
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aciodrv_panb_send_lamp(struct aciodrv_device_ctx *device,
|
||||||
|
uint8_t node_id, struct ac_io_panb_poll_out *state)
|
||||||
|
{
|
||||||
|
log_assert(device);
|
||||||
|
struct ac_io_message msg;
|
||||||
|
|
||||||
|
/* only the first node is handling the commands */
|
||||||
|
if (node_id != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.addr = node_id + 1;
|
||||||
|
msg.cmd.code = ac_io_u16(AC_IO_CMD_PANB_SEND_LAMP);
|
||||||
|
msg.cmd.nbytes = 0x54;
|
||||||
|
memcpy(&msg.cmd.raw, state, sizeof(struct ac_io_panb_poll_out));
|
||||||
|
|
||||||
|
if (!aciodrv_send(device, &msg)) {
|
||||||
|
log_warning("Sending lamp state failed");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
56
src/main/aciodrv/panb.h
Normal file
56
src/main/aciodrv/panb.h
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
#ifndef ACIODRV_PANB_H
|
||||||
|
#define ACIODRV_PANB_H
|
||||||
|
|
||||||
|
#include "acio/panb.h"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Send the AC_IO_CMD_PANB_START_AUTO_INPUT command on a PANB device.
|
||||||
|
*
|
||||||
|
* @param device Context of opened device.
|
||||||
|
* @param node_id node_id Id of the node to query (0 based).
|
||||||
|
* @param node_count The number of nodes to poll.
|
||||||
|
* @return True if successful, false on error.
|
||||||
|
* @note node_id should be 0, PANB internally manages the other nodes.
|
||||||
|
* @note Upon calling, the device will stop replying to commands and just keep sending
|
||||||
|
* AC_IO_CMD_PANB_POLL_REPLY messages indefinitely. Failure to retrieve them fast enough
|
||||||
|
* will cause the device to malfunction. It is thus advised to make use of the aciodrv-proc
|
||||||
|
* module to spawn a thread that will handle these messages and provide an easy access to the
|
||||||
|
* latest input state.
|
||||||
|
* @note This module is supposed to be used in combination with the common
|
||||||
|
* device driver foundation.
|
||||||
|
* @see driver.h
|
||||||
|
*/
|
||||||
|
bool aciodrv_panb_start_auto_input(struct aciodrv_device_ctx *device, uint8_t node_id, uint8_t node_count);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieve a AC_IO_CMD_PANB_POLL_REPLY message from a PANB device. This assumes that there
|
||||||
|
* is such message incoming (ie. that start_auto_input has been called prior).
|
||||||
|
*
|
||||||
|
* @param device Context of opened device.
|
||||||
|
* @param poll_in Buffer to hold the received message, or NULL.
|
||||||
|
* @return True if successful, false on error.
|
||||||
|
* @note node_id should be 0, PANB internally manages the other nodes.
|
||||||
|
* @note Failure to retrieve the incoming messages fast enough will cause the device to malfunction.
|
||||||
|
* It is thus advised to make use of the aciodrv-proc module to spawn a thread that will handle these
|
||||||
|
* messages and provide an easy access to the latest input state.
|
||||||
|
* @note This module is supposed to be used in combination with the common
|
||||||
|
* device driver foundation.
|
||||||
|
* @see driver.h
|
||||||
|
*/
|
||||||
|
bool aciodrv_panb_recv_poll(struct aciodrv_device_ctx *device, struct ac_io_panb_poll_in *poll_in);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Light lamps on a PANB device.
|
||||||
|
*
|
||||||
|
* @param node_id Id of the node to query (0 based).
|
||||||
|
* @param state Pointer to a lamp state struct
|
||||||
|
* (mandatory).
|
||||||
|
* @return True on success, false on error.
|
||||||
|
* @note node_id should be 0, PANB internally manages the other nodes.
|
||||||
|
* @note This module is supposed to be used in combination with the common
|
||||||
|
* device driver foundation.
|
||||||
|
* @see driver.h
|
||||||
|
*/
|
||||||
|
bool aciodrv_panb_send_lamp(struct aciodrv_device_ctx *device, uint8_t node_id, struct ac_io_panb_poll_out *state);
|
||||||
|
|
||||||
|
#endif
|
@ -3,10 +3,12 @@ exes += aciotest
|
|||||||
libs_aciotest := \
|
libs_aciotest := \
|
||||||
bio2drv \
|
bio2drv \
|
||||||
aciodrv \
|
aciodrv \
|
||||||
|
aciodrv-proc \
|
||||||
util \
|
util \
|
||||||
|
|
||||||
src_aciotest := \
|
src_aciotest := \
|
||||||
icca.c \
|
icca.c \
|
||||||
kfca.c \
|
kfca.c \
|
||||||
bi2a-sdvx.c \
|
bi2a-sdvx.c \
|
||||||
|
panb.c \
|
||||||
main.c \
|
main.c \
|
||||||
|
@ -10,6 +10,7 @@
|
|||||||
#include "aciotest/handler.h"
|
#include "aciotest/handler.h"
|
||||||
#include "aciotest/icca.h"
|
#include "aciotest/icca.h"
|
||||||
#include "aciotest/kfca.h"
|
#include "aciotest/kfca.h"
|
||||||
|
#include "aciotest/panb.h"
|
||||||
|
|
||||||
#include "util/log.h"
|
#include "util/log.h"
|
||||||
|
|
||||||
@ -37,6 +38,13 @@ static bool aciotest_assign_handler(
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!memcmp(product, "PANB", 4)) {
|
||||||
|
handler->init = aciotest_panb_handler_init;
|
||||||
|
handler->update = aciotest_panb_handler_update;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
if (!memcmp(product, "BI2A", 4)) {
|
if (!memcmp(product, "BI2A", 4)) {
|
||||||
if (bi2a_mode == 0) {
|
if (bi2a_mode == 0) {
|
||||||
handler->init = aciotest_bi2a_sdvx_handler_init;
|
handler->init = aciotest_bi2a_sdvx_handler_init;
|
||||||
|
76
src/main/aciotest/panb.c
Normal file
76
src/main/aciotest/panb.c
Normal file
@ -0,0 +1,76 @@
|
|||||||
|
#include "aciotest/panb.h"
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include "aciodrv/panb.h"
|
||||||
|
#include "aciodrv-proc/panb.h"
|
||||||
|
|
||||||
|
struct panb_handler_ctx {
|
||||||
|
bool running;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool aciotest_panb_handler_init(struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx)
|
||||||
|
{
|
||||||
|
if (node_id != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
*ctx = malloc(sizeof(struct panb_handler_ctx));
|
||||||
|
struct panb_handler_ctx *panb_ctx = (struct panb_handler_ctx*)*ctx;
|
||||||
|
panb_ctx->running = true;
|
||||||
|
|
||||||
|
return aciodrv_proc_panb_init(device);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx)
|
||||||
|
{
|
||||||
|
uint8_t button[AC_IO_PANB_MAX_KEYS];
|
||||||
|
struct ac_io_panb_poll_out state;
|
||||||
|
struct panb_handler_ctx *panb_ctx = (struct panb_handler_ctx *) ctx;
|
||||||
|
|
||||||
|
if (node_id != 0) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!panb_ctx->running) {
|
||||||
|
printf(">>> PANB:\nDevice has been closed. Press Ctrl+C to exit.");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aciodrv_proc_panb_get_state(button)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(">>> PANB:\nPress first and last keys to close device\n");
|
||||||
|
|
||||||
|
for (int i=0; i<AC_IO_PANB_MAX_KEYS; i++) {
|
||||||
|
printf("%01X ", button[i]);
|
||||||
|
}
|
||||||
|
printf("\n");
|
||||||
|
|
||||||
|
/* I added a key combo to properly close the module.
|
||||||
|
* Leaving the PANB device in autopolling state without ever
|
||||||
|
* reading packets from the serial interface eventually
|
||||||
|
* makes it fall into a state where it doesn't send anything anymore
|
||||||
|
* and won't even respond to a reset, thus requiring a power cycle.
|
||||||
|
*/
|
||||||
|
if (button[0] && button[AC_IO_PANB_MAX_KEYS-1]) {
|
||||||
|
aciodrv_proc_panb_fini(device);
|
||||||
|
panb_ctx->running = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* light the panel */
|
||||||
|
for (int i=0; i<AC_IO_PANB_MAX_KEYS; i++) {
|
||||||
|
state.key[i].green = (button[i])? 0x7F : 0;
|
||||||
|
state.key[i].red = 0;
|
||||||
|
state.key[i].blue = (button[i])? 0x23 : 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!aciodrv_panb_send_lamp(device, node_id, &state)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
12
src/main/aciotest/panb.h
Normal file
12
src/main/aciotest/panb.h
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#ifndef ACIOTEST_PANB_H
|
||||||
|
#define ACIOTEST_PANB_H
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include "aciodrv/device.h"
|
||||||
|
|
||||||
|
bool aciotest_panb_handler_init(struct aciodrv_device_ctx *device, uint8_t node_id, void **ctx);
|
||||||
|
bool aciotest_panb_handler_update(struct aciodrv_device_ctx *device, uint8_t node_id, void *ctx);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in New Issue
Block a user