掌機 - Anbernic RG351P - 修正STM32F103手柄吞鍵問題



參考資料:
https://github.com/OpenSimHardware/PedalButtonController
https://opensimhardware.wordpress.com/pedal-button-controller/

main.c

#include <linux/types.h>
#include <linux/input.h>
#include <linux/hidraw.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdint.h>
#include <errno.h>
#include <time.h>
#include <sys/time.h>
#include <SDL.h>
#include <SDL_ttf.h>
#include <SDL_image.h>

#ifndef PC
    #include "hex_font.h"
#endif
#include "hex_splash.h"

TTF_Font *font = NULL;
SDL_Surface *real = NULL;
SDL_Surface *screen = NULL;
SDL_Surface *splash = NULL;

uint8_t mycfg[] = {    
    0x04, 0x01, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x0f, 
    0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 
    0x03, 0x03, 0x03, 0x03, 0x03, 0x03, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x16, 0x16, 0x16, 
    0x00, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x16, 0x00, 0x00, 0x00, 
    0x04, 0x02, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x01, 0x00, 0x00, 0x00, 0xff, 0x0f, 0x00, 0x00, 
    0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x32, 0x04, 0x05, 
    0x04, 0x03, 0x10, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x00, 0x2f, 
    0x78, 0xf9, 0x8c, 0x00, 0x01, 0x7f, 0x00, 0x00, 0x2d, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x01, 
    0x7f, 0x38, 0xd8, 0xf4, 0x58, 0xf9, 0x74, 0x00, 0xb2, 0x15, 0x01, 0x7f, 0x00, 0x00, 0x00, 0x01, 
    0x50, 0xf9, 0x74, 0x00, 0x00, 0x01, 0x7f, 0x00, 0x69, 0x00, 0x2d, 0x00, 0x6d, 0x00, 0x73, 0x00, 
    0x04, 0x04, 0x00, 0x01, 0x7f, 0x00, 0x6e, 0x00, 0x2d, 0x00, 0x73, 0x00, 0x68, 0x00, 0x01, 0x7f, 
    0x6f, 0x00, 0x72, 0x00, 0x65, 0x00, 0x2d, 0x00, 0x6f, 0x01, 0x7f, 0x00, 0x73, 0x00, 0x6f, 0x00, 
    0x6c, 0x00, 0x65, 0x00, 0x01, 0x7f, 0x65, 0x00, 0x2d, 0x00, 0x6c, 0x00, 0x31, 0x00, 0x2d, 0x01, 
    0x7f, 0x00, 0x2d, 0x00, 0x30, 0x00, 0x2e, 0x00, 0x64, 0x00, 0x6c, 0x00, 0x6c, 0x00, 0x00, 0x00, 
    0x04, 0x05, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 
    0xe8, 0xe8, 0xee, 0xed, 0xec, 0xeb, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 
    0xe8, 0xe8, 0x74, 0x00, 0x00, 0x00, 0x8c, 0x00, 0x40, 0xcd, 0x8b, 0x77, 0xd0, 0x38, 0x8d, 0x00, 
    0x00, 0x00, 0x00, 0x00, 0x1f, 0xd2, 0x8b, 0x77, 0xed, 0x3a, 0xd8, 0xf4, 0x00, 0x00, 0x8c, 0x00, 
    0x04, 0x06, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 
    0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 0xe8, 
    0xe8, 0xe8, 0xff, 0xff, 0x30, 0xfa, 0x74, 0x00, 0x2b, 0x17, 0x8b, 0x77, 0x01, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0xa9, 0x75, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0xfa, 0x74, 0x00, 
    0x04, 0x07, 0x00, 0x00, 0xd0, 0x01, 0xa0, 0x03, 0x50, 0x05, 0x20, 0x07, 0xc0, 0x08, 0xa0, 0x0a, 
    0x40, 0x0c, 0x40, 0x0e, 0xff, 0x0f, 0x00, 0x00, 0x80, 0x05, 0xc0, 0x09, 0x40, 0x0c, 0x10, 0x0e, 
    0x10, 0x0f, 0x80, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 
    0x00, 0x00, 0x60, 0x00, 0x30, 0x01, 0x70, 0x02, 0x40, 0x04, 0x60, 0x08, 0xff, 0x0f, 0xb0, 0x75, 
    0x04, 0x08, 0x00, 0x00, 0x00, 0x00, 0x60, 0x00, 0xa0, 0x01, 0xb0, 0x04, 0x70, 0x0b, 0x40, 0x0e, 
    0xb0, 0x0f, 0xff, 0x0f, 0xff, 0x0f, 0x00, 0x00, 0x40, 0x04, 0x50, 0x06, 0x80, 0x07, 0xc0, 0x07, 
    0xf0, 0x07, 0x60, 0x08, 0x60, 0x09, 0xd0, 0x0b, 0xff, 0x0f, 0xff, 0x0f, 0x40, 0x0e, 0x40, 0x0c, 
    0xa0, 0x0a, 0xc0, 0x08, 0x20, 0x07, 0x50, 0x05, 0xa0, 0x03, 0xd0, 0x01, 0x00, 0x00, 0x00, 0x00, 
    0x04, 0x09, 0x4c, 0x69, 0x6e, 0x65, 0x61, 0x72, 0x00, 0x00, 0x00, 0x00, 0x45, 0x78, 0x70, 0x6f, 
    0x6e, 0x65, 0x6e, 0x74, 0x31, 0x00, 0x45, 0x78, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x32, 0x00, 
    0x53, 0x68, 0x61, 0x70, 0x65, 0x31, 0x00, 0x00, 0x00, 0x00, 0x53, 0x68, 0x61, 0x70, 0x65, 0x32, 
    0x00, 0x00, 0x00, 0x00, 0x49, 0x6e, 0x76, 0x65, 0x72, 0x74, 0x65, 0x64, 0x00, 0x00, 0x00, 0x00, 
};

