main.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <termios.h>
#include <errno.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <linux/input.h>
#include <stdint.h>
int uart_open(const char *port)
{
int fd;
fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
if (-1 == fd)
{
perror("Can't Open Serial Port");
return -1;
}
if (fcntl(fd, F_SETFL, 0) < 0)
{
printf("fcntl failed!\n");
return -1;
}
printf("serial open=%d\n", fd);
return fd;
}
void uart_close(int fd)
{
close(fd);
}
int uart_set(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity)
{
int i;
int speed_arr[] = {B115200, B19200, B9600, B4800, B2400, B1200, B300};
int name_arr[] = {115200, 19200, 9600, 4800, 2400, 1200, 300};
struct termios options;
if (tcgetattr(fd, &options) != 0)
{
perror("SetupSerial 1");
return -1;
}
for (i = 0; i < sizeof(speed_arr) / sizeof(int); i++)
{
if (speed == name_arr[i])
{
cfsetispeed(&options, speed_arr[i]);
cfsetospeed(&options, speed_arr[i]);
}
}
options.c_cflag |= CLOCAL;
options.c_cflag |= CREAD;
switch (flow_ctrl)
{
case 0:
options.c_cflag &= ~CRTSCTS;
break;
case 1:
options.c_cflag |= CRTSCTS;
break;
case 2:
options.c_cflag |= IXON | IXOFF | IXANY;
break;
}
options.c_cflag &= ~CSIZE;
switch (databits)
{
case 5:
options.c_cflag |= CS5;
break;
case 6:
options.c_cflag |= CS6;
break;
case 7:
options.c_cflag |= CS7;
break;
case 8:
options.c_cflag |= CS8;
break;
default:
fprintf(stderr, "Unsupported data size\n");
return -1;
}
switch (parity)
{
case 'n':
case 'N':
options.c_cflag &= ~PARENB;
options.c_iflag &= ~INPCK;
break;
case 'o':
case 'O':
options.c_cflag |= (PARODD | PARENB);
options.c_iflag |= INPCK;
break;
case 'e':
case 'E':
options.c_cflag |= PARENB;
options.c_cflag &= ~PARODD;
options.c_iflag |= INPCK;
break;
case 's':
case 'S':
options.c_cflag &= ~PARENB;
options.c_cflag &= ~CSTOPB;
break;
default:
fprintf(stderr, "Unsupported parity\n");
return -1;
}
switch (stopbits)
{
case 1:
options.c_cflag &= ~CSTOPB;
break;
case 2:
options.c_cflag |= CSTOPB;
break;
default:
fprintf(stderr, "Unsupported stop bits\n");
return -1;
}
options.c_oflag &= ~OPOST;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
// 0x0D 0x0A
options.c_iflag &= ~(INLCR | ICRNL | IGNCR);
options.c_oflag &= ~(ONLCR | OCRNL);
options.c_cc[VTIME] = 1;
options.c_cc[VMIN] = 1;
tcflush(fd, TCIFLUSH);
if (tcsetattr(fd, TCSANOW, &options) != 0)
{
perror("com set error!\n");
return -1;
}
return 0;
}
int uart_init(int fd, int speed, int flow_ctrl, int databits, int stopbits, int parity)
{
if (uart_set(fd, speed, flow_ctrl, databits, stopbits, parity) == -1)
{
return -1;
}
else
{
return 0;
}
}
int uart_read(int fd, char *rcv_buf, int data_len)
{
int len, fs_sel;
fd_set fs_read;
struct timeval time;
FD_ZERO(&fs_read);
FD_SET(fd, &fs_read);
time.tv_sec = 10;
time.tv_usec = 0;
fs_sel = select(fd + 1, &fs_read, NULL, NULL, &time);
// printf("fs_sel = %d\n",fs_sel);
if (fs_sel)
{
len = read(fd, rcv_buf, data_len);
return len;
}
else
{
return 0;
}
}
// int uart_write(int fd, char *send_buf, int data_len)
// {
// int len = 0;
// len = write(fd, send_buf, data_len);
// if (len == data_len)
// {
// printf("send data: %s\n", send_buf);
// return len;
// }
// else
// {
// tcflush(fd, TCOFLUSH);
// return -1;
// }
// }
void dump_cmd_frame(const char *buf, int len)
{
int i;
// printf("dump_cmd_frame: \n");
for (i = 0; i < len; i++)
{
printf(" %02X", buf[i] & 0xFF);
}
printf("\n");
}
// MIYOO 282
#define MIYOO_AXIS_MAX_COUNT 16
#define MIYOO_PLAYER_MAGIC 0xFF
#define MIYOO_PLAYER_MAGIC_END 0xFE
#if 0
struct MIYOO_PAD_FRAME
{
uint8_t magic;
uint8_t axis0;
uint8_t axis1;
uint8_t magicEnd;
};
#define MIYOO_PAD_FRAME_LEN 4 // sizeof(struct MIYOO_PAD_FRAME) =12 ????? why
#else
struct MIYOO_PAD_FRAME
{
uint8_t magic;
uint8_t unused0;
uint8_t unused1;
uint8_t axis0;
uint8_t axis1;
uint8_t magicEnd;
};
#define MIYOO_PAD_FRAME_LEN 6 // sizeof(struct MIYOO_PAD_FRAME) =12 ????? why
#endif
static struct MIYOO_PAD_FRAME s_frame;
// static struct MIYOO_PAD_FRAME s_frame_last;
// static uint32_t s_pkio;
// static uint32_t s_pkio_last;
static int32_t s_miyoo_axis[MIYOO_AXIS_MAX_COUNT];
static int32_t s_miyoo_axis_last[MIYOO_AXIS_MAX_COUNT];
// static int key_pressed(int key)
// {
// if (s_pkio & (1 << key) && !(s_pkio_last & (1 << key)))
// return 1;
// return 0;
// }
// static int key_released(int key)
// {
// if (!(s_pkio & (1 << key)) && s_pkio_last & (1 << key))
// return 1;
// return 0;
// }
// static void check_key_event()
// {
// int i;
// for (i = 0; i < MIYOO_IO_MAX; i++)
// {
// if (key_pressed(i))
// {
// printf("pressed %s\n", s_btn_label[i]);
// miyoo_report_key(EV_KEY, g_miyoo_key_event[i], 1);
// }
// if (key_released(i))
// {
// printf("released %s\n", s_btn_label[i]);
// miyoo_report_key(EV_KEY, g_miyoo_key_event[i], 0);
// }
// }
// }
#if 0
#define MIYOO_ADC_MAX_X (200)
#define MIYOO_ADC_ZERO_X (137)
#define MIYOO_ADC_MIN_X (76)
#define MIYOO_ADC_MAX_Y (200)
#define MIYOO_ADC_ZERO_Y (135)
#define MIYOO_ADC_MIN_Y (72)
#define MIYOO_ADC_DEAD_ZONE (10)
#define MIYOO_AXIS_INT8_DRIFT (5)
#else
static int MIYOO_ADC_MAX_X = 200;
static int MIYOO_ADC_ZERO_X = 137;
static int MIYOO_ADC_MIN_X = 76;
static int MIYOO_ADC_MAX_Y = 200;
static int MIYOO_ADC_ZERO_Y = 135;
static int MIYOO_ADC_MIN_Y = 72;
static int MIYOO_ADC_DEAD_ZONE = 10;
static int MIYOO_AXIS_INT8_DRIFT = 5;
#define JOYPAD_CONFIG_FILE "/config/joypad.config"
static int getKeyValueDefault(const char *str, const char *key, int defaultValue)
{
int index;
char buf[16];
const char *p = strstr(str, key);
if (!p)
return defaultValue;
p = strchr(p, '=');
if (!p)
return defaultValue;
memset(buf, 0, sizeof(buf));
memcpy(buf, p + 1, 3);
index = defaultValue;
sscanf(buf, "%d", &index);
return index;
}
int fileToMem(const char *path, void *data)
{
int len, fileLen;
FILE *fp = fopen(path, "r");
if (!fp)
{
// printf("can not open %s\n", path);
return 0;
}
fseek(fp, 0, SEEK_END);
fileLen = ftell(fp);
// printf("file %s len=%d\n", path, fileLen);
fseek(fp, 0, SEEK_SET);
len = fread(data, 1, fileLen, fp);
fclose(fp);
return len;
}
static void defaule_cal_config()
{
printf("defaule_cal_config\n");
MIYOO_ADC_MAX_X = 200;
MIYOO_ADC_ZERO_X = 137;
MIYOO_ADC_MIN_X = 76;
MIYOO_ADC_MAX_Y = 200;
MIYOO_ADC_ZERO_Y = 135;
MIYOO_ADC_MIN_Y = 72;
}
static void miyoo_read_cal_config()
{
char configBuf[4096];
memset(configBuf, 0, sizeof(configBuf));
fileToMem(JOYPAD_CONFIG_FILE, configBuf);
// static int MIYOO_ADC_MAX_X = 200;
// static int MIYOO_ADC_ZERO_X = 137;
// static int MIYOO_ADC_MIN_X = 76;
// static int MIYOO_ADC_MAX_Y = 200;
// static int MIYOO_ADC_ZERO_Y = 135;
// static int MIYOO_ADC_MIN_Y = 72;
// x_min=83
// x_max=195
// y_min=74
// y_max=226
// x_zero=134
// y_zero=148
MIYOO_ADC_MIN_X = getKeyValueDefault(configBuf, "x_min", 76);
MIYOO_ADC_MAX_X = getKeyValueDefault(configBuf, "x_max", 200);
MIYOO_ADC_MIN_Y = getKeyValueDefault(configBuf, "y_min", 72);
MIYOO_ADC_MAX_Y = getKeyValueDefault(configBuf, "y_max", 200);
MIYOO_ADC_ZERO_X = getKeyValueDefault(configBuf, "x_zero", 137);
MIYOO_ADC_ZERO_Y = getKeyValueDefault(configBuf, "y_zero", 135);
if (MIYOO_ADC_MAX_X == MIYOO_ADC_ZERO_X || MIYOO_ADC_MIN_X == MIYOO_ADC_ZERO_X)
defaule_cal_config();
if (MIYOO_ADC_MAX_Y == MIYOO_ADC_ZERO_Y || MIYOO_ADC_MIN_Y == MIYOO_ADC_ZERO_Y)
defaule_cal_config();
printf("joystick read cal: [%d %d %d] [%d %d %d]\n",
MIYOO_ADC_MIN_X,
MIYOO_ADC_ZERO_X,
MIYOO_ADC_MAX_X,
MIYOO_ADC_MIN_Y,
MIYOO_ADC_ZERO_Y,
MIYOO_ADC_MAX_Y);
}
#endif
static int filterDeadzone(int newAxis, int oldAxis)
{
// miyoo- 20220823 disable deadzone drift filter, already in MCU.
#if 0
if(newAxis > MIYOO_ADC_DEAD_ZONE || newAxis < -MIYOO_ADC_DEAD_ZONE
|| oldAxis > MIYOO_ADC_DEAD_ZONE || oldAxis < -MIYOO_ADC_DEAD_ZONE )
return 0;
if(abs(newAxis - oldAxis) < MIYOO_AXIS_INT8_DRIFT)
return 1;
#endif
return 0;
}
static int limitValue8(int value)
{
if (value > 127)
value = 127;
else if (value < -128)
value = -128;
return value;
}
int g_lastX = 0;
int g_lastY = 0;
static void check_axis_event()
{
int i;
for (i = 0; i < MIYOO_AXIS_MAX_COUNT; i++)
{
if (s_miyoo_axis[i] != s_miyoo_axis_last[i])
{
if (!filterDeadzone(s_miyoo_axis[i], s_miyoo_axis_last[i]))
{
if (i == 0)
{
g_lastX = limitValue8(s_miyoo_axis[i]);
// miyoo_report_abs(EV_ABS, ABS_X, g_lastX);
}
else if (i == 1)
{
g_lastY = limitValue8(s_miyoo_axis[i]);
// miyoo_report_abs(EV_ABS, ABS_Y, g_lastY);
}
// printf("[raw ]\t%d \t %d\n", s_frame.axis0, s_frame.axis1);
// printf("[asix]\t%d \t %d\n", g_lastX, g_lastY);
}
}
s_miyoo_axis_last[i] = s_miyoo_axis[i];
}
}
int miyoo_frame_to_axis_x(uint8_t rawX)
{
int value = 0;
if (rawX > MIYOO_ADC_ZERO_X)
value = (rawX - MIYOO_ADC_ZERO_X) * 126 / (MIYOO_ADC_MAX_X - MIYOO_ADC_ZERO_X);
if (rawX < MIYOO_ADC_ZERO_X)
value = (rawX - MIYOO_ADC_ZERO_X) * 126 / (MIYOO_ADC_ZERO_X - MIYOO_ADC_MIN_X);
if (value > 0 && value < MIYOO_ADC_DEAD_ZONE)
return 0;
if (value < 0 && value > -(MIYOO_ADC_DEAD_ZONE))
return 0;
return value;
}
int miyoo_frame_to_axis_y(uint8_t rawY)
{
int value = 0;
if (rawY > MIYOO_ADC_ZERO_Y)
value = (rawY - MIYOO_ADC_ZERO_Y) * 126 / (MIYOO_ADC_MAX_Y - MIYOO_ADC_ZERO_Y);
if (rawY < MIYOO_ADC_ZERO_Y)
value = (rawY - MIYOO_ADC_ZERO_Y) * 126 / (MIYOO_ADC_ZERO_Y - MIYOO_ADC_MIN_Y);
if (value > 0 && value < MIYOO_ADC_DEAD_ZONE)
return 0;
if (value < 0 && value > -(MIYOO_ADC_DEAD_ZONE))
return 0;
return value;
}
static void parser_miyoo_input(const char *cmd, int len)
{
int i, p;
// printf("len=%d, size=%d\n", len, sizeof(s_frame));
if (!cmd || len < MIYOO_PAD_FRAME_LEN)
return;
for (i = 0; i < len - MIYOO_PAD_FRAME_LEN + 1; i += MIYOO_PAD_FRAME_LEN)
{
for (p = 0; p < MIYOO_PAD_FRAME_LEN - 1; p++)
{
if ((cmd[i] == MIYOO_PLAYER_MAGIC) && (cmd[i + MIYOO_PAD_FRAME_LEN - 1] == MIYOO_PLAYER_MAGIC_END))
{
memcpy(&s_frame, cmd + i, sizeof(s_frame));
break;
}
else
i++;
}
}
s_miyoo_axis[ABS_X] = miyoo_frame_to_axis_x(s_frame.axis0);
s_miyoo_axis[ABS_Y] = miyoo_frame_to_axis_y(s_frame.axis1);
check_axis_event();
}
#define SERIAL_GAMEDECK ("/dev/ttyS0")
static pthread_t ntid;
static volatile int s_serial_run = 0;
static int s_fd = -1;
void *thread_serial_gamedeck(void *arg)
{
int len;
int i;
char rcv_buf[100];
printf("thread serial joystick\n");
while (s_serial_run)
{
len = uart_read(s_fd, rcv_buf, 99);
if (len > 0)
{
rcv_buf[len] = '\0';
// dump_cmd_frame(rcv_buf, len);
// parser_miyoo_input(rcv_buf, len);
parser_miyoo_input(rcv_buf, len);
}
else
{
printf("cannot receive data\n");
}
usleep(14);
// sleep(2);
}
uart_close(s_fd);
s_fd = -1;
}
int miyoo_init_serial_input()
{
int err;
miyoo_read_cal_config();
// miyoo_create_ukey();
memset(&s_frame, 0, sizeof(s_frame));
// memset(&s_frame_last, 0, sizeof(s_frame_last));
memset(s_miyoo_axis, 0, sizeof(s_miyoo_axis));
memset(s_miyoo_axis_last, 0, sizeof(s_miyoo_axis_last));
s_fd = uart_open(SERIAL_GAMEDECK);
err = uart_init(s_fd, 9600, 0, 8, 1, 'N');
if (s_fd <= 0)
{
printf("open %s error.\n", SERIAL_GAMEDECK);
return -1;
}
s_serial_run = 1;
err = pthread_create(&ntid, NULL, thread_serial_gamedeck, NULL);
return 0;
}
void miyoo_close_serial_input()
{
s_serial_run = 0;
}