安装完毕后,安装目录里的文件有这些:

把遥控接收器插到电脑后面的串口上,然后双击“AeroPrism”即可启动上位机软件。启动后,需要设置好串口号,我的是COM1。

然后就可以使用了。
通过切换遥控器模式实现不同的功能。比如快捷运行,只要把快捷方式放到“Shortcuts”文件夹下,通过OSD就可以快速运行电脑上的任何文件了。活用这个功能,在听歌、看影片、看照片的时候就会很方便了。

因为是软解,这套DIY还可以变通把红外遥控的码显示出来,但是只限于NEC协议。

上位机解码部分代码
;==========================================================
; 红外码串口接收
;
;==========================================================
;串口设备的缓存推荐值(系统用,和软件中的是两回事)
#MAX_WRITE_BUFFER = 1024
#MAX_READ_BUFFER = 1024
#EVENT_CHAR = $ff ;用来产生事件的字符(ANSI only, 1 Byte)
#FRAME_DURATION = 108 ;遥控器每帧数据时间(ms)
#MARGIN_OF_ERROR = 10 ;误差(ms)
;在何时接收到什么键码
Structure WhenWhatKey
key_code.l ;键码
dwTimeFirst.l ;接收到最初的32位码的时间
dwTime.l ;接收时间
fBurst.l ;是否连发码
EndStructure
Global m_hCommPort.l ;串口设备句柄
Global m_timeouts_orig.COMMTIMEOUTS ;保存系统默认的串口超时值
Global m_dwEventFlags.l ;用于 WaitCommEvent 的串口事件
Global m_hEventReadExit.l ;读线程退出内核事件
Global m_hReadThread.l ;读线程句柄
;函数声明
Declare Read_StatusThread(*value)
Declare KeyCodePump(*pBuffer, cbData.l)
Declare PortEventHandler(dwCommEvent.l)
;串口设置字串
DataSection
DCS:
Data.s "baud=9600 parity=N data=8 stop=1"
EndDataSection
; 试一下串口端口是否可用
Procedure.i IsPortAvailable(nPort.l)
Dim sPortString.c(8)
*p = @sPortString()
CopyMemoryString(@"COM", @*p)
CopyMemoryString(Str(nPort))
hComm.l = CreateFile_(sPortString(), #GENERIC_READ, 0, #Null, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL | #FILE_FLAG_OVERLAPPED, #Null)
If hComm = #INVALID_HANDLE_VALUE
ProcedureReturn #False
Else
CloseHandle_(hComm)
ProcedureReturn #True
EndIf
EndProcedure
Procedure ConfigurePort(hComm.l)
;设置 DCB
dcb.DCB
GetCommState_(hComm, @dcb)
sSettings.s
Restore DCS
Read.s sSettings
BuildCommDCB_(@sSettings, @dcb) ;波特率、奇偶校验、停止位
dcb\EvtChar = #EVENT_CHAR ;事件字符
dcb\fbits | (1 << 1) ;奇偶校验
SetCommState_(hComm, @dcb)
;设置超时参数
GetCommTimeouts_(hComm, @m_timeouts_orig) ;先保存原来的
ct.COMMTIMEOUTS
With ct
\ReadIntervalTimeout = 20
\ReadTotalTimeoutMultiplier = 0
\ReadTotalTimeoutConstant = 0
EndWith
SetCommTimeouts_(hComm, @ct)
;设置缓存大小
SetupComm_(hComm, #MAX_READ_BUFFER, #MAX_WRITE_BUFFER)
EndProcedure
Procedure SetPortEvent(dwEvent.l)
m_dwEventFlags = dwEvent
EndProcedure
Procedure StartupComm(nPort.l)
If GetFileType_(m_hCommPort) = #FILE_TYPE_CHAR
ProcedureReturn
EndIf
;打开串口设备
Dim sPortString.c(8)
*p = @sPortString()
CopyMemoryString(@"COM", @*p)
CopyMemoryString(Str(nPort))
m_hCommPort = CreateFile_(sPortString(), #GENERIC_READ, 0, #Null, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL | #FILE_FLAG_OVERLAPPED, #Null)
If m_hCommPort = #INVALID_HANDLE_VALUE
ProcedureReturn
EndIf
;配置串口参数
ConfigurePort(m_hCommPort)
;设置 WaitCommEvent 的串口事件
SetPortEvent(#EV_ERR)
;建立线程退出事件
m_hEventReadExit = CreateEvent_(#Null, 0, 0, #Null)
;启动读线程
m_hReadThread = ThreadID(CreateThread(@Read_StatusThread(), 0))
SetThreadPriority_(m_hReadThread, #THREAD_PRIORITY_HIGHEST)
EndProcedure
Procedure BreakdownComm()
If GetFileType_(m_hCommPort) <> #FILE_TYPE_CHAR
ProcedureReturn
EndIf
;结束读线程
SetEvent_(m_hEventReadExit)
WaitForSingleObject_(m_hReadThread, #INFINITE)
CloseHandle_(m_hEventReadExit)
CloseHandle_(m_hReadThread)
;还原超时参数
SetCommTimeouts_(m_hCommPort, @m_timeouts_orig)
CloseHandle_(m_hCommPort)
m_hCommPort = #Null
EndProcedure
; 改变串口设备
Procedure AlterComm(nPort.l)
;打开新串口
Dim sPortString.c(8)
*p = @sPortString()
CopyMemoryString(@"COM", @*p)
CopyMemoryString(Str(nPort))
hComm.l = CreateFile_(sPortString(), #GENERIC_READ, 0, #Null, #OPEN_EXISTING, #FILE_ATTRIBUTE_NORMAL | #FILE_FLAG_OVERLAPPED, #Null)
If hComm = #INVALID_HANDLE_VALUE
ProcedureReturn
EndIf
;关闭旧串口
If GetFileType_(m_hCommPort) = #FILE_TYPE_CHAR
;结束读线程
SetEvent_(m_hEventReadExit)
WaitForSingleObject_(m_hReadThread, #INFINITE)
CloseHandle_(m_hReadThread)
;还原超时参数
SetCommTimeouts_(m_hCommPort, @m_timeouts_orig)
;关闭内核文件对象
CloseHandle_(m_hCommPort)
m_hCommPort = #Null
Else ;之前没有串口设备打开,需要建立相关同步对象
;建立线程退出事件
m_hEventReadExit = CreateEvent_(#Null, 0, 0, #Null)
EndIf
m_hCommPort = hComm
;配置新串口
ConfigurePort(m_hCommPort)
;设置 WaitCommEvent 的串口事件
SetPortEvent(#EV_ERR)
;启动读线程
m_hReadThread = ThreadID(CreateThread(@Read_StatusThread(), 0))
SetThreadPriority_(m_hReadThread, #THREAD_PRIORITY_HIGHEST)
EndProcedure
; 串口读与串口事件线程
Procedure Read_StatusThread(*value)
#READ_STATUS_CHECK_TIMEOUT = #INFINITE
#BYTES_OF_READ_BUFFER = 40
Define.l cbRead, cbDummy
dwWaitRst.l
Define.l dwCommEvent, dwStoredEvtFlags = ~0
Define.i fThreadDone = #False, fWaitingOnRead = #False, fWaitingOnStat = #False
; 建立接收缓存
Dim buffer.a(#BYTES_OF_READ_BUFFER - 1)
; 建立内核对象
Define.OVERLAPPED osReader, osStatus
osReader\hEvent = CreateEvent_(#Null, 1, 0, #Null)
osStatus\hEvent = CreateEvent_(#Null, 1, 0, #Null)
; 需要侦测下面几个事件:
; Read event
; Status event
; Thread exit event
;
Dim hArray.l(2)
hArray(0) = osReader\hEvent
hArray(1) = osStatus\hEvent
hArray(2) = m_hEventReadExit
While Not fThreadDone
; 若无读操作处于等待中,新建一个读操作
If Not fWaitingOnRead
If Not ReadFile_(m_hCommPort, buffer(), #BYTES_OF_READ_BUFFER, @cbRead, @osReader)
If GetLastError_() <> #ERROR_IO_PENDING
; 出错了
EndIf
fWaitingOnRead = #True
Else ; 读操作立即完成
If cbRead <> 0
KeyCodePump(buffer(), cbRead)
EndIf
EndIf
EndIf
;更新 WaitCommEvent 的事件
If dwStoredEvtFlags <> m_dwEventFlags
dwStoredEvtFlags = m_dwEventFlags
SetCommMask_(m_hCommPort, dwStoredEvtFlags)
EndIf
; 若无串口事件处于等待中,建立串口事件等待
If Not fWaitingOnStat
If Not WaitCommEvent_(m_hCommPort, @dwCommEvent, @osStatus)
If GetLastError_() <> #ERROR_IO_PENDING
; 出错了
Else
fWaitingOnStat = #True
EndIf
Else ; WaitCommEvent 立即返回
PortEventHandler(dwCommEvent)
EndIf
EndIf
;等待未决操作完成
If fWaitingOnStat And fWaitingOnRead
dwWaitRst = WaitForMultipleObjects_(3, hArray(), 0, #READ_STATUS_CHECK_TIMEOUT)
Select dwWaitRst
Case #WAIT_OBJECT_0 ; 读操作结束
If Not GetOverlappedResult_(m_hCommPort, @osReader, @cbRead, 0)
If GetLastError_() = #ERROR_OPERATION_ABORTED
; 读操作放弃
Else
; 出错了
EndIf
Else ;读操作成功完成
If cbRead <> 0
KeyCodePump(buffer(), cbRead)
EndIf
EndIf
fWaitingOnRead = #False
Case #WAIT_OBJECT_0 + 1 ;有串口事件
If Not GetOverlappedResult_(m_hCommPort, @osStatus, @cbDummy, 0)
If GetLastError_() = #ERROR_OPERATION_ABORTED
; WaitCommEvent 放弃
Else
; 出错了
EndIf
Else ; 成功
PortEventHandler(dwCommEvent) ;WaitCommEvent 仍会填充 dwCommEvent
EndIf
fWaitingOnStat = #False
Case #WAIT_OBJECT_0 + 2 ; 线程退出
GetOverlappedResult_(m_hCommPort, @osReader, @cbRead, #False)
PurgeComm_(m_hCommPort, #PURGE_RXABORT | #PURGE_RXCLEAR) ;停止异步读取(线程退出后,接收缓存就不存在了)
fThreadDone = #True
Case #WAIT_TIMEOUT ; 超时
;
; 用这个机会检查串口状态、清除错误等
;
EndSelect
EndIf
Wend
; 释放内核对象
CloseHandle_(osReader\hEvent)
CloseHandle_(osStatus\hEvent)
EndProcedure
;响应串口事件
Procedure PortEventHandler(dwCommEvent.l)
Define.l fCTS, fDSR, fERR, fRING, fRLSD, fBREAK, fRXCHAR, fRXFLAG, fTXEMPTY
fCTS = #EV_CTS & dwCommEvent
fDSR = #EV_DSR & dwCommEvent
fERR = #EV_ERR & dwCommEvent
fRING = #EV_RING & dwCommEvent
fRLSD = #EV_RLSD & dwCommEvent
fBREAK = #EV_BREAK & dwCommEvent
fRXCHAR = #EV_RXCHAR & dwCommEvent
fRXFLAG = #EV_RXFLAG & dwCommEvent
fTXEMPTY = #EV_TXEMPTY & dwCommEvent
If fERR ;有错误发生
dwErrs.l
cs.COMSTAT
ClearCommError_(m_hCommPort, @dwErrs, @cs)
EndIf
EndProcedure
;把收到的数据取出,检验合法性,投入队列
Procedure KeyCodePump(*pBuffer, cbData.l)
Static s_previous_key.WhenWhatKey ;之前接收到的键码
Static Dim s_buffer.a(33) ;按键数据缓存
Static s_offset.l ;偏移
ks.KeyInstruction
;获得当前时间
dwTime.l = timeGetTime_()
;把收到的数据放到缓存中
If s_offset + cbData <= 34
CopyMemory(*pBuffer, @s_buffer() + s_offset, cbData)
s_offset + cbData
Else ;之前接收过乱码?
If cbData = 34 ;丢弃之前的,本次的算作一次接收
CopyMemory(*pBuffer, @s_buffer(), 34)
s_offset = 34
Else
s_offset = 0
FillMemory(@s_previous_key, SizeOf(WhenWhatKey), 0)
ProcedureReturn
EndIf
EndIf
Select s_offset
Case 2 ;连发码
If PeekU(s_buffer()) = 0 And dwTime - s_previous_key\dwTime <= #FRAME_DURATION + #MARGIN_OF_ERROR ;有效的连发码
s_previous_key\dwTime = dwTime
s_previous_key\fBurst = 1
If dwTime - s_previous_key\dwTimeFirst >= g_kb_delay
ks\key_code = s_previous_key\key_code
ks\fStatus = #KS_BURST
EnterCriticalSection_(@g_csQKI)
EnterQueue(@g_queueKeyIns, @ks)
LeaveCriticalSection_(@g_csQKI)
SetEvent_(g_hEventKeySignal)
EndIf
EndIf
s_offset = 0
Case 34 ;键码
Dim key_code.a(3) ;a(3) -- ID7 ~ ID0
;a(2) -- ID7 ~ ID0 (NOT)
;a(1) -- FUN7 ~ FUN0
;a(0) -- FUN7 ~ FUN0 (NOT)
;红外码低位在前发送
Define.i i, j, k
If s_buffer(0) = 0 And s_buffer(33) = 0
k = 1
For i = 3 To 0 Step -1
Select s_buffer(k)
Case $0 ;逻辑1
key_code(i) | $80
Case $e0, $f0 ;逻辑0
key_code(i) | $0
Default ;按0处理
key_code(i) | $0
EndSelect
k + 1
For j = 1 To 7
key_code(i) >> 1
Select s_buffer(k)
Case $0 ;逻辑1
key_code(i) | $80
Case $e0, $f0 ;逻辑0
key_code(i) | $0
Default ;按0处理
key_code(i) | $0
EndSelect
k + 1
Next j
Next i
If key_code(0) ! key_code(1) = $ff ;And key_code(2) ! key_code(3) = $ff ;有效键码
If s_previous_key\fBurst = 0 And s_previous_key\key_code = PeekL(key_code()) And dwTime - s_previous_key\dwTime <= g_dbclick_time ;认为是双击
ks\fStatus = #KS_DBCLICK
Else
s_previous_key\key_code = PeekL(key_code())
s_previous_key\fBurst = 0
ks\fStatus = #KS_PRESSED
EndIf
s_previous_key\dwTime = dwTime
s_previous_key\dwTimeFirst = dwTime
ks\key_code = PeekL(key_code())
EnterCriticalSection_(@g_csQKI)
EnterQueue(@g_queueKeyIns, @ks)
LeaveCriticalSection_(@g_csQKI)
SetEvent_(g_hEventKeySignal)
PostThreadMessage_(g_idMainThread, #TM_IRKEYCODE, ks\key_code, 0)
EndIf
EndIf
s_offset = 0
EndSelect
EndProcedure |
(责任编辑:admin) |