From 8476e9ba32ce11e3ffe46a497aae4fe3fb2c3fa7 Mon Sep 17 00:00:00 2001 From: hailin <3dgans@outlook.com> Date: Wed, 1 Sep 2021 22:34:13 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E4=BF=AE=E6=AD=A3=E4=BA=86macOS=E4=B8=8A?= =?UTF-8?q?=E7=9A=84=E5=85=A8=E9=94=AE=E6=97=A0=E5=86=B2=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E5=88=87=E6=8D=A2=20*=E5=BF=85=E9=A1=BB=E5=90=8C=E6=97=B6?= =?UTF-8?q?=E6=8A=8Acmake=E6=9E=84=E5=BB=BA=E7=B1=BB=E5=9E=8B=E6=94=B9?= =?UTF-8?q?=E6=88=90DEBUG=E5=BC=80=E5=90=AF=E8=B0=83=E8=AF=95=E8=BE=93?= =?UTF-8?q?=E5=87=BA=E4=B8=8D=E7=84=B6=E5=9C=A8macOS=E4=B8=8A=E4=BC=9A?= =?UTF-8?q?=E5=87=BA=E4=B8=80=E4=BA=9B=E5=A5=87=E5=A5=87=E6=80=AA=E6=80=AA?= =?UTF-8?q?=E7=9A=84=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../sipeed_keyboard_68/include/smk_hid.h | 20 ++++----- .../keyboard/sipeed_keyboard_68/smk_hid.c | 45 +++++++++++++++++-- 2 files changed, 52 insertions(+), 13 deletions(-) diff --git a/firmware/keyboard/sipeed_keyboard_68/include/smk_hid.h b/firmware/keyboard/sipeed_keyboard_68/include/smk_hid.h index b114e6e..8c4a49d 100644 --- a/firmware/keyboard/sipeed_keyboard_68/include/smk_hid.h +++ b/firmware/keyboard/sipeed_keyboard_68/include/smk_hid.h @@ -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)*/\ @@ -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)*/\ diff --git a/firmware/keyboard/sipeed_keyboard_68/smk_hid.c b/firmware/keyboard/sipeed_keyboard_68/smk_hid.c index d710d4c..19ba402 100644 --- a/firmware/keyboard/sipeed_keyboard_68/smk_hid.c +++ b/firmware/keyboard/sipeed_keyboard_68/smk_hid.c @@ -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" @@ -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() }; @@ -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) { @@ -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(){ @@ -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); @@ -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) From 44eec06011c1a5c853fcf3dd409ff45f24aee903 Mon Sep 17 00:00:00 2001 From: hailin <3dgans@outlook.com> Date: Wed, 1 Sep 2021 22:35:42 +0800 Subject: [PATCH 2/2] add video playback and improved stability --- software/hidtest/kbapi.py | 35 +++++++++++++------ software/hidtest/kbled.py | 3 +- software/hidtest/maingui.py | 69 +++++++++++++++++++++++++++++++++++-- 3 files changed, 93 insertions(+), 14 deletions(-) diff --git a/software/hidtest/kbapi.py b/software/hidtest/kbapi.py index 1fba64e..4be4597 100644 --- a/software/hidtest/kbapi.py +++ b/software/hidtest/kbapi.py @@ -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) @@ -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): @@ -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): @@ -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: diff --git a/software/hidtest/kbled.py b/software/hidtest/kbled.py index 98fcf74..703fefb 100644 --- a/software/hidtest/kbled.py +++ b/software/hidtest/kbled.py @@ -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] @@ -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): diff --git a/software/hidtest/maingui.py b/software/hidtest/maingui.py index 9deac62..c273a38 100644 --- a/software/hidtest/maingui.py +++ b/software/hidtest/maingui.py @@ -6,6 +6,8 @@ from PyQt5.QtGui import QPixmap import sys +import cv2 +import numpy as np import threading from kbled import keyboard_led @@ -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 @@ -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) @@ -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)