Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
95 changes: 95 additions & 0 deletions Controllers/AP2QMKController/AP2Controller.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*------------------------------------------------------*\
| AP2Controller.cpp |
| |
| Driver for QMK/Shine firmware for AnnePro2 keyboard |
| |
| Tomasz Fortuna 26/09/2021 |
| Sergey Gavrilov (DrZlo13) 06/06/2021 |
\*------------------------------------------------------*/

#include "AP2Controller.h"
#include <cstring>
#include <cassert>

AP2Controller::AP2Controller(hid_device* dev_handle, const char* path)
{
dev = dev_handle;
location = path;
}

AP2Controller::~AP2Controller()
{
hid_close(dev);
}

std::string AP2Controller::GetDeviceLocation()
{
return ("HID: " + location);
}

std::string AP2Controller::GetSerialString()
{
wchar_t serial_string[128];
int ret = hid_get_serial_number_string(dev, serial_string, 128);

if (ret != 0)
{
return("");
}

std::wstring return_wstring = serial_string;
std::string return_string(return_wstring.begin(), return_wstring.end());

return(return_string);
}

/* All possible shine commands. Check Shine/AP-QMK code for arguments */
enum {
/* Basic config */
CMD_LED_ON = 0x01,
CMD_LED_OFF = 0x02,

CMD_LED_SET_PROFILE = 0x03,
CMD_LED_NEXT_PROFILE = 0x04,
CMD_LED_PREV_PROFILE = 0x05,

CMD_LED_NEXT_INTENSITY = 0x06,
CMD_LED_NEXT_ANIMATION_SPEED = 0x07,

/* Masks */
/* Override a key color, eg. capslock */
CMD_LED_MASK_SET_KEY = 0x10,
/* Override all keys in a row with configurable colors */
CMD_LED_MASK_SET_ROW = 0x11,

/* Override all keys with single color (eg. foreground color) */
CMD_LED_MASK_SET_MONO = 0x12,

/* Reactive / status */
CMD_LED_GET_STATUS = 0x20,
CMD_LED_KEY_BLINK = 0x21,
CMD_LED_KEY_DOWN = 0x22,
CMD_LED_KEY_UP = 0x23, /* TODO */
CMD_LED_IAP = 0x24,
};

/* Raw HID Commands */
enum AP2RawHidCodes {
AP2_RAW_FORWARD_SHINE = 1,
};

void AP2Controller::SendDirect(unsigned char frame_count, unsigned char * frame_data)
{
/* This sends HID RAW command to forward message directly to shine */
unsigned char frame[65];
/*
* First byte is special and denotes message number or something like that.
* Non-zero values will get eaten under Windows. Zero values will be eaten under Linux.
*/
frame[0] = 0x00;
frame[1] = AP2_RAW_FORWARD_SHINE;
frame[2] = CMD_LED_MASK_SET_ROW;
assert(frame_count <= 65-3);
memcpy(frame + 3, frame_data, frame_count);
hid_write(dev, frame, frame_count + 3);
}
36 changes: 36 additions & 0 deletions Controllers/AP2QMKController/AP2Controller.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*-----------------------------------------*\
| AP2Controller.h |
| |
| Driver for AnnePro2 w/QMK keyboard |
| |
| Sergey Gavrilov (DrZlo13) 06/06/2021 |
\*-----------------------------------------*/

#pragma once
#include "RGBController.h"

#include <string>
#include <vector>
#include <hidapi/hidapi.h>

#pragma once

class AP2Controller
{
public:
AP2Controller(hid_device* dev_handle, const char* path);
~AP2Controller();

std::string GetDeviceLocation();
std::string GetSerialString();

void SendDirect
(
unsigned char frame_count,
unsigned char * frame_data
);

private:
hid_device* dev;
std::string location;
};
28 changes: 28 additions & 0 deletions Controllers/AP2QMKController/AP2ControllerDetect.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "Detector.h"
#include "AP2Controller.h"
#include "RGBController.h"
#include "RGBController_AP2.h"
#include <hidapi/hidapi.h>

