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.
90 lines
2.5 KiB
C
90 lines
2.5 KiB
C
#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);
|
|
} |