int upgrade(void)
{
    char buf[255] = { 0 };
    struct hidraw_devinfo info = { 0 };
    struct hidraw_report_descriptor rpt_desc = { 0 };
    int fd = -1, x = 0, r = 0, desc_size = 0, err_cnt = 0;

    fd = open("/dev/hidraw0", O_RDWR | O_NONBLOCK);
    if (fd < 0) {
        printf("failed to open device\n");
        return -1;
    }

    ioctl(fd, HIDIOCGRDESCSIZE, &desc_size);
    rpt_desc.size = desc_size;
    ioctl(fd, HIDIOCGRDESC, &rpt_desc);
    ioctl(fd, HIDIOCGRAWNAME(sizeof(buf)), buf);
    if (strcmp(buf, "OpenSimHardware OSH PB Controller") != 0) {
        printf("failed to open rg351p device\n");
        close(fd);
        return -1;
    }
    ioctl(fd, HIDIOCGRAWPHYS(sizeof(buf)), buf);
    ioctl(fd, HIDIOCGRAWINFO, &info);

    buf[0] = 0x9;
    buf[1] = 0xff;
    buf[2] = 0xff;
    buf[3] = 0xff;
    ioctl(fd, HIDIOCSFEATURE(4), buf);

    buf[0] = 0x9;
    ioctl(fd, HIDIOCGFEATURE(sizeof(buf)), buf);

    err_cnt = 0;
    for (x = 0; x < 9; x++) {
        mycfg[64 * x] = 2;
        r = write(fd, &mycfg[64 * x], 64);
        if (r < 0) {
            err_cnt += 1;
        }
        printf("wrote: %d\n", r);
        usleep(100000);
    }
    close(fd);
    return err_cnt;
}

void flip_screen(void)
{
    int x = 0, y = 0;
    uint16_t *s = screen->pixels;
    uint16_t *d = real->pixels;

    for (y = 0; y < 320; y++) {
        for (x = 0; x < 480; x++) {
            d[y + ((480 - x) * 320)] = s[x + (y * 480)];
        }
    }
    SDL_Flip(real);
}

void text(char *msg, uint8_t r, uint8_t g, uint8_t b)
{
    int w, h;
    SDL_Rect rt = { 0 };
    SDL_Surface *t = NULL;
    SDL_Color col = { r, g, b };

    t = TTF_RenderUTF8_Blended(font, msg, col);
    if (t) {
        TTF_SizeUTF8(font, msg, &w, &h);
        rt.x = (480 - w) / 2;
        rt.y = 260;
        SDL_BlitSurface(splash, NULL, screen, NULL);
        SDL_BlitSurface(t, NULL, screen, &rt);
        SDL_FreeSurface(t);
    }
    flip_screen();
}

int main(int argc, char **argv)
{
    int ok = 0;
    SDL_Surface *t = NULL;

    if (SDL_Init(SDL_INIT_VIDEO) != 0) { 
        printf("failed to init sdl\n");
        return -1;
    }
    real = SDL_SetVideoMode(320, 480, 16, SDL_HWSURFACE);
    if (real == NULL) {
        printf("failed to set video mode\n");
        return -1;
    }
    SDL_ShowCursor(SDL_FALSE);
    if (TTF_Init() == -1) {
        printf("failed to init ttf\n");
        return -1;
    }
#ifndef PC
    font = TTF_OpenFontRW(SDL_RWFromMem(hex_font, sizeof(hex_font)), 1, 38);
#else
    font = TTF_OpenFont("font.ttf", 38);
#endif
    screen = SDL_CreateRGBSurface(SDL_SWSURFACE, 480, 320, 16, 0, 0, 0, 0);
    SDL_FillRect(real, &real->clip_rect, SDL_MapRGB(real->format, 0, 0, 0));
    
    SDL_RWops *rw = NULL;
    rw = SDL_RWFromMem(hex_splash, sizeof(hex_splash)); t = IMG_Load_RW(rw, 1);
    splash = SDL_ConvertSurface(t, real->format, 0); SDL_FreeSurface(t);

    text("手柄固件更新中...", 0x00, 0x00, 0xa0);
    ok = upgrade();
    SDL_Delay(1000);

    if (ok < 0) {
        text("更新失败, 系统关机中...", 0xa0, 0x00, 0x00);
    }
    else {
        text("更新完成, 系统关机中...", 0x00, 0xa0, 0x00);
    }
    SDL_Delay(1500);

    TTF_Quit();
    SDL_FreeSurface(splash);
    SDL_Quit();

#ifndef PC
    system("poweroff");
#endif
    return 0;
}