#define AP2_VID 0x04D9
#define AP2_PID_1 0xA291 /* C18 */
#define AP2_PID_2 0xA290 /* C15 */

/******************************************************************************************\
* DetectAnnePro2Controllers *
* Tests the USB address to see if an AnnePro2 w/QMK firmware keyboard is there. *
\******************************************************************************************/
void DetectAP2Controllers(hid_device_info* info, const std::string&)
{
hid_device* dev = hid_open_path(info->path);
if (dev)
{
AP2Controller* controller = new AP2Controller(dev, info->path);
RGBController_AP2* rgb_controller = new RGBController_AP2(controller);
// Constructor sets the name
ResourceManager::get()->RegisterRGBController(rgb_controller);
}
}

REGISTER_HID_DETECTOR_I("Anne Pro 2 C18 QMK/Shine", DetectAP2Controllers, AP2_VID, AP2_PID_1, 1);
REGISTER_HID_DETECTOR_I("Anne Pro 2 C15 QMK/Shine", DetectAP2Controllers, AP2_VID, AP2_PID_2, 1);
232 changes: 232 additions & 0 deletions Controllers/AP2QMKController/RGBController_AP2.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,232 @@
/*-----------------------------------------*\
| RGBController_AnnePro2.cpp |
| |
| Generic RGB Interface for AnnePro2 w/QMK |
| |
| Sergey Gavrilov (DrZlo13) 06/06/2021 |
| Tomasz Fortuna 26/09/2021 (QMK protocol) |
\*-----------------------------------------*/

#include "RGBController_AP2.h"

using namespace std::chrono_literals;

#define NA 0xFFFFFFFF
#define LED_REAL_COUNT (5*14)
#define LED_COUNT (LED_REAL_COUNT - 9)

static unsigned int matrix_map[5][14] =
{ { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13 },
{ 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27 },
{ 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, NA },
{ 41, NA, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, NA },
{ 53, NA, 54, 55, NA, NA, 56, NA, NA, 57, 58, 59, 60, NA } };

static const char* zone_names[] =
{
"Keyboard",
};

static zone_type zone_types[] =
{
ZONE_TYPE_MATRIX
};

static const unsigned int zone_sizes[] =
{
LED_COUNT,
};

typedef struct
{
const char * name;
const unsigned char idx;
} led_type;

static const led_type led_names[] =
{
/* Key Label Index */
{ "Key: Escape", 0 },
{ "Key: 1", 1 },
{ "Key: 2", 2 },
{ "Key: 3", 3 },
{ "Key: 4", 4 },
{ "Key: 5", 5 },
{ "Key: 6", 6 },
{ "Key: 7", 7 },
{ "Key: 8", 8 },
{ "Key: 9", 9 },
{ "Key: 0", 10 },
{ "Key: -", 11 },
{ "Key: =", 12 },
{ "Key: Backspace", 13 },
{ "Key: Tab", 14 },
{ "Key: Q", 15 },
{ "Key: W", 16 },
{ "Key: E", 17 },
{ "Key: R", 18 },
{ "Key: T", 19 },
{ "Key: Y", 20 },
{ "Key: U", 21 },
{ "Key: I", 22 },
{ "Key: O", 23 },
{ "Key: P", 24 },
{ "Key: [", 25 },
{ "Key: ]", 26 },
{ "Key: \\ (ANSI)", 27 },
{ "Key: Caps Lock", 28 },
{ "Key: A", 29 },
{ "Key: S", 30 },
{ "Key: D", 31 },
{ "Key: F", 32 },
{ "Key: G", 33 },
{ "Key: H", 34 },
{ "Key: J", 35 },
{ "Key: K", 36 },
{ "Key: L", 37 },
{ "Key: ;", 38 },
{ "Key: '", 39 },
{ "Key: Enter", 40 },
{ "Key: Left Shift", 41 },
{ "Key: Z", 42 },
{ "Key: X", 43 },
{ "Key: C", 44 },
{ "Key: V", 45 },
{ "Key: B", 46 },
{ "Key: N", 47 },
{ "Key: M", 48 },
{ "Key: ,", 49 },
{ "Key: .", 50 },
{ "Key: /", 51 },
{ "Key: Right Shift", 52 },
{ "Key: Left Control", 53 },
{ "Key: Left Windows", 54 },
{ "Key: Left Alt", 55 },
{ "Key: Space", 56 },
{ "Key: Right Alt", 57 },
{ "Key: Right Fn", 58 },
{ "Key: Menu", 59 },
{ "Key: Right Control", 60 },
};

