Skip to content

Commit

Permalink
Merge pull request #27 from ganhailin/main
Browse files Browse the repository at this point in the history
修正macOS上的全键无冲自动切换,增加GUI的视频播放功能
  • Loading branch information
bitsk authored Sep 2, 2021
2 parents 97c0f54 + 44eec06 commit 7723d2a
Show file tree
Hide file tree
Showing 5 changed files with 145 additions and 27 deletions.
20 changes: 10 additions & 10 deletions firmware/keyboard/sipeed_keyboard_68/include/smk_hid.h
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@
0x91, 0x02, /*OUTPUT (Data,Var,Abs)*/\
0xc0, /*END_COLLECTION*/

#define NKRO_KAYBOARD_DR_SIZE (57-18)
#define NKRO_KAYBOARD_DR_SIZE 57
#define NKRO_KAYBOARD_RD(...) \
0x05, 0x01, /*USAGE_PAGE (Generic Desktop)*/\
0x09, 0x06, /*USAGE (Keyboard)*/\
Expand All @@ -80,15 +80,15 @@
0x75, 0x01, /*REPORT_SIZE (1)*/\
0x95, 0x08, /*REPORT_COUNT (8)*/\
0x81, 0x02, /*INPUT (Data,Var,Abs)*/\
/*0x95, 0x05,*/ /*REPORT_COUNT (5)*/\
/*0x75, 0x01,*/ /*REPORT_SIZE (1)*/\
/*0x05, 0x08,*/ /*USAGE_PAGE (LEDs)*/\
/*0x19, 0x01,*/ /*USAGE_MINIMUM (Num Lock)*/\
/*0x29, 0x05,*/ /*USAGE_MAXIMUM (Kana)*/\
/*0x91, 0x02,*/ /*OUTPUT (Data,Var,Abs)*/\
/*0x95, 0x01,*/ /*REPORT_COUNT (1)*/\
/*0x75, 0x03,*/ /*REPORT_SIZE (3)*/\
/*0x91, 0x03,*/ /*OUTPUT (Cnst,Var,Abs)*/\
0x95, 0x05, /*REPORT_COUNT (5)*/\
0x75, 0x01, /*REPORT_SIZE (1)*/\
0x05, 0x08, /*USAGE_PAGE (LEDs)*/\
0x19, 0x01, /*USAGE_MINIMUM (Num Lock)*/\
0x29, 0x05, /*USAGE_MAXIMUM (Kana)*/\
0x91, 0x02, /*OUTPUT (Data,Var,Abs)*/\
0x95, 0x01, /*REPORT_COUNT (1)*/\
0x75, 0x03, /*REPORT_SIZE (3)*/\
0x91, 0x03, /*OUTPUT (Cnst,Var,Abs)*/\
0x05, 0x07, /*USAGE_PAGE (Keyboard)*/\
0x15, 0x00, /*LOGICAL_MINIMUM (0)*/\
0x25, 0x01, /*LOGICAL_MAXIMUM (1)*/\
Expand Down
45 changes: 42 additions & 3 deletions firmware/keyboard/sipeed_keyboard_68/smk_hid.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#include "FreeRTOS.h"
#include "queue.h"
#include "task.h"
#include "timers.h"

#include "keyboard/smk_event.h"
#include "keyboard/smk_keycode.h"
Expand All @@ -19,10 +20,14 @@ volatile int current_nkro_interface =NKRO_REPORT_ID;

static atomic_t kb_isupdate=0;
static int kb_idle=0;
static int kb_idle_dur=0;
static atomic_t kb_report_update=0;
static int use_nkro=0;
int kb_configured=0;
int force_basic_keyboard=0;

TimerHandle_t hid_timer;