RGBController_AP2::RGBController_AP2(AP2Controller* annepro2_ptr)
{
annepro2 = annepro2_ptr;

name = "Anne Pro 2 QMK/Shine";
vendor = "Obinslab";
type = DEVICE_TYPE_KEYBOARD;
description = "Obinslab Anne Pro 2 Device with QMK firmware";
location = annepro2->GetDeviceLocation();
serial = annepro2->GetSerialString();

mode Direct;
Direct.name = "Direct";
Direct.value = 0;
Direct.flags = MODE_FLAG_HAS_PER_LED_COLOR;
Direct.color_mode = MODE_COLORS_PER_LED;
modes.push_back(Direct);

SetupZones();
}

RGBController_AP2::~RGBController_AP2()
{
delete annepro2;
}

void RGBController_AP2::SetupZones()
{
/*---------------------------------------------------------*\
| Set up zones |
\*---------------------------------------------------------*/
unsigned int total_led_count = 0;
for(unsigned int zone_idx = 0; zone_idx < 1; zone_idx++)
{
zone new_zone;
new_zone.name = zone_names[zone_idx];
new_zone.type = zone_types[zone_idx];
new_zone.leds_min = zone_sizes[zone_idx];
new_zone.leds_max = zone_sizes[zone_idx];
new_zone.leds_count = zone_sizes[zone_idx];

if(zone_types[zone_idx] == ZONE_TYPE_MATRIX)
{
new_zone.matrix_map = new matrix_map_type;
new_zone.matrix_map->height = 5;
new_zone.matrix_map->width = 14;
new_zone.matrix_map->map = (unsigned int *)&matrix_map;
}
else
{
new_zone.matrix_map = NULL;
}

zones.push_back(new_zone);

total_led_count += zone_sizes[zone_idx];
}

for(unsigned int led_idx = 0; led_idx < total_led_count; led_idx++)
{
led new_led;
new_led.name = led_names[led_idx].name;
new_led.value = led_names[led_idx].idx;
leds.push_back(new_led);
}

SetupColors();
}

void RGBController_AP2::ResizeZone(int /*zone*/, int /*new_size*/)
{
/*---------------------------------------------------------*\
| This device does not support resizing zones |
\*---------------------------------------------------------*/
}

void RGBController_AP2::DeviceUpdateLEDs()
{
unsigned char frame_buf[64];

/* Send rows separately */
for (int row=0; row < 5; row++) {
frame_buf[0] = row;
/* NOTE: That's very not optimal, but easy for firmware, handles all
* colors and works. Using a 256-color palette one could update whole
* keyboard with a single RAW HID. */
for (int col=0; col < 14; col++) {
const unsigned int led_idx = matrix_map[row][col];
if (led_idx == NA)
continue;
frame_buf[1 + col * 4 + 0] = RGBGetBValue(colors[led_idx]);
frame_buf[1 + col * 4 + 1] = RGBGetGValue(colors[led_idx]);
frame_buf[1 + col * 4 + 2] = RGBGetRValue(colors[led_idx]);
frame_buf[1 + col * 4 + 3] = 0xff;
}
annepro2->SendDirect(4 * 14 + 1, frame_buf);

/* Minimal processing time; without it, later frames get destroyed */
std::this_thread::sleep_for(5ms);
}
}

void RGBController_AP2::UpdateZoneLEDs(int /*zone*/)
{
DeviceUpdateLEDs();
}

void RGBController_AP2::UpdateSingleLED(int /*led*/)
{
DeviceUpdateLEDs();
}

void RGBController_AP2::SetCustomMode()
{
active_mode = 0;
}

void RGBController_AP2::DeviceUpdateMode()
{

}
Loading