static const uint8_t hid_keyboard_report_desc[HID_KEYBOARD_REPORT_DESC_SIZE] = {
STANDERD_KAYBOARD_RD()
};
Expand Down Expand Up @@ -134,8 +139,11 @@ void usbd_hid_kb_int_callback(uint8_t ep)
times[0]++;
if(use_nkro&&!force_basic_keyboard)
return;
if((!kb_idle)||atomic_set(&kb_isupdate,0))
if((!kb_idle&&kb_report_update)||atomic_set(&kb_isupdate,0)){
kb_report_update=0;
usbd_ep_write(HID_KB_INT_EP,hid_usb.buf[hid_usb.flag] , 8, NULL);
//USBD_LOG_DBG("times:%u,%u,%u,%u\r\n",times[0],times[1],times[2],times[3]);
}
}
void usbd_hid_nkro_int_callback(uint8_t ep)
{
Expand Down Expand Up @@ -219,7 +227,13 @@ void nkro_set_idle_callback(uint8_t reportid, uint8_t duration){

void kb_set_idle_callback(uint8_t reportid, uint8_t duration){
USBD_LOG_DBG("kb_set_idle_callback:%d,%d\r\n",reportid,duration);
USBD_LOG_DBG("kb_set_idle:%dms\r\n",duration*4);
kb_idle=duration==0;
kb_idle_dur=duration*4;
if(duration==0)
xTimerChangePeriod(hid_timer,portMAX_DELAY,portMAX_DELAY);
else
xTimerChangePeriod(hid_timer,pdMS_TO_TICKS(kb_idle_dur),portMAX_DELAY);
}

void smk_reset_callback(){
Expand All @@ -233,11 +247,20 @@ void smk_configured_callback(){
kb_configured=1;
}

static void smk_hidreport_update(TimerHandle_t xTimer)
{
kb_report_update=1;
}
void kb_set_protocol_callback(uint8_t protocal)
{
USBD_LOG_DBG("kb_set_protocol_callback:switch to nkro mode\r\n");
use_nkro=protocal;
}
void smk_hid_usb_init()
{
usbd_hid_add_interface(&hid_class, &hid_intf_kb);
usbd_interface_add_endpoint(&hid_intf_kb, &hid_kb_in_ep);
usbd_hid_callback_register(hid_intf_kb.intf_num,keyboard_led_cb,NULL,kb_set_idle_callback,NULL,NULL,NULL,smk_reset_callback,smk_configured_callback);
usbd_hid_callback_register(hid_intf_kb.intf_num,keyboard_led_cb,NULL,kb_set_idle_callback,NULL,NULL,kb_set_protocol_callback,smk_reset_callback,smk_configured_callback);
usbd_hid_report_descriptor_register(hid_intf_kb.intf_num, hid_keyboard_report_desc, HID_KEYBOARD_REPORT_DESC_SIZE);

usbd_hid_add_interface(&hid_class, &hid_intf_data);
Expand All @@ -247,10 +270,26 @@ void smk_hid_usb_init()

usbd_hid_add_interface(&hid_class, &hid_intf_nkro);
usbd_interface_add_endpoint(&hid_intf_nkro, &hid_nkro_in_ep);
usbd_hid_callback_register(hid_intf_nkro.intf_num,keyboard_led_cb,NULL,nkro_set_idle_callback,NULL,NULL,NULL,smk_reset_callback,NULL);
usbd_hid_callback_register(hid_intf_nkro.intf_num,keyboard_led_cb,NULL,nkro_set_idle_callback,NULL,NULL,kb_set_protocol_callback,smk_reset_callback,NULL);
usbd_hid_report_descriptor_register(hid_intf_nkro.intf_num, hid_nkro_report_desc, HID_NKRO_REPORT_DESC_SIZE);

hid_data_protocol_init();

// Set daemon task to handle keyscan periodically
hid_timer = xTimerCreate(
"hid report timer", // pcTimerName
pdMS_TO_TICKS(1), // xTimerPeriodInTicks
pdTRUE, // uxAutoReload
xTaskGetCurrentTaskHandle(), // pvTimerID
smk_hidreport_update // pxCallbackFunction
);

// Start timer
xTimerStart(
hid_timer, // xTimer
portMAX_DELAY // xTicksToWait
);

}

void smk_usb_hid_daemon_task(void *pvParameters)
Expand Down
35 changes: 25 additions & 10 deletions software/hidtest/kbapi.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ def __init__(self):
self.hidruning = False
self.isdeviceoen = False
self.lock=threading.Lock()
self.thid = threading.Thread(target=self.hidthread)

def newpackage(self, reportid, packageid, addr, len):
buffer = bytearray(8)
Expand Down Expand Up @@ -75,23 +76,27 @@ def writedata(self, addr, buffer: bytearray):
time.sleep(0.001)
wait -= 1
if wait == 0:
self.lock.release()
if self.lock.locked():
self.lock.release()
return -1
else:
datain = self.inputdatas.get()
reportid, retlen, packageid, retaddr = struct.unpack(self.Report_HEADER_Format, bytearray(datain[0:8]))
if packageid != self.getretid():
# print('pkgid error')
self.lock.release()
if self.lock.locked():
self.lock.release()
return -2
# else:
# print('succeed')
if (retlen != datatosent):
self.lock.release()
if self.lock.locked():
self.lock.release()
return -3
datasize -= datatosent
datapoint += datatosent
self.lock.release()
if self.lock.locked():
self.lock.release()
return datasize

def readdata(self, addr, len: int):
Expand All @@ -112,24 +117,28 @@ def readdata(self, addr, len: int):
time.sleep(0.001)
wait -= 1
if wait == 0:
self.lock.release()
if self.lock.locked():
self.lock.release()
return -1, retdata
else:
datain = self.inputdatas.get()
reportid, retlen, packageid, retaddr = struct.unpack(self.Report_HEADER_Format, bytearray(datain[0:8]))
if packageid != self.totalpackageid:
# print('pkgid error')
self.lock.release()
if self.lock.locked():
self.lock.release()
return -2, retdata
# else:
# print('succeed')
if (retlen != datatoget):
self.lock.release()
if self.lock.locked():
self.lock.release()
return -3, retdata
retdata += bytearray(datain[8:8 + retlen])
datasize -= datatoget
datapoint += datatoget
self.lock.release()
if self.lock.locked():
self.lock.release()
return datapoint, retdata

def hidthread(self):
Expand Down Expand Up @@ -171,12 +180,18 @@ def hidthread(self):
break

def init_hid_interface(self):
if self.thid.is_alive():
self.stop_and_wait()
self.thid = threading.Thread(target=self.hidthread)
self.hidruning = True
self.thid = threading.Thread(target=self.hidthread)
self.thid.start()
def stop_and_wait(self):
self.hidruning =False
self.thid.join()
self.isdeviceoen=False
if self.thid.is_alive():
self.thid.join()
self.thid = threading.Thread(target=self.hidthread)

def wait_for_kb(self,timeout=0):
timesecond=timeout/1000;
while not self.isdeviceoen:
Expand Down
3 changes: 2 additions & 1 deletion software/hidtest/kbled.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ def gammafunction(self, r, g, b):

def play_frame_full(self, frame):
frame = cv2.resize(frame, (128, int(self.keyh / self.keyw * 128)), interpolation=cv2.INTER_NEAREST)
self.play_frame(frame)
return self.play_frame(frame)

def play_frame(self, frame):
xsize = frame.shape[1]
Expand Down Expand Up @@ -165,6 +165,7 @@ def play_frame(self, frame):
colordata += struct.pack('BBBB', int(colorb), int(colorg), int(colorr), 0)
keyid += 1
self.kb.writedata(0x9000, colordata)
return colordata
def switchmode(self,mode:int):
self.kb.writedata(0x8000, struct.pack('I', mode))
def getled(self):
Expand Down
69 changes: 66 additions & 3 deletions software/hidtest/maingui.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@
from PyQt5.QtGui import QPixmap

import sys
import cv2
import numpy as np
import threading

from kbled import keyboard_led
Expand All @@ -19,25 +21,40 @@ def __init__(self):
self.ui.tabWidget.setCurrentIndex(0)
self.kb = keyboard_ctl()
self.leds=keyboard_led(self.kb)
self.video_opened=False
self.video_running=False
self.leddata=bytearray(272)

self.ui.mode_set_btn.clicked.connect(self.set_mode_func)
self.ui.connect_btn.clicked.connect(self.connectfunc)
self.ui.stop_btn.clicked.connect(self.stopfunc)
self.ui.video_play_btn.clicked.connect(self.videofunc)

self.videothreadid = threading.Thread(target=self.videothread)

self.videolock=threading.Lock()

self.previewtimer=QTimer()
self.previewtimer.timeout.connect(self.updateperview)
self.videotimer=QTimer()
self.videotimer.timeout.connect(self.videotimerfunc)

def connectfunc(self):
self.kb.init_hid_interface()
if(self.kb.wait_for_kb(1000)==False):
self.ui.logbox.appendPlainText("Connect Failed\n")
self.kb.stop_and_wait()
return
self.startTimer()
def stopfunc(self):
self.stopTimer()
self.stopvideo()
self.kb.stop_and_wait()

def closeEvent(self, event):
self.kb.stop_and_wait()
self.stopvideo()

def set_mode_func(self):
if self.kb.isdeviceoen==False:
return
Expand All @@ -53,11 +70,13 @@ def stopTimer(self):
self.previewtimer.stop()
def updateperview(self):
if(self.kb.wait_for_kb(1000)==False):return
lens,data=self.leds.getled()
if(lens<0):return
if(self.video_running==False):
lens,self.leddata=self.leds.getled()
if(lens<0):
return
width=(self.ui.preview_box.width()-10)
height=(self.ui.preview_box.height()-10)
img=self.leds.getpreview_rgb(data,(width,height))
img=self.leds.getpreview_rgb(self.leddata,(width,height))
previewimg = QImage(img,
width, height, width*3,
QImage.Format_RGB888)
Expand All @@ -68,6 +87,50 @@ def updateperview(self):
self.prescene.addItem(self.preitem)
self.ui.preview_box.setScene(self.prescene)

def videofunc(self):
if self.kb.wait_for_kb(100)==False:
return
if self.videothreadid.is_alive():
self.video_running=False
self.videothreadid.join()
self.videolink=self.ui.video_link_box.text()
self.cvvideo=cv2.VideoCapture()
self.cvvideo.open(self.videolink)
if(self.cvvideo.isOpened()):
self.leds.switchmode(0xff)
fps=self.cvvideo.get(cv2.CAP_PROP_FPS)
self.videotimer.start(int(np.floor(1000/fps)))
self.video_opened=True
self.video_running=True
self.videothreadid = threading.Thread(target=self.videothread)
self.videothreadid.start()
def videotimerfunc(self):
if(self.videolock.locked()):
self.videolock.release()
def videothread(self):
kbresetflag=False
while self.video_running and self.video_opened:
self.videolock.acquire()
if kbresetflag:
self.leds.switchmode(0xff)
ret, frame1 = self.cvvideo.read()
if(ret):
if self.kb.wait_for_kb(100) == False:
kbresetflag=True
continue
self.leddata=self.leds.play_frame_full(frame1)
else:
self.cvvideo.set(cv2.CAP_PROP_POS_FRAMES,0)
# kb.stop_and_wait()
# sys.exit(0)
def stopvideo(self):
if self.videothreadid.is_alive():
self.video_running=False
self.videolock.release()
self.videothreadid.join()
self.cvvideo.release()
self.video_opened=False
self.videotimer.stop()

if __name__ == '__main__':
app = QApplication(sys.argv)
Expand Down

0 comments on commit 7723d2a

Please sign in to comment.