Update to 1.66+, revert USB lib to 3.4, fix USB/Serial issue in Android 13+
- Updated source code with Emu48 version 1.66+ - Update Revert usb-serial-for-android to version 3.4 - Fix an USB serial issue with Android 13+ (fix #23)
This commit is contained in:
parent
8025fe107d
commit
9f58423a93
45 changed files with 4112 additions and 4428 deletions
|
@ -60,7 +60,7 @@ CHANGES
|
|||
|
||||
Version 2.8 (2024-xx-xx)
|
||||
|
||||
- Update the usb serial drivers usb-serial-for-android to version 3.7.3
|
||||
- Updated source code with Emu48 version 1.66+.
|
||||
|
||||
|
||||
Version 2.7 (2024-06-14)
|
||||
|
@ -277,6 +277,7 @@ FAQ
|
|||
TODO
|
||||
|
||||
- NDK 26 does not compile
|
||||
- Adding a new KML command for Android only: CUSTOM_PIXEL_BORDER_ON 10001 / CUSTOM_PIXEL_BORDER_OFF 10002 / CUSTOM_PIXEL_BORDER_TOGGLE 10003
|
||||
- Patching 49G to disable 10 min auto off causes a reset when touching the Recent button and coming back to the app (with a Flashcard loaded).
|
||||
- Add an "haptic" feedback with a sound instead of a vibration (F. Giampietro).
|
||||
- Add a Cancel button to the HP48 memory card creator dialog.
|
||||
|
|
|
@ -65,7 +65,7 @@ add_library( # Sets the name of the library.
|
|||
src/main/cpp/core/disrpl.c
|
||||
# src/main/cpp/core/Emu48.c #-> To rewrite
|
||||
src/main/cpp/core/engine.c
|
||||
src/main/cpp/core/external.c
|
||||
# src/main/cpp/core/external.c # Removed 167/166+
|
||||
src/main/cpp/core/fetch.c
|
||||
src/main/cpp/core/files.c
|
||||
src/main/cpp/core/i28f160.c
|
||||
|
|
|
@ -34,8 +34,8 @@ android {
|
|||
applicationId "org.emulator.forty.eight"
|
||||
minSdk 21
|
||||
targetSdk 34
|
||||
versionCode 27
|
||||
versionName "2.8"
|
||||
versionCode 26
|
||||
versionName "2.7"
|
||||
setProperty("archivesBaseName", "Emu48-v$versionName")
|
||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||
externalNativeBuild {
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
android:fullBackupContent="@xml/backup_descriptor">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
|
||||
android:launchMode="singleTop"
|
||||
android:theme="@style/AppTheme.NoActionBar"
|
||||
|
|
|
@ -526,10 +526,10 @@ h3 { color:red; font-size:1.1em; }
|
|||
"String" object in stack level 1 to the clipboard. On all
|
||||
other objects, the command will be ignored. This prevents sending
|
||||
binary objects to the clipboard.</p>
|
||||
<p>The decimal point (radix mark) of "Real Numbers" in the
|
||||
clipboard is equal to the calculator setting. This is important when
|
||||
you try to paste the numbers into a program using the locale settings
|
||||
of the host operating system.</p>
|
||||
<p>The decimal point of "Real Numbers" in the clipboard is
|
||||
equal to the calculator setting. This is important when you try to
|
||||
paste the numbers into a program using the locale settings of the host
|
||||
operating system.</p>
|
||||
<h2><a name=ss9.5>9.5 Paste Stack</a></h2>
|
||||
<p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
|
||||
emulation.</p>
|
||||
|
@ -539,14 +539,18 @@ h3 { color:red; font-size:1.1em; }
|
|||
object. Is the content a complex number object, the number will be
|
||||
saved as "Complex Number" object, otherwise cases as
|
||||
"String" object.</p>
|
||||
<p>To import "Real or Complex Numbers" from the clipboard, the
|
||||
decimal point (radix mark) of the clipboard and calculator <u>must</u>
|
||||
match. A real or complex number is only detected in the case of valid
|
||||
real number characters in the clipboard. Especially heading and tailing
|
||||
white spaces aren't valid number characters also.</p>
|
||||
<p>Complex numbers must be in the form <i>(a,b)</i> when using the point
|
||||
radix mark or in the form <i>(a;b)</i> when using the comma radix mark.
|
||||
The Cartesian or algebraic form <i>a+bi</i> is not supported.</p>
|
||||
<p>To import "Real Numbers" from the clipboard, the decimal
|
||||
point character of the clipboard and calculator <u>must not match</u> any
|
||||
more. There's an auto detection for decoding the thousands separator and
|
||||
decimal point character. The thousands separator is removed at decoding.
|
||||
A real number is detected in the case of valid real number characters in
|
||||
the clipboard.</p>
|
||||
<p>"Complex Numbers" must be in the form <i>(a,b)</i> when
|
||||
using the decimal point or in the form <i>(a;b)</i> when using the decimal
|
||||
comma. Using a thousands separator is not allowed in complex number
|
||||
strings because in decimal point mode, the comma is used as separator
|
||||
between real and imaginary part of the number. The Cartesian or algebraic
|
||||
form <i>a+bi</i> is not supported.</p>
|
||||
<h2><a name=ss9.6>9.6 Reset Calculator</a></h2>
|
||||
<p>This emulates the Reset pin of the internal CPU.</p>
|
||||
<h2><a name=ss9.7>9.7 Backup</a></h2>
|
||||
|
@ -675,7 +679,7 @@ h3 { color:red; font-size:1.1em; }
|
|||
Cyrille de Brebisson of Hewlett-Packard.</p>
|
||||
<h1><a name=s15>15. License</a></h1>
|
||||
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
|
||||
Copyright (C) 2022 Christoph Gießelink</p>
|
||||
Copyright (C) 2024 Christoph Gießelink</p>
|
||||
<p>This program is free software; you can redistribute it and/or modify it
|
||||
under the terms of the GNU General Public License as published by the Free
|
||||
Software Foundation; either version 2 of the License, or (at your option)
|
||||
|
|
|
@ -58,11 +58,6 @@ LINKS
|
|||
|
||||
CHANGES
|
||||
|
||||
Version 2.8 (2024-xx-xx)
|
||||
|
||||
- Update the usb serial drivers usb-serial-for-android to version 3.7.3
|
||||
|
||||
|
||||
Version 2.7 (2024-06-14)
|
||||
|
||||
- Updated source code with Emu48 version 1.65+. This new version improve the serial communication.
|
||||
|
|
|
@ -13,7 +13,7 @@
|
|||
#include "kml.h"
|
||||
#include "debugger.h"
|
||||
|
||||
#define VERSION "1.65+"
|
||||
#define VERSION "1.66+"
|
||||
|
||||
#ifdef _DEBUG
|
||||
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" Debug");
|
||||
|
@ -2045,6 +2045,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||
MSG msg;
|
||||
WNDCLASS wc;
|
||||
ATOM classAtom;
|
||||
WSADATA wsd;
|
||||
RECT rectWindow;
|
||||
HACCEL hAccel;
|
||||
DWORD dwThreadId;
|
||||
|
@ -2059,16 +2060,8 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||
|
||||
hApp = hInst;
|
||||
#if defined _UNICODE
|
||||
{
|
||||
ppArgv = (LPCTSTR*) CommandLineToArgvW(GetCommandLine(),&nArgc);
|
||||
}
|
||||
#else
|
||||
{
|
||||
nArgc = __argc; // no. of command line arguments
|
||||
ppArgv = (LPCTSTR*) __argv; // command line arguments
|
||||
}
|
||||
#endif
|
||||
nArgc = __argc; // no. of command line arguments
|
||||
ppArgv = __targv; // command line arguments
|
||||
|
||||
wc.style = CS_BYTEALIGNCLIENT;
|
||||
wc.lpfnWndProc = (WNDPROC)MainWndProc;
|
||||
|
@ -2298,6 +2291,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
|||
if (NewDocument()) SetWindowTitle(_T("Untitled"));
|
||||
|
||||
start:
|
||||
VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0);
|
||||
if (bStartupBackup) SaveBackup(); // make a RAM backup at startup
|
||||
if (pbyRom) SwitchToState(SM_RUN);
|
||||
|
||||
|
@ -2313,6 +2307,7 @@ start:
|
|||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
WSACleanup(); // cleanup network stack
|
||||
|
||||
// clean up DDE server
|
||||
DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER);
|
||||
|
|
|
@ -369,6 +369,7 @@ extern BOOL SendByteUdp(BYTE byData);
|
|||
|
||||
// Stack.c
|
||||
extern BOOL bDetectClpObject;
|
||||
extern BOOL bLocaleDecimalPoint;
|
||||
extern LRESULT OnStackCopy(VOID);
|
||||
extern LRESULT OnStackPaste(VOID);
|
||||
|
||||
|
|
|
@ -65,8 +65,8 @@ static CONST TCHAR cHex[] = { _T('0'),_T('1'),_T('2'),_T('3'),
|
|||
_T('8'),_T('9'),_T('A'),_T('B'),
|
||||
_T('C'),_T('D'),_T('E'),_T('F') };
|
||||
|
||||
static INT nDbgPosX = 0; // position of debugger window
|
||||
static INT nDbgPosY = 0;
|
||||
static INT nDbgPosX = CW_USEDEFAULT; // position of debugger window
|
||||
static INT nDbgPosY = CW_USEDEFAULT;
|
||||
|
||||
static WORD wBreakpointCount = 0; // number of breakpoints
|
||||
static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table
|
||||
|
@ -1885,7 +1885,10 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
if (nDbgPosX != CW_USEDEFAULT) // not default window position
|
||||
{
|
||||
SetWindowLocation(hDlg,nDbgPosX,nDbgPosY);
|
||||
}
|
||||
if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
|
||||
SendMessage(hDlg,WM_SETICON,ICON_BIG,(LPARAM) LoadIcon(hApp,MAKEINTRESOURCE(IDI_EMU48)));
|
||||
|
||||
|
@ -2201,7 +2204,7 @@ static INT_PTR CALLBACK Debugger(HWND hDlg, UINT message, WPARAM wParam, LPARAM
|
|||
|
||||
LRESULT OnToolDebug(VOID) // debugger dialogbox call
|
||||
{
|
||||
if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),NULL,
|
||||
if ((hDlgDebug = CreateDialog(hApp,MAKEINTRESOURCE(IDD_DEBUG),hWnd,
|
||||
(DLGPROC)Debugger)) == NULL)
|
||||
AbortMessage(_T("Debugger Dialog Box Creation Error !"));
|
||||
return 0;
|
||||
|
@ -3501,46 +3504,79 @@ static BOOL OnBrowseSaveMem(HWND hDlg)
|
|||
//
|
||||
// write file to memory
|
||||
//
|
||||
static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr)
|
||||
static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,UINT uBitMode)
|
||||
{
|
||||
HANDLE hFile;
|
||||
DWORD dwRead;
|
||||
BYTE byData;
|
||||
DWORD dwFileSize,dwRead;
|
||||
LPBYTE pbyData;
|
||||
|
||||
hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file
|
||||
return FALSE;
|
||||
|
||||
while (dwStartAddr <= 0xFFFFF) // read until EOF or end of Saturn address space
|
||||
dwFileSize = GetFileSize(hFile, NULL);
|
||||
if ((pbyData = (LPBYTE) malloc(dwFileSize)) != NULL)
|
||||
{
|
||||
ReadFile(hFile,&byData,sizeof(byData),&dwRead,NULL);
|
||||
if (dwRead == 0) break; // EOF
|
||||
|
||||
if (dwStartAddr < 0xFFFFF)
|
||||
ReadFile(hFile,pbyData,dwFileSize,&dwRead,NULL);
|
||||
if (uBitMode == 2) // auto mode (0=8-bit, 1=4-bit, 2=auto)
|
||||
{
|
||||
Write2(dwStartAddr,byData); // write byte in map mode
|
||||
dwStartAddr += 2;
|
||||
BOOL bPacked = FALSE; // data not packed
|
||||
DWORD dwIndex;
|
||||
for (dwIndex = 0; !bPacked && dwIndex < dwFileSize; ++dwIndex)
|
||||
{
|
||||
bPacked = ((pbyData[dwIndex] & 0xF0) != 0);
|
||||
}
|
||||
uBitMode = bPacked ? 0 : 1; // 0=8-bit, 1=4-bit
|
||||
}
|
||||
|
||||
if (uBitMode == 0) // 0=8-bit
|
||||
{
|
||||
LPBYTE pbyDataNew = (LPBYTE) realloc(pbyData,2*dwFileSize);
|
||||
if (pbyDataNew)
|
||||
{
|
||||
LPBYTE pbySrc,pbyDest;
|
||||
pbyData = pbyDataNew;
|
||||
pbySrc = pbyData + dwFileSize;
|
||||
dwFileSize *= 2; // new filesize
|
||||
pbyDest = pbyData + dwFileSize;
|
||||
while (pbySrc != pbyDest) // unpack source
|
||||
{
|
||||
CONST BYTE byValue = *(--pbySrc);
|
||||
*(--pbyDest) = byValue >> 4;
|
||||
*(--pbyDest) = byValue & 0xF;
|
||||
}
|
||||
_ASSERT(pbySrc == pbyData);
|
||||
_ASSERT(pbyDest == pbyData);
|
||||
}
|
||||
else // special handling to avoid address wrap around
|
||||
{
|
||||
byData &= 0xF;
|
||||
Nwrite(&byData,dwStartAddr,1); // write nibble in map mode
|
||||
++dwStartAddr;
|
||||
free(pbyData);
|
||||
pbyData = NULL;
|
||||
}
|
||||
}
|
||||
if (pbyData) // have data to save
|
||||
{
|
||||
LPBYTE p = pbyData;
|
||||
while (dwFileSize > 0 && dwStartAddr <= 0xFFFFF)
|
||||
{
|
||||
Nwrite(p++,dwStartAddr++,1);
|
||||
--dwFileSize;
|
||||
}
|
||||
}
|
||||
|
||||
free(pbyData);
|
||||
}
|
||||
CloseHandle(hFile);
|
||||
return TRUE;
|
||||
return pbyData != NULL;
|
||||
}
|
||||
|
||||
//
|
||||
// write memory data to file
|
||||
//
|
||||
static BOOL SaveMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,DWORD dwEndAddr)
|
||||
static BOOL SaveMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,DWORD dwEndAddr,UINT uBitMode)
|
||||
{
|
||||
HANDLE hFile;
|
||||
DWORD dwAddr,dwWritten;
|
||||
BYTE byData;
|
||||
DWORD dwAddr,dwSend,dwWritten;
|
||||
BYTE byData[2];
|
||||
|
||||
hFile = CreateFile(lpszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||
if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file
|
||||
|
@ -3549,8 +3585,14 @@ static BOOL SaveMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,DWORD dwEndAddr)
|
|||
for (dwAddr = dwStartAddr; dwAddr <= dwEndAddr; dwAddr += 2)
|
||||
{
|
||||
_ASSERT(dwAddr <= 0xFFFFF);
|
||||
byData = Read2(dwAddr); // read byte in map mode
|
||||
WriteFile(hFile,&byData,sizeof(byData),&dwWritten,NULL);
|
||||
Npeek(byData,dwAddr,2); // read two nibble in map mode
|
||||
dwSend = 2; // send 2 nibble
|
||||
if (uBitMode == 0) // (0=8-bit, 1=4-bit)
|
||||
{
|
||||
byData[0] = byData[0]|(byData[1]<<4);
|
||||
dwSend = 1; // send 1 byte
|
||||
}
|
||||
WriteFile(hFile,&byData,dwSend,&dwWritten,NULL);
|
||||
}
|
||||
|
||||
CloseHandle(hFile);
|
||||
|
@ -3564,9 +3606,14 @@ static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
{
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
DWORD dwStartAddr;
|
||||
int nButton;
|
||||
UINT uBitMode;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
CheckDlgButton(hDlg,IDC_DEBUG_DATA_LOAD_ABIT,BST_CHECKED);
|
||||
return TRUE;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
|
@ -3586,8 +3633,14 @@ static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
|
||||
_ASSERT(dwStartAddr <= 0xFFFFF);
|
||||
|
||||
for (nButton = IDC_DEBUG_DATA_LOAD_8BIT; nButton <= IDC_DEBUG_DATA_LOAD_ABIT; ++nButton)
|
||||
{
|
||||
if (IsDlgButtonChecked(hDlg,nButton) == BST_CHECKED)
|
||||
break;
|
||||
}
|
||||
uBitMode = (UINT) (nButton - IDC_DEBUG_DATA_LOAD_8BIT);
|
||||
// load memory dump file
|
||||
if (!LoadMemData(szFilename,dwStartAddr))
|
||||
if (!LoadMemData(szFilename,dwStartAddr,uBitMode))
|
||||
return FALSE;
|
||||
|
||||
// update memory window
|
||||
|
@ -3617,9 +3670,13 @@ static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
{
|
||||
TCHAR szFilename[MAX_PATH];
|
||||
DWORD dwStartAddr,dwEndAddr;
|
||||
UINT uBitMode;
|
||||
|
||||
switch (message)
|
||||
{
|
||||
case WM_INITDIALOG:
|
||||
CheckDlgButton(hDlg,IDC_DEBUG_DATA_SAVE_8BIT,BST_CHECKED);
|
||||
return TRUE;
|
||||
case WM_COMMAND:
|
||||
switch(LOWORD(wParam))
|
||||
{
|
||||
|
@ -3643,8 +3700,9 @@ static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPA
|
|||
_ASSERT(dwStartAddr <= 0xFFFFF);
|
||||
_ASSERT(dwEndAddr <= 0xFFFFF);
|
||||
|
||||
uBitMode = IsDlgButtonChecked(hDlg,IDC_DEBUG_DATA_SAVE_4BIT);
|
||||
// save memory dump file
|
||||
if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr))
|
||||
if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr,uBitMode))
|
||||
return FALSE;
|
||||
|
||||
// no break
|
||||
|
|
|
@ -1,101 +0,0 @@
|
|||
/*
|
||||
* external.c
|
||||
*
|
||||
* This file is part of Emu48
|
||||
*
|
||||
* Copyright (C) 1995 Sebastien Carlier
|
||||
*
|
||||
*/
|
||||
#include "pch.h"
|
||||
#include "Emu48.h"
|
||||
#include "ops.h"
|
||||
|
||||
#define SAMPLES_PER_SEC 44100 // sound sampling rate
|
||||
|
||||
//| 38G | 39G | 40G | 48SX | 48GX | 49G | Name
|
||||
//#F0E4F #80F0F #80F0F #706D2 #80850 #80F0F =SFLAG53_56
|
||||
|
||||
// memory address for flags -53 to -56
|
||||
// CdB for HP: add apples beep management
|
||||
#define SFLAG53_56 ( (cCurrentRomType=='6') \
|
||||
? 0xE0E4F \
|
||||
: ( (cCurrentRomType=='A') \
|
||||
? 0xF0E4F \
|
||||
: ( (cCurrentRomType!='E' && cCurrentRomType!='X' && cCurrentRomType!='P' && cCurrentRomType!='2' && cCurrentRomType!='Q') \
|
||||
? ( (cCurrentRomType=='S') \
|
||||
? 0x706D2 \
|
||||
: 0x80850 \
|
||||
) \
|
||||
: 0x80F0F \
|
||||
) \
|
||||
) \
|
||||
)
|
||||
|
||||
VOID External(CHIPSET* w) // Beep patch
|
||||
{
|
||||
BYTE fbeep;
|
||||
DWORD freq,dur;
|
||||
|
||||
freq = Npack(w->D,5); // frequency in Hz
|
||||
dur = Npack(w->C,5); // duration in ms
|
||||
Nread(&fbeep,SFLAG53_56,1); // fetch system flags -53 to -56
|
||||
|
||||
w->carry = TRUE; // setting of no beep
|
||||
if (!(fbeep & 0x8) && freq) // bit -56 clear and frequency > 0 Hz
|
||||
{
|
||||
if (freq > 4400) freq = 4400; // high limit of HP (SX)
|
||||
|
||||
SoundBeep(freq,dur); // beeping
|
||||
|
||||
// estimate cpu cycles for beeping time (2MHz / 4MHz)
|
||||
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
|
||||
|
||||
// original routine return with...
|
||||
w->P = 0; // P=0
|
||||
w->intk = TRUE; // INTON
|
||||
w->carry = FALSE; // RTNCC
|
||||
}
|
||||
w->pc = rstkpop();
|
||||
return;
|
||||
}
|
||||
|
||||
VOID RCKBp(CHIPSET* w) // ROM Check Beep patch
|
||||
{
|
||||
DWORD dw2F,dwCpuFreq;
|
||||
DWORD freq,dur;
|
||||
BYTE f,d;
|
||||
|
||||
f = w->C[1]; // f = freq ctl
|
||||
d = w->C[0]; // d = duration ctl
|
||||
|
||||
if (cCurrentRomType == 'S') // Clarke chip with 48S ROM
|
||||
{
|
||||
// CPU strobe frequency @ RATE 14 = 1.97MHz
|
||||
dwCpuFreq = ((14 + 1) * 524288) >> 2;
|
||||
|
||||
dw2F = f * 126 + 262; // F=f*63+131
|
||||
}
|
||||
else // York chip with 48G and later ROM
|
||||
{
|
||||
// CPU strobe frequency @ RATE 27 = 3.67MHz
|
||||
// CPU strobe frequency @ RATE 29 = 3.93MHz
|
||||
dwCpuFreq = ((27 + 1) * 524288) >> 2;
|
||||
|
||||
dw2F = f * 180 + 367; // F=f*90+183.5
|
||||
}
|
||||
|
||||
freq = dwCpuFreq / dw2F;
|
||||
dur = (dw2F * (256 - 16 * d)) * 1000 / 2 / dwCpuFreq;
|
||||
|
||||
if (freq > 4400) freq = 4400; // high limit of HP
|
||||
|
||||
SoundBeep(freq,dur); // beeping
|
||||
|
||||
// estimate cpu cycles for beeping time (2MHz / 4MHz)
|
||||
w->cycles += dur * ((cCurrentRomType=='S') ? 2000 : 4000);
|
||||
|
||||
w->P = 0; // P=0
|
||||
w->carry = FALSE; // RTNCC
|
||||
w->pc = rstkpop();
|
||||
return;
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -664,7 +664,7 @@ which is possible in case of only 0 or 1 present symbols. */
|
|||
static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
||||
static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/
|
||||
static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u;
|
||||
unsigned i, numpresent, pointer, size; /*total table size*/
|
||||
size_t i, numpresent, pointer, size; /*total table size*/
|
||||
unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned));
|
||||
if(!maxlens) return 83; /*alloc fail*/
|
||||
|
||||
|
@ -683,7 +683,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
|||
size = headsize;
|
||||
for(i = 0; i < headsize; ++i) {
|
||||
unsigned l = maxlens[i];
|
||||
if(l > FIRSTBITS) size += (1u << (l - FIRSTBITS));
|
||||
if(l > FIRSTBITS) size += (((size_t)1) << (l - FIRSTBITS));
|
||||
}
|
||||
tree->table_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len));
|
||||
tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value));
|
||||
|
@ -701,8 +701,8 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
|||
unsigned l = maxlens[i];
|
||||
if(l <= FIRSTBITS) continue;
|
||||
tree->table_len[i] = l;
|
||||
tree->table_value[i] = pointer;
|
||||
pointer += (1u << (l - FIRSTBITS));
|
||||
tree->table_value[i] = (unsigned short)pointer;
|
||||
pointer += (((size_t)1) << (l - FIRSTBITS));
|
||||
}
|
||||
lodepng_free(maxlens);
|
||||
|
||||
|
@ -726,7 +726,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
|||
unsigned index = reverse | (j << l);
|
||||
if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
|
||||
tree->table_len[index] = l;
|
||||
tree->table_value[index] = i;
|
||||
tree->table_value[index] = (unsigned short)i;
|
||||
}
|
||||
} else {
|
||||
/*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/
|
||||
|
@ -743,7 +743,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
|||
unsigned reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */
|
||||
unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS)));
|
||||
tree->table_len[index2] = l;
|
||||
tree->table_value[index2] = i;
|
||||
tree->table_value[index2] = (unsigned short)i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2886,7 +2886,7 @@ static unsigned lodepng_chunk_createv(ucvector* out,
|
|||
}
|
||||
|
||||
unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize,
|
||||
unsigned length, const char* type, const unsigned char* data) {
|
||||
size_t length, const char* type, const unsigned char* data) {
|
||||
ucvector v = ucvector_init(*out, *outsize);
|
||||
unsigned error = lodepng_chunk_createv(&v, length, type, data);
|
||||
*out = v.data;
|
||||
|
@ -3363,7 +3363,7 @@ unsigned lodepng_info_copy(LodePNGInfo* dest, const LodePNGInfo* source) {
|
|||
static void addColorBits(unsigned char* out, size_t index, unsigned bits, unsigned in) {
|
||||
unsigned m = bits == 1 ? 7 : bits == 2 ? 3 : 1; /*8 / bits - 1*/
|
||||
/*p = the partial index in the byte, e.g. with 4 palettebits it is 0 for first half or 1 for second half*/
|
||||
unsigned p = (unsigned)index & m;
|
||||
unsigned p = (unsigned) index & m;
|
||||
in &= (1u << bits) - 1u; /*filter out any other bits of the input value*/
|
||||
in = in << (bits * (m - p));
|
||||
if(p == 0) out[index * bits / 8u] = in;
|
||||
|
@ -5889,7 +5889,7 @@ static size_t ilog2i(size_t i) {
|
|||
l = ilog2(i);
|
||||
/* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u)
|
||||
linearly approximates the missing fractional part multiplied by i */
|
||||
return i * l + ((i - ((size_t) 1u << l)) << 1u);
|
||||
return i * l + ((i - (((size_t)1) << l)) << 1u);
|
||||
}
|
||||
|
||||
static unsigned filter(unsigned char* out, const unsigned char* in, unsigned w, unsigned h,
|
||||
|
|
|
@ -1001,7 +1001,7 @@ and data separately. The type is a 4-letter string.
|
|||
The out variable and outsize are updated to reflect the new reallocated buffer.
|
||||
Returne error code (0 if it went ok)
|
||||
*/
|
||||
unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, unsigned length,
|
||||
unsigned lodepng_chunk_create(unsigned char** out, size_t* outsize, size_t length,
|
||||
const char* type, const unsigned char* data);
|
||||
|
||||
|
||||
|
|
|
@ -1002,9 +1002,9 @@ static DWORD ReadT2Acc(VOID)
|
|||
// maybe CPU speed measurement, slow down the next 10 CPU opcodes
|
||||
if (dwCycDif < 150)
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
nOpcSlow = 10; // slow down next 10 opcodes
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
|
@ -1146,9 +1146,9 @@ VOID ReadIO(BYTE *a, DWORD d, DWORD s, BOOL bUpdate)
|
|||
// CPU running with max. speed we may get a timeout overflow
|
||||
// -> to avoid this slow down CPU speed on transmit buffer full
|
||||
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
EnterCriticalSection(&csSlowLock);
|
||||
{
|
||||
InitAdjustSpeed(); // init variables if necessary
|
||||
nOpcSlow = 10; // slow down next 10 opcodes
|
||||
}
|
||||
LeaveCriticalSection(&csSlowLock);
|
||||
|
|
|
@ -121,62 +121,67 @@
|
|||
#define IDC_DEBUG_DATA_BUT 1084
|
||||
#define IDC_DEBUG_DATA_STARTADDR 1085
|
||||
#define IDC_DEBUG_DATA_ENDADDR 1086
|
||||
#define IDC_DEBUG_SET_SYMB 1087
|
||||
#define IDC_DEBUG_SET_MODEL 1088
|
||||
#define IDC_DEBUG_SET_FILE 1089
|
||||
#define IDC_DEBUG_SET_BROWSE 1090
|
||||
#define IDC_DEBUG_STACK 1091
|
||||
#define IDC_STATIC_BREAKPOINT 1092
|
||||
#define IDC_BREAKEDIT_ADD 1093
|
||||
#define IDC_BREAKEDIT_DELETE 1094
|
||||
#define IDC_BREAKEDIT_WND 1095
|
||||
#define IDC_STATIC_MMU 1096
|
||||
#define IDC_MMU_IO_A 1097
|
||||
#define IDC_MMU_NCE2_A 1098
|
||||
#define IDC_MMU_CE1_A 1099
|
||||
#define IDC_MMU_CE2_A 1100
|
||||
#define IDC_MMU_NCE3_A 1101
|
||||
#define IDC_MMU_IO_S 1102
|
||||
#define IDC_MMU_CE1_S 1103
|
||||
#define IDC_MMU_CE2_S 1104
|
||||
#define IDC_MMU_NCE2_S 1105
|
||||
#define IDC_MMU_NCE3_S 1106
|
||||
#define IDC_STATIC_MISC 1107
|
||||
#define IDC_MISC_BS_TXT 1108
|
||||
#define IDC_INSTR_TEXT 1109
|
||||
#define IDC_INSTR_CODE 1110
|
||||
#define IDC_INSTR_COPY 1111
|
||||
#define IDC_INSTR_CLEAR 1112
|
||||
#define IDC_PROFILE_LASTCYCLES 1113
|
||||
#define IDC_PROFILE_LASTTIME 1114
|
||||
#define IDC_BPCODE 1115
|
||||
#define IDC_BPRPL 1116
|
||||
#define IDC_BPACCESS 1117
|
||||
#define IDC_BPREAD 1118
|
||||
#define IDC_BPWRITE 1119
|
||||
#define IDC_FIND_DATA 1120
|
||||
#define IDC_FIND_PREV 1121
|
||||
#define IDC_FIND_NEXT 1122
|
||||
#define IDC_FIND_ASCII 1123
|
||||
#define IDC_ADDR20_24 1124
|
||||
#define IDC_ADDR25_27 1125
|
||||
#define IDC_ADDR28_29 1126
|
||||
#define IDC_ADDR30_34 1127
|
||||
#define IDC_RPLVIEW_DATA 1128
|
||||
#define IDC_MACRO_SLOW 1129
|
||||
#define IDC_MACRO_FAST 1130
|
||||
#define IDC_MACRO_SLIDER 1131
|
||||
#define IDC_MACRO_REAL 1132
|
||||
#define IDC_MACRO_MANUAL 1133
|
||||
#define IDC_SOUND_SLIDER 1134
|
||||
#define IDC_SOUND_DEVICE 1135
|
||||
#define IDC_TRACE_FILE 1136
|
||||
#define IDC_TRACE_BROWSE 1137
|
||||
#define IDC_TRACE_NEW 1138
|
||||
#define IDC_TRACE_APPEND 1139
|
||||
#define IDC_TRACE_REGISTER 1140
|
||||
#define IDC_TRACE_MMU 1141
|
||||
#define IDC_TRACE_OPCODE 1142
|
||||
#define IDC_DEBUG_DATA_SAVE_8BIT 1087
|
||||
#define IDC_DEBUG_DATA_SAVE_4BIT 1088
|
||||
#define IDC_DEBUG_DATA_LOAD_8BIT 1089
|
||||
#define IDC_DEBUG_DATA_LOAD_4BIT 1090
|
||||
#define IDC_DEBUG_DATA_LOAD_ABIT 1091
|
||||
#define IDC_DEBUG_SET_SYMB 1092
|
||||
#define IDC_DEBUG_SET_MODEL 1093
|
||||
#define IDC_DEBUG_SET_FILE 1094
|
||||
#define IDC_DEBUG_SET_BROWSE 1095
|
||||
#define IDC_DEBUG_STACK 1096
|
||||
#define IDC_STATIC_BREAKPOINT 1097
|
||||
#define IDC_BREAKEDIT_ADD 1098
|
||||
#define IDC_BREAKEDIT_DELETE 1099
|
||||
#define IDC_BREAKEDIT_WND 1100
|
||||
#define IDC_STATIC_MMU 1101
|
||||
#define IDC_MMU_IO_A 1102
|
||||
#define IDC_MMU_NCE2_A 1103
|
||||
#define IDC_MMU_CE1_A 1104
|
||||
#define IDC_MMU_CE2_A 1105
|
||||
#define IDC_MMU_NCE3_A 1106
|
||||
#define IDC_MMU_IO_S 1107
|
||||
#define IDC_MMU_CE1_S 1108
|
||||
#define IDC_MMU_CE2_S 1109
|
||||
#define IDC_MMU_NCE2_S 1110
|
||||
#define IDC_MMU_NCE3_S 1111
|
||||
#define IDC_STATIC_MISC 1112
|
||||
#define IDC_MISC_BS_TXT 1113
|
||||
#define IDC_INSTR_TEXT 1114
|
||||
#define IDC_INSTR_CODE 1115
|
||||
#define IDC_INSTR_COPY 1116
|
||||
#define IDC_INSTR_CLEAR 1117
|
||||
#define IDC_PROFILE_LASTCYCLES 1118
|
||||
#define IDC_PROFILE_LASTTIME 1119
|
||||
#define IDC_BPCODE 1120
|
||||
#define IDC_BPRPL 1121
|
||||
#define IDC_BPACCESS 1122
|
||||
#define IDC_BPREAD 1123
|
||||
#define IDC_BPWRITE 1124
|
||||
#define IDC_FIND_DATA 1125
|
||||
#define IDC_FIND_PREV 1126
|
||||
#define IDC_FIND_NEXT 1127
|
||||
#define IDC_FIND_ASCII 1128
|
||||
#define IDC_ADDR20_24 1129
|
||||
#define IDC_ADDR25_27 1130
|
||||
#define IDC_ADDR28_29 1131
|
||||
#define IDC_ADDR30_34 1132
|
||||
#define IDC_RPLVIEW_DATA 1133
|
||||
#define IDC_MACRO_SLOW 1134
|
||||
#define IDC_MACRO_FAST 1135
|
||||
#define IDC_MACRO_SLIDER 1136
|
||||
#define IDC_MACRO_REAL 1137
|
||||
#define IDC_MACRO_MANUAL 1138
|
||||
#define IDC_SOUND_SLIDER 1139
|
||||
#define IDC_SOUND_DEVICE 1140
|
||||
#define IDC_TRACE_FILE 1141
|
||||
#define IDC_TRACE_BROWSE 1142
|
||||
#define IDC_TRACE_NEW 1143
|
||||
#define IDC_TRACE_APPEND 1144
|
||||
#define IDC_TRACE_REGISTER 1145
|
||||
#define IDC_TRACE_MMU 1146
|
||||
#define IDC_TRACE_OPCODE 1147
|
||||
#define ID_FILE_NEW 40001
|
||||
#define ID_FILE_OPEN 40002
|
||||
#define ID_FILE_SAVE 40003
|
||||
|
@ -257,7 +262,7 @@
|
|||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 131
|
||||
#define _APS_NEXT_COMMAND_VALUE 40074
|
||||
#define _APS_NEXT_CONTROL_VALUE 1143
|
||||
#define _APS_NEXT_CONTROL_VALUE 1148
|
||||
#define _APS_NEXT_SYMED_VALUE 109
|
||||
#endif
|
||||
#endif
|
||||
|
|
|
@ -241,8 +241,8 @@ VOID RebuildRomCrc(VOID)
|
|||
{
|
||||
// has no Crc
|
||||
}
|
||||
// HP49G
|
||||
if (cCurrentRomType == 'X' && dwRomSize == _KB(2048))
|
||||
// HP48GII/49G+/50G/49G
|
||||
if ((strchr("2QX",cCurrentRomType)) && dwRomSize == _KB(2048))
|
||||
{
|
||||
CorrectAllFlashPages(); // go through all pages
|
||||
}
|
||||
|
|
|
@ -104,7 +104,6 @@ BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
|
|||
|
||||
LPCTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort;
|
||||
|
||||
_ASSERT(Chipset.IORam[IOC] & SON); // UART on
|
||||
CommClose(); // close port if already open
|
||||
|
||||
dwBytesRead = 0L; // no bytes received
|
||||
|
|
|
@ -182,23 +182,24 @@ VOID ReadSettings(VOID)
|
|||
disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
|
||||
disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
|
||||
// Emulator
|
||||
bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle);
|
||||
bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu);
|
||||
bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
|
||||
bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
|
||||
bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove);
|
||||
bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance);
|
||||
bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed);
|
||||
dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles);
|
||||
dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles);
|
||||
dwGPCycles = ReadInt(_T("Emulator"),_T("GPCycles"),dwGPCycles); // CdB for HP: add apples
|
||||
dwG2Cycles = ReadInt(_T("Emulator"),_T("G2Cycles"),dwG2Cycles); // CdB for HP: add apples
|
||||
dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay);
|
||||
dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay);
|
||||
bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
|
||||
uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
||||
dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
||||
dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
||||
bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle);
|
||||
bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu);
|
||||
bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
|
||||
bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
|
||||
bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove);
|
||||
bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance);
|
||||
bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed);
|
||||
dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles);
|
||||
dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles);
|
||||
dwGPCycles = ReadInt(_T("Emulator"),_T("GPCycles"),dwGPCycles); // CdB for HP: add apples
|
||||
dwG2Cycles = ReadInt(_T("Emulator"),_T("G2Cycles"),dwG2Cycles); // CdB for HP: add apples
|
||||
dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay);
|
||||
dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay);
|
||||
bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
|
||||
uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
||||
dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
||||
dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
||||
bLocaleDecimalPoint = ReadInt(_T("Emulator"),_T("LocaleDecimalPoint"),bLocaleDecimalPoint);
|
||||
// LowBat
|
||||
bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
|
||||
// Macro
|
||||
|
@ -254,6 +255,7 @@ VOID WriteSettings(VOID)
|
|||
WriteInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
||||
WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
||||
WriteInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
||||
WriteInt(_T("Emulator"),_T("LocaleDecimalPoint"),bLocaleDecimalPoint);
|
||||
// LowBat
|
||||
WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
|
||||
// Macro
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#define DOCSTR 0x02A2C // String
|
||||
|
||||
BOOL bDetectClpObject = TRUE; // try to detect clipboard object
|
||||
BOOL bLocaleDecimalPoint = FALSE; // use decimal point character from calculator
|
||||
|
||||
//################
|
||||
//#
|
||||
|
@ -26,6 +27,100 @@ BOOL bDetectClpObject = TRUE; // try to detect clipboard object
|
|||
//#
|
||||
//################
|
||||
|
||||
//
|
||||
// check if cGroup character is thousands separator
|
||||
//
|
||||
static BOOL CheckThousandGroup(LPCTSTR cp,TCHAR cGroup)
|
||||
{
|
||||
UINT uLastPos;
|
||||
UINT i;
|
||||
|
||||
// get decimal point
|
||||
CONST TCHAR cDecimalPoint = cGroup ^ (_T('.') ^ _T(','));
|
||||
|
||||
BOOL bFound = FALSE; // 1st separator not found
|
||||
BOOL bPosOK = TRUE;
|
||||
|
||||
for (i = 0; bPosOK && cp[i] != cDecimalPoint && cp[i] != 0; ++i)
|
||||
{
|
||||
if (cp[i] == cGroup) // found separator
|
||||
{
|
||||
if (bFound)
|
||||
{
|
||||
// verify separator position
|
||||
bPosOK = (uLastPos + 4 == i);
|
||||
}
|
||||
|
||||
uLastPos = i; // last position of separator
|
||||
bFound = TRUE; // separator found
|
||||
}
|
||||
}
|
||||
|
||||
// check last grouping
|
||||
return bPosOK && bFound && (uLastPos + 4 == i);
|
||||
}
|
||||
|
||||
//
|
||||
// get decimal point from clipboard
|
||||
//
|
||||
static TCHAR GetClpbrdDecimalPoint(LPCTSTR cp)
|
||||
{
|
||||
TCHAR cDec = 0; // default for invalid decimal point detection
|
||||
|
||||
TCHAR cLast = 0; // last decimal point
|
||||
UINT uPoint = 0; // no. of points
|
||||
UINT uComma = 0; // no. of commas
|
||||
|
||||
LPCTSTR p;
|
||||
for (p = cp; *p; ++p) // count '.' and ',' characters
|
||||
{
|
||||
if (*p == _T('.'))
|
||||
{
|
||||
cLast = *p; // last occurance
|
||||
++uPoint;
|
||||
}
|
||||
if (*p == _T(','))
|
||||
{
|
||||
cLast = *p; // last occurance
|
||||
++uComma;
|
||||
}
|
||||
}
|
||||
|
||||
if (uComma == 0 && uPoint == 0) // none of both
|
||||
{
|
||||
cDec = _T('.');
|
||||
}
|
||||
else if (uComma == 1 && uPoint == 0) // one single ','
|
||||
{
|
||||
cDec = _T(',');
|
||||
}
|
||||
else if (uComma == 0 && uPoint == 1) // one single '.'
|
||||
{
|
||||
cDec = _T('.');
|
||||
}
|
||||
else if (uComma == 1 && uPoint == 1) // one single ',' and '.'
|
||||
{
|
||||
// change from ',' to '.' or vice versa
|
||||
const TCHAR cFirst = cLast ^ (_T('.') ^ _T(','));
|
||||
|
||||
if (CheckThousandGroup(cp,cFirst)) // check if 1st character is grouped
|
||||
{
|
||||
cDec = cLast;
|
||||
}
|
||||
}
|
||||
// multiple grouped ',' and single '.'
|
||||
else if (uComma > 1 && uPoint == 1 && CheckThousandGroup(cp,_T(',')))
|
||||
{
|
||||
cDec = _T('.');
|
||||
}
|
||||
// multiple grouped '.' and single ','
|
||||
else if (uComma == 1 && uPoint > 1 && CheckThousandGroup(cp,_T('.')))
|
||||
{
|
||||
cDec = _T(',');
|
||||
}
|
||||
return cDec;
|
||||
}
|
||||
|
||||
static LPTSTR Trim(LPCTSTR cp)
|
||||
{
|
||||
LPCTSTR pcWs = _T(" \t\n\r"); // valid whitespace characters
|
||||
|
@ -238,22 +333,23 @@ static INT RPL_GetBcd(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHAR cD
|
|||
|
||||
static __inline INT SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,LPBYTE pbyNum,INT nSize)
|
||||
{
|
||||
TCHAR cVc[] = _T(".0123456789eE+-");
|
||||
TCHAR cVc[] = _T(",.0123456789eE+-");
|
||||
|
||||
BYTE byNum[80];
|
||||
INT i,nIp,nDp,nMaxExp;
|
||||
LONG lExp;
|
||||
|
||||
cVc[0] = cDec; // replace decimal char
|
||||
// get thousand separator
|
||||
const TCHAR cThousand = cDec ^ (_T('.') ^ _T(','));
|
||||
|
||||
if ( nMantLen + nExpLen >= nSize // destination buffer too small
|
||||
|| !*cp // empty string
|
||||
|| _tcsspn(cp,cVc) != (SIZE_T) lstrlen(cp) // real contain only these numbers
|
||||
|| _tcsspn(cp,cVc) != (SIZE_T) lstrlen(cp) // real doesn't contain only these numbers
|
||||
|| (SIZE_T) lstrlen(cp) >= ARRAYSIZEOF(byNum)) // ignore too long reals
|
||||
return 0;
|
||||
|
||||
byNum[0] = (*cp != _T('-')) ? 0 : 9; // set sign nibble
|
||||
if (*cp == _T('-') || *cp == _T('+')) // skip sign character
|
||||
if (*cp == _T('-') || *cp == _T('+')) // skip sign nibble
|
||||
cp++;
|
||||
|
||||
// only '.', '0' .. '9' are valid here
|
||||
|
@ -264,8 +360,13 @@ static __inline INT SetBcd(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,
|
|||
if (*cp != cDec) // no decimal point
|
||||
{
|
||||
// count integer part
|
||||
while (*cp >= _T('0') && *cp <= _T('9'))
|
||||
byNum[++nIp] = *cp++ - _T('0');
|
||||
for (; (*cp >= _T('0') && *cp <= _T('9')) || *cp == cThousand; ++cp)
|
||||
{
|
||||
if (*cp != cThousand) // not thousand separator
|
||||
{
|
||||
byNum[++nIp] = *cp - _T('0');
|
||||
}
|
||||
}
|
||||
if (!nIp) return 0;
|
||||
}
|
||||
|
||||
|
@ -376,8 +477,8 @@ static INT RPL_GetComplex(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHA
|
|||
TCHAR cSep;
|
||||
|
||||
cSep = (cDec == _T('.')) // current separator
|
||||
? _T(',') // radix mark '.' -> ',' separator
|
||||
: _T(';'); // radix mark ',' -> ';' separator
|
||||
? _T(',') // decimal point '.' -> ',' separator
|
||||
: _T(';'); // decimal comma ',' -> ';' separator
|
||||
|
||||
nPos = 0; // write buffer position
|
||||
|
||||
|
@ -420,8 +521,8 @@ static INT RPL_SetComplex(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,L
|
|||
nLen = 0; // read data length
|
||||
|
||||
cSep = (cDec == _T('.')) // current separator
|
||||
? _T(',') // radix mark '.' -> ',' separator
|
||||
: _T(';'); // radix mark ',' -> ';' separator
|
||||
? _T(',') // decimal point '.' -> ',' separator
|
||||
: _T(';'); // decimal comma ',' -> ';' separator
|
||||
|
||||
if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string
|
||||
{
|
||||
|
@ -468,8 +569,14 @@ static INT RPL_SetComplex(LPCTSTR cp,INT nMantLen,INT nExpLen,CONST TCHAR cDec,L
|
|||
|
||||
static TCHAR GetRadix(VOID)
|
||||
{
|
||||
// get locale decimal point
|
||||
// GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,&cDecimal,1);
|
||||
if (bLocaleDecimalPoint) // use Windows Locale decimal point character
|
||||
{
|
||||
TCHAR cDecimal[2];
|
||||
|
||||
// get locale decimal point with zero terminator
|
||||
GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,cDecimal,2);
|
||||
return cDecimal[0];
|
||||
}
|
||||
|
||||
return RPL_GetSystemFlag(fnRadix) ? _T(',') : _T('.');
|
||||
}
|
||||
|
@ -683,9 +790,11 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
|||
|
||||
if ((lpstrClipdata = (LPCTSTR) GlobalLock(hClipObj)))
|
||||
{
|
||||
TCHAR cDec;
|
||||
BYTE byNumber[128];
|
||||
DWORD dwAddress;
|
||||
INT s;
|
||||
|
||||
INT s = 0; // no valid object
|
||||
|
||||
do
|
||||
{
|
||||
|
@ -715,9 +824,14 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
|||
}
|
||||
}
|
||||
|
||||
// try to convert string to real format
|
||||
_ASSERT(16 <= ARRAYSIZEOF(byNumber));
|
||||
s = RPL_SetBcd(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber));
|
||||
cDec = GetClpbrdDecimalPoint(lpstrClipdata);
|
||||
|
||||
if (cDec) // valid decimal point
|
||||
{
|
||||
// try to convert string to real format
|
||||
_ASSERT(16 <= ARRAYSIZEOF(byNumber));
|
||||
s = RPL_SetBcd(lpstrClipdata,12,3,cDec,byNumber,sizeof(byNumber));
|
||||
}
|
||||
|
||||
if (s > 0) // is a real number
|
||||
{
|
||||
|
@ -736,9 +850,14 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
|||
break;
|
||||
}
|
||||
|
||||
// search for ';' as separator
|
||||
cDec = (_tcschr(lpstrClipdata,_T(';')) != NULL)
|
||||
? _T(',') // decimal comma
|
||||
: _T('.'); // decimal point
|
||||
|
||||
// try to convert string to complex format
|
||||
_ASSERT(32 <= ARRAYSIZEOF(byNumber));
|
||||
s = RPL_SetComplex(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber));
|
||||
s = RPL_SetComplex(lpstrClipdata,12,3,cDec,byNumber,sizeof(byNumber));
|
||||
|
||||
if (s > 0) // is a real complex
|
||||
{
|
||||
|
|
|
@ -247,7 +247,7 @@ VOID SetHP48Time(VOID) // set date and time
|
|||
ULONGLONG ticks, time;
|
||||
DWORD dw;
|
||||
WORD crc, i;
|
||||
BYTE p[4];
|
||||
LPBYTE pbyTime;
|
||||
|
||||
_ASSERT(sizeof(ULONGLONG) == 8); // check size of datatype
|
||||
|
||||
|
@ -282,29 +282,23 @@ VOID SetHP48Time(VOID) // set date and time
|
|||
time = ticks; // save for calc. timeout
|
||||
time += OFF_TIME; // add 10 min for auto off
|
||||
|
||||
dw = RPLTIME; // HP addresses for clock in port0
|
||||
pbyTime = Port0 + RPLTIME; // HP addresses for clock in port0
|
||||
|
||||
crc = 0x0; // reset crc value
|
||||
for (i = 0; i < 13; ++i, ++dw) // write date and time
|
||||
for (i = 0; i < 13; ++i) // write date and time
|
||||
{
|
||||
*p = (BYTE) ticks & 0xf;
|
||||
crc = (crc >> 4) ^ (((crc ^ ((WORD) *p)) & 0xf) * 0x1081);
|
||||
Port0[dw] = *p; // always store in port0
|
||||
*pbyTime = (BYTE) ticks & 0xf; // time
|
||||
crc = UpCRC(crc,*pbyTime);
|
||||
ticks >>= 4;
|
||||
}
|
||||
|
||||
Nunpack(p,crc,4); // write crc
|
||||
memcpy(Port0+dw,p,4); // always store in port0
|
||||
|
||||
dw += 4; // HP addresses for timeout
|
||||
|
||||
for (i = 0; i < 13; ++i, ++dw) // write time for auto off
|
||||
{
|
||||
Port0[dw] = (BYTE) time & 0xf; // always store in port0
|
||||
pbyTime[13+4] = (BYTE) time & 0xf; // auto off
|
||||
time >>= 4;
|
||||
++pbyTime;
|
||||
}
|
||||
|
||||
Port0[dw] = 0xf; // always store in port0
|
||||
Nunpack(pbyTime,crc,4); // write crc
|
||||
|
||||
pbyTime[13+4] = 0xf;
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,13 +22,10 @@ VOID ResetUdp(VOID)
|
|||
|
||||
BOOL SendByteUdp(BYTE byData)
|
||||
{
|
||||
WSADATA wsd;
|
||||
SOCKET sClient;
|
||||
|
||||
BOOL bErr = TRUE;
|
||||
|
||||
VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0);
|
||||
|
||||
// IP address not specified
|
||||
if (sServer.sin_addr.s_addr == INADDR_NONE)
|
||||
{
|
||||
|
@ -72,7 +69,5 @@ BOOL SendByteUdp(BYTE byData)
|
|||
bErr = sendto(sClient, (LPCCH) &byData, sizeof(byData), 0, (LPSOCKADDR) &sServer, sizeof(sServer)) == SOCKET_ERROR;
|
||||
closesocket(sClient);
|
||||
}
|
||||
|
||||
WSACleanup(); // cleanup network stack
|
||||
return bErr;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1199,9 +1199,12 @@ typedef struct tagCOPYDATASTRUCT {
|
|||
PVOID lpData;
|
||||
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
|
||||
|
||||
|
||||
|
||||
|
||||
// Locale info
|
||||
#define LOCALE_USER_DEFAULT 1024
|
||||
#define LOCALE_SDECIMAL 0x0000000E // decimal separator, eg "." for 1,234.00
|
||||
typedef DWORD LCID;
|
||||
typedef DWORD LCTYPE;
|
||||
extern int GetLocaleInfo(LCID Locale, LCTYPE LCType, LPSTR lpLCData, int cchData);
|
||||
|
||||
|
||||
#ifdef UNICODE
|
||||
|
|
|
@ -158,7 +158,9 @@ public class Serial {
|
|||
if(usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
|
||||
usbPermission = UsbPermission.Requested;
|
||||
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
|
||||
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(INTENT_ACTION_GRANT_USB), flags);
|
||||
Intent intent = new Intent(INTENT_ACTION_GRANT_USB);
|
||||
intent.setPackage(context.getPackageName());
|
||||
PendingIntent usbPermissionIntent = PendingIntent.getBroadcast(context, 0, intent, flags);
|
||||
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
|
||||
if(debug) Log.d(TAG, "Request permission");
|
||||
connectionStatus = "serial_connection_failed_user_has_not_given_permission";
|
||||
|
|
|
@ -8,13 +8,11 @@ package org.emulator.calculator.usbserial.driver;
|
|||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.util.Log;
|
||||
|
||||
import org.emulator.calculator.usbserial.util.HexDump;
|
||||
import org.emulator.calculator.usbserial.util.UsbUtils;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
|
@ -32,8 +30,6 @@ import java.util.Map;
|
|||
*/
|
||||
public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||
|
||||
public static final int USB_SUBCLASS_ACM = 2;
|
||||
|
||||
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
|
||||
|
||||
private final UsbDevice mDevice;
|
||||
|
@ -42,31 +38,21 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
public CdcAcmSerialDriver(UsbDevice device) {
|
||||
mDevice = device;
|
||||
mPorts = new ArrayList<>();
|
||||
int ports = countPorts(device);
|
||||
for (int port = 0; port < ports; port++) {
|
||||
mPorts.add(new CdcAcmSerialPort(mDevice, port));
|
||||
}
|
||||
if (mPorts.size() == 0) {
|
||||
mPorts.add(new CdcAcmSerialPort(mDevice, -1));
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public static boolean probe(UsbDevice device) {
|
||||
return countPorts(device) > 0;
|
||||
}
|
||||
|
||||
private static int countPorts(UsbDevice device) {
|
||||
int controlInterfaceCount = 0;
|
||||
int dataInterfaceCount = 0;
|
||||
for (int i = 0; i < device.getInterfaceCount(); i++) {
|
||||
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
|
||||
device.getInterface(i).getInterfaceSubclass() == USB_SUBCLASS_ACM)
|
||||
for( int i = 0; i < device.getInterfaceCount(); i++) {
|
||||
if(device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_COMM)
|
||||
controlInterfaceCount++;
|
||||
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
|
||||
if(device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
|
||||
dataInterfaceCount++;
|
||||
}
|
||||
return Math.min(controlInterfaceCount, dataInterfaceCount);
|
||||
for( int port = 0; port < Math.min(controlInterfaceCount, dataInterfaceCount); port++) {
|
||||
mPorts.add(new CdcAcmSerialPort(mDevice, port));
|
||||
}
|
||||
if(mPorts.size() == 0) {
|
||||
mPorts.add(new CdcAcmSerialPort(mDevice, -1));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,11 +95,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
|
||||
@Override
|
||||
protected void openInt() throws IOException {
|
||||
Log.d(TAG, "interfaces:");
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
Log.d(TAG, mDevice.getInterface(i).toString());
|
||||
}
|
||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||
if (mPortNumber == -1) {
|
||||
Log.d(TAG,"device might be castrated ACM device, trying single interface logic");
|
||||
openSingleInterface();
|
||||
|
@ -149,57 +131,38 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
|
||||
private void openInterface() throws IOException {
|
||||
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
|
||||
|
||||
int controlInterfaceCount = 0;
|
||||
int dataInterfaceCount = 0;
|
||||
mControlInterface = null;
|
||||
mDataInterface = null;
|
||||
int j = getInterfaceIdFromDescriptors();
|
||||
Log.d(TAG, "interface count=" + mDevice.getInterfaceCount() + ", IAD=" + j);
|
||||
if (j >= 0) {
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface usbInterface = mDevice.getInterface(i);
|
||||
if (usbInterface.getId() == j || usbInterface.getId() == j+1) {
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
|
||||
usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) {
|
||||
mControlIndex = usbInterface.getId();
|
||||
mControlInterface = usbInterface;
|
||||
}
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
|
||||
mDataInterface = usbInterface;
|
||||
}
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface usbInterface = mDevice.getInterface(i);
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM) {
|
||||
if(controlInterfaceCount == mPortNumber) {
|
||||
mControlIndex = i;
|
||||
mControlInterface = usbInterface;
|
||||
}
|
||||
controlInterfaceCount++;
|
||||
}
|
||||
}
|
||||
if (mControlInterface == null || mDataInterface == null) {
|
||||
Log.d(TAG, "no IAD fallback");
|
||||
int controlInterfaceCount = 0;
|
||||
int dataInterfaceCount = 0;
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface usbInterface = mDevice.getInterface(i);
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
|
||||
usbInterface.getInterfaceSubclass() == USB_SUBCLASS_ACM) {
|
||||
if (controlInterfaceCount == mPortNumber) {
|
||||
mControlIndex = usbInterface.getId();
|
||||
mControlInterface = usbInterface;
|
||||
}
|
||||
controlInterfaceCount++;
|
||||
}
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
|
||||
if (dataInterfaceCount == mPortNumber) {
|
||||
mDataInterface = usbInterface;
|
||||
}
|
||||
dataInterfaceCount++;
|
||||
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
|
||||
if(dataInterfaceCount == mPortNumber) {
|
||||
mDataInterface = usbInterface;
|
||||
}
|
||||
dataInterfaceCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if(mControlInterface == null) {
|
||||
throw new IOException("No control interface");
|
||||
}
|
||||
Log.d(TAG, "Control interface id " + mControlInterface.getId());
|
||||
Log.d(TAG, "Control iface=" + mControlInterface);
|
||||
|
||||
if (!mConnection.claimInterface(mControlInterface, true)) {
|
||||
throw new IOException("Could not claim control interface");
|
||||
}
|
||||
|
||||
mControlEndpoint = mControlInterface.getEndpoint(0);
|
||||
if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) {
|
||||
throw new IOException("Invalid control endpoint");
|
||||
|
@ -208,10 +171,12 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
if(mDataInterface == null) {
|
||||
throw new IOException("No data interface");
|
||||
}
|
||||
Log.d(TAG, "data interface id " + mDataInterface.getId());
|
||||
Log.d(TAG, "data iface=" + mDataInterface);
|
||||
|
||||
if (!mConnection.claimInterface(mDataInterface, true)) {
|
||||
throw new IOException("Could not claim data interface");
|
||||
}
|
||||
|
||||
for (int i = 0; i < mDataInterface.getEndpointCount(); i++) {
|
||||
UsbEndpoint ep = mDataInterface.getEndpoint(i);
|
||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
|
||||
|
@ -221,36 +186,6 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
private int getInterfaceIdFromDescriptors() {
|
||||
ArrayList<byte[]> descriptors = UsbUtils.getDescriptors(mConnection);
|
||||
Log.d(TAG, "USB descriptor:");
|
||||
for(byte[] descriptor : descriptors)
|
||||
Log.d(TAG, HexDump.toHexString(descriptor));
|
||||
|
||||
if (descriptors.size() > 0 &&
|
||||
descriptors.get(0).length == 18 &&
|
||||
descriptors.get(0)[1] == 1 && // bDescriptorType
|
||||
descriptors.get(0)[4] == (byte)(UsbConstants.USB_CLASS_MISC) && //bDeviceClass
|
||||
descriptors.get(0)[5] == 2 && // bDeviceSubClass
|
||||
descriptors.get(0)[6] == 1) { // bDeviceProtocol
|
||||
// is IAD device, see https://www.usb.org/sites/default/files/iadclasscode_r10.pdf
|
||||
int port = -1;
|
||||
for (int d = 1; d < descriptors.size(); d++) {
|
||||
if (descriptors.get(d).length == 8 &&
|
||||
descriptors.get(d)[1] == 0x0b && // bDescriptorType == IAD
|
||||
descriptors.get(d)[4] == UsbConstants.USB_CLASS_COMM && // bFunctionClass == CDC
|
||||
descriptors.get(d)[5] == USB_SUBCLASS_ACM) { // bFunctionSubClass == ACM
|
||||
port++;
|
||||
if (port == mPortNumber &&
|
||||
descriptors.get(d)[3] == 2) { // bInterfaceCount
|
||||
return descriptors.get(d)[2]; // bFirstInterface
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException {
|
||||
int len = mConnection.controlTransfer(
|
||||
USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000);
|
||||
|
@ -351,9 +286,42 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
return new LinkedHashMap<>();
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_ARDUINO,
|
||||
new int[] {
|
||||
UsbId.ARDUINO_UNO,
|
||||
UsbId.ARDUINO_UNO_R3,
|
||||
UsbId.ARDUINO_MEGA_2560,
|
||||
UsbId.ARDUINO_MEGA_2560_R3,
|
||||
UsbId.ARDUINO_SERIAL_ADAPTER,
|
||||
UsbId.ARDUINO_SERIAL_ADAPTER_R3,
|
||||
UsbId.ARDUINO_MEGA_ADK,
|
||||
UsbId.ARDUINO_MEGA_ADK_R3,
|
||||
UsbId.ARDUINO_LEONARDO,
|
||||
UsbId.ARDUINO_MICRO,
|
||||
});
|
||||
supportedDevices.put(UsbId.VENDOR_VAN_OOIJEN_TECH,
|
||||
new int[] {
|
||||
UsbId.VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL,
|
||||
});
|
||||
supportedDevices.put(UsbId.VENDOR_ATMEL,
|
||||
new int[] {
|
||||
UsbId.ATMEL_LUFA_CDC_DEMO_APP,
|
||||
});
|
||||
supportedDevices.put(UsbId.VENDOR_LEAFLABS,
|
||||
new int[] {
|
||||
UsbId.LEAFLABS_MAPLE,
|
||||
});
|
||||
supportedDevices.put(UsbId.VENDOR_ARM,
|
||||
new int[] {
|
||||
UsbId.ARM_MBED,
|
||||
});
|
||||
supportedDevices.put(UsbId.VENDOR_ST,
|
||||
new int[] {
|
||||
UsbId.ST_CDC,
|
||||
});
|
||||
return supportedDevices;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -7,11 +7,9 @@ package org.emulator.calculator.usbserial.driver;
|
|||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.util.Log;
|
||||
|
||||
//import org.emulator.calculator.usbserial.BuildConfig;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
|
@ -22,366 +20,355 @@ import java.util.Map;
|
|||
|
||||
public class Ch34xSerialDriver implements UsbSerialDriver {
|
||||
|
||||
private static final String TAG = Ch34xSerialDriver.class.getSimpleName();
|
||||
private static final String TAG = Ch34xSerialDriver.class.getSimpleName();
|
||||
|
||||
private final UsbDevice mDevice;
|
||||
private final UsbSerialPort mPort;
|
||||
private final UsbDevice mDevice;
|
||||
private final UsbSerialPort mPort;
|
||||
|
||||
private static final int LCR_ENABLE_RX = 0x80;
|
||||
private static final int LCR_ENABLE_TX = 0x40;
|
||||
private static final int LCR_MARK_SPACE = 0x20;
|
||||
private static final int LCR_PAR_EVEN = 0x10;
|
||||
private static final int LCR_ENABLE_PAR = 0x08;
|
||||
private static final int LCR_STOP_BITS_2 = 0x04;
|
||||
private static final int LCR_CS8 = 0x03;
|
||||
private static final int LCR_CS7 = 0x02;
|
||||
private static final int LCR_CS6 = 0x01;
|
||||
private static final int LCR_CS5 = 0x00;
|
||||
private static final int LCR_ENABLE_RX = 0x80;
|
||||
private static final int LCR_ENABLE_TX = 0x40;
|
||||
private static final int LCR_MARK_SPACE = 0x20;
|
||||
private static final int LCR_PAR_EVEN = 0x10;
|
||||
private static final int LCR_ENABLE_PAR = 0x08;
|
||||
private static final int LCR_STOP_BITS_2 = 0x04;
|
||||
private static final int LCR_CS8 = 0x03;
|
||||
private static final int LCR_CS7 = 0x02;
|
||||
private static final int LCR_CS6 = 0x01;
|
||||
private static final int LCR_CS5 = 0x00;
|
||||
|
||||
private static final int GCL_CTS = 0x01;
|
||||
private static final int GCL_DSR = 0x02;
|
||||
private static final int GCL_RI = 0x04;
|
||||
private static final int GCL_CD = 0x08;
|
||||
private static final int SCL_DTR = 0x20;
|
||||
private static final int SCL_RTS = 0x40;
|
||||
private static final int GCL_CTS = 0x01;
|
||||
private static final int GCL_DSR = 0x02;
|
||||
private static final int GCL_RI = 0x04;
|
||||
private static final int GCL_CD = 0x08;
|
||||
private static final int SCL_DTR = 0x20;
|
||||
private static final int SCL_RTS = 0x40;
|
||||
|
||||
public Ch34xSerialDriver(UsbDevice device) {
|
||||
mDevice = device;
|
||||
mPort = new Ch340SerialPort(mDevice, 0);
|
||||
}
|
||||
public Ch34xSerialDriver(UsbDevice device) {
|
||||
mDevice = device;
|
||||
mPort = new Ch340SerialPort(mDevice, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsbDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
@Override
|
||||
public UsbDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UsbSerialPort> getPorts() {
|
||||
return Collections.singletonList(mPort);
|
||||
}
|
||||
@Override
|
||||
public List<UsbSerialPort> getPorts() {
|
||||
return Collections.singletonList(mPort);
|
||||
}
|
||||
|
||||
public class Ch340SerialPort extends CommonUsbSerialPort {
|
||||
public class Ch340SerialPort extends CommonUsbSerialPort {
|
||||
|
||||
private static final int USB_TIMEOUT_MILLIS = 5000;
|
||||
private static final int USB_TIMEOUT_MILLIS = 5000;
|
||||
|
||||
private final int DEFAULT_BAUD_RATE = 9600;
|
||||
private final int DEFAULT_BAUD_RATE = 9600;
|
||||
|
||||
private boolean dtr = false;
|
||||
private boolean rts = false;
|
||||
private boolean dtr = false;
|
||||
private boolean rts = false;
|
||||
|
||||
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
}
|
||||
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsbSerialDriver getDriver() {
|
||||
return Ch34xSerialDriver.this;
|
||||
}
|
||||
@Override
|
||||
public UsbSerialDriver getDriver() {
|
||||
return Ch34xSerialDriver.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openInt() throws IOException {
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface usbIface = mDevice.getInterface(i);
|
||||
if (!mConnection.claimInterface(usbIface, true)) {
|
||||
throw new IOException("Could not claim data interface");
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||
UsbInterface usbIface = mDevice.getInterface(i);
|
||||
if (!mConnection.claimInterface(usbIface, true)) {
|
||||
throw new IOException("Could not claim data interface");
|
||||
}
|
||||
}
|
||||
|
||||
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
||||
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
||||
UsbEndpoint ep = dataIface.getEndpoint(i);
|
||||
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
||||
mReadEndpoint = ep;
|
||||
} else {
|
||||
mWriteEndpoint = ep;
|
||||
}
|
||||
}
|
||||
}
|
||||
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
||||
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
||||
UsbEndpoint ep = dataIface.getEndpoint(i);
|
||||
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
||||
mReadEndpoint = ep;
|
||||
} else {
|
||||
mWriteEndpoint = ep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
initialize();
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
}
|
||||
initialize();
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeInt() {
|
||||
try {
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
|
||||
mConnection.releaseInterface(mDevice.getInterface(i));
|
||||
} catch(Exception ignored) {}
|
||||
}
|
||||
@Override
|
||||
protected void closeInt() {
|
||||
try {
|
||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
|
||||
mConnection.releaseInterface(mDevice.getInterface(i));
|
||||
} catch(Exception ignored) {}
|
||||
}
|
||||
|
||||
private int controlOut(int request, int value, int index) {
|
||||
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
||||
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
|
||||
value, index, null, 0, USB_TIMEOUT_MILLIS);
|
||||
}
|
||||
private int controlOut(int request, int value, int index) {
|
||||
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
||||
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
|
||||
value, index, null, 0, USB_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
||||
|
||||
private int controlIn(int request, int value, int index, byte[] buffer) {
|
||||
final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
||||
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
|
||||
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
|
||||
}
|
||||
private int controlIn(int request, int value, int index, byte[] buffer) {
|
||||
final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
||||
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
|
||||
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
|
||||
}
|
||||
|
||||
|
||||
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
|
||||
byte[] buffer = new byte[expected.length];
|
||||
int ret = controlIn(request, value, 0, buffer);
|
||||
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
|
||||
byte[] buffer = new byte[expected.length];
|
||||
int ret = controlIn(request, value, 0, buffer);
|
||||
|
||||
if (ret < 0) {
|
||||
throw new IOException("Failed send cmd [" + msg + "]");
|
||||
}
|
||||
if (ret < 0) {
|
||||
throw new IOException("Failed send cmd [" + msg + "]");
|
||||
}
|
||||
|
||||
if (ret != expected.length) {
|
||||
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
|
||||
}
|
||||
if (ret != expected.length) {
|
||||
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
|
||||
}
|
||||
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
if (expected[i] == -1) {
|
||||
continue;
|
||||
}
|
||||
for (int i = 0; i < expected.length; i++) {
|
||||
if (expected[i] == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
int current = buffer[i] & 0xff;
|
||||
if (expected[i] != current) {
|
||||
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
int current = buffer[i] & 0xff;
|
||||
if (expected[i] != current) {
|
||||
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void setControlLines() throws IOException {
|
||||
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
|
||||
throw new IOException("Failed to set control lines");
|
||||
}
|
||||
}
|
||||
private void setControlLines() throws IOException {
|
||||
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
|
||||
throw new IOException("Failed to set control lines");
|
||||
}
|
||||
}
|
||||
|
||||
private byte getStatus() throws IOException {
|
||||
byte[] buffer = new byte[2];
|
||||
int ret = controlIn(0x95, 0x0706, 0, buffer);
|
||||
if (ret < 0)
|
||||
throw new IOException("Error getting control lines");
|
||||
return buffer[0];
|
||||
}
|
||||
private byte getStatus() throws IOException {
|
||||
byte[] buffer = new byte[2];
|
||||
int ret = controlIn(0x95, 0x0706, 0, buffer);
|
||||
if (ret < 0)
|
||||
throw new IOException("Error getting control lines");
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
private void initialize() throws IOException {
|
||||
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
|
||||
private void initialize() throws IOException {
|
||||
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
|
||||
|
||||
if (controlOut(0xa1, 0, 0) < 0) {
|
||||
throw new IOException("Init failed: #2");
|
||||
}
|
||||
if (controlOut(0xa1, 0, 0) < 0) {
|
||||
throw new IOException("Init failed: #2");
|
||||
}
|
||||
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
|
||||
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
|
||||
checkState("init #4", 0x95, 0x2518, new int[]{-1 /* 0x56, c3*/, 0x00});
|
||||
|
||||
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
|
||||
throw new IOException("Init failed: #5");
|
||||
}
|
||||
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
|
||||
throw new IOException("Init failed: #5");
|
||||
}
|
||||
|
||||
checkState("init #6", 0x95, 0x0706, new int[]{-1/*0xf?*/, -1/*0xec,0xee*/});
|
||||
checkState("init #6", 0x95, 0x0706, new int[]{-1/*0xf?*/, -1/*0xec,0xee*/});
|
||||
|
||||
if (controlOut(0xa1, 0x501f, 0xd90a) < 0) {
|
||||
throw new IOException("Init failed: #7");
|
||||
}
|
||||
if (controlOut(0xa1, 0x501f, 0xd90a) < 0) {
|
||||
throw new IOException("Init failed: #7");
|
||||
}
|
||||
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
setBaudRate(DEFAULT_BAUD_RATE);
|
||||
|
||||
setControlLines();
|
||||
setControlLines();
|
||||
|
||||
checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, -1/*0xec,0xee*/});
|
||||
}
|
||||
checkState("init #10", 0x95, 0x0706, new int[]{-1/* 0x9f, 0xff*/, -1/*0xec,0xee*/});
|
||||
}
|
||||
|
||||
|
||||
private void setBaudRate(int baudRate) throws IOException {
|
||||
long factor;
|
||||
long divisor;
|
||||
private void setBaudRate(int baudRate) throws IOException {
|
||||
final long CH341_BAUDBASE_FACTOR = 1532620800;
|
||||
final int CH341_BAUDBASE_DIVMAX = 3;
|
||||
|
||||
if (baudRate == 921600) {
|
||||
divisor = 7;
|
||||
factor = 0xf300;
|
||||
} else {
|
||||
final long BAUDBASE_FACTOR = 1532620800;
|
||||
final int BAUDBASE_DIVMAX = 3;
|
||||
long factor = CH341_BAUDBASE_FACTOR / baudRate;
|
||||
int divisor = CH341_BAUDBASE_DIVMAX;
|
||||
|
||||
// if(BuildConfig.DEBUG && (baudRate & (3<<29)) == (1<<29))
|
||||
// baudRate &= ~(1<<29); // for testing purpose bypass dedicated baud rate handling
|
||||
factor = BAUDBASE_FACTOR / baudRate;
|
||||
divisor = BAUDBASE_DIVMAX;
|
||||
while ((factor > 0xfff0) && divisor > 0) {
|
||||
factor >>= 3;
|
||||
divisor--;
|
||||
}
|
||||
if (factor > 0xfff0) {
|
||||
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
|
||||
}
|
||||
factor = 0x10000 - factor;
|
||||
}
|
||||
while ((factor > 0xfff0) && divisor > 0) {
|
||||
factor >>= 3;
|
||||
divisor--;
|
||||
}
|
||||
|
||||
divisor |= 0x0080; // else ch341a waits until buffer full
|
||||
int val1 = (int) ((factor & 0xff00) | divisor);
|
||||
int val2 = (int) (factor & 0xff);
|
||||
Log.d(TAG, String.format("baud rate=%d, 0x1312=0x%04x, 0x0f2c=0x%04x", baudRate, val1, val2));
|
||||
int ret = controlOut(0x9a, 0x1312, val1);
|
||||
if (ret < 0) {
|
||||
throw new IOException("Error setting baud rate: #1)");
|
||||
}
|
||||
ret = controlOut(0x9a, 0x0f2c, val2);
|
||||
if (ret < 0) {
|
||||
throw new IOException("Error setting baud rate: #2");
|
||||
}
|
||||
}
|
||||
if (factor > 0xfff0) {
|
||||
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||
if(baudRate <= 0) {
|
||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||
}
|
||||
setBaudRate(baudRate);
|
||||
factor = 0x10000 - factor;
|
||||
divisor |= 0x0080; // else ch341a waits until buffer full
|
||||
int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor));
|
||||
if (ret < 0) {
|
||||
throw new IOException("Error setting baud rate: #1)");
|
||||
}
|
||||
|
||||
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
|
||||
ret = controlOut(0x9a, 0x0f2c, (int) (factor & 0xff));
|
||||
if (ret < 0) {
|
||||
throw new IOException("Error setting baud rate: #2");
|
||||
}
|
||||
}
|
||||
|
||||
switch (dataBits) {
|
||||
case DATABITS_5:
|
||||
lcr |= LCR_CS5;
|
||||
break;
|
||||
case DATABITS_6:
|
||||
lcr |= LCR_CS6;
|
||||
break;
|
||||
case DATABITS_7:
|
||||
lcr |= LCR_CS7;
|
||||
break;
|
||||
case DATABITS_8:
|
||||
lcr |= LCR_CS8;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
||||
}
|
||||
@Override
|
||||
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||
if(baudRate <= 0) {
|
||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||
}
|
||||
setBaudRate(baudRate);
|
||||
|
||||
switch (parity) {
|
||||
case PARITY_NONE:
|
||||
break;
|
||||
case PARITY_ODD:
|
||||
lcr |= LCR_ENABLE_PAR;
|
||||
break;
|
||||
case PARITY_EVEN:
|
||||
lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN;
|
||||
break;
|
||||
case PARITY_MARK:
|
||||
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE;
|
||||
break;
|
||||
case PARITY_SPACE:
|
||||
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid parity: " + parity);
|
||||
}
|
||||
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
|
||||
|
||||
switch (stopBits) {
|
||||
case STOPBITS_1:
|
||||
break;
|
||||
case STOPBITS_1_5:
|
||||
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
||||
case STOPBITS_2:
|
||||
lcr |= LCR_STOP_BITS_2;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
||||
}
|
||||
switch (dataBits) {
|
||||
case DATABITS_5:
|
||||
lcr |= LCR_CS5;
|
||||
break;
|
||||
case DATABITS_6:
|
||||
lcr |= LCR_CS6;
|
||||
break;
|
||||
case DATABITS_7:
|
||||
lcr |= LCR_CS7;
|
||||
break;
|
||||
case DATABITS_8:
|
||||
lcr |= LCR_CS8;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
||||
}
|
||||
|
||||
int ret = controlOut(0x9a, 0x2518, lcr);
|
||||
if (ret < 0) {
|
||||
throw new IOException("Error setting control byte");
|
||||
}
|
||||
}
|
||||
switch (parity) {
|
||||
case PARITY_NONE:
|
||||
break;
|
||||
case PARITY_ODD:
|
||||
lcr |= LCR_ENABLE_PAR;
|
||||
break;
|
||||
case PARITY_EVEN:
|
||||
lcr |= LCR_ENABLE_PAR | LCR_PAR_EVEN;
|
||||
break;
|
||||
case PARITY_MARK:
|
||||
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE;
|
||||
break;
|
||||
case PARITY_SPACE:
|
||||
lcr |= LCR_ENABLE_PAR | LCR_MARK_SPACE | LCR_PAR_EVEN;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid parity: " + parity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCD() throws IOException {
|
||||
return (getStatus() & GCL_CD) == 0;
|
||||
}
|
||||
switch (stopBits) {
|
||||
case STOPBITS_1:
|
||||
break;
|
||||
case STOPBITS_1_5:
|
||||
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
||||
case STOPBITS_2:
|
||||
lcr |= LCR_STOP_BITS_2;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getCTS() throws IOException {
|
||||
return (getStatus() & GCL_CTS) == 0;
|
||||
}
|
||||
int ret = controlOut(0x9a, 0x2518, lcr);
|
||||
if (ret < 0) {
|
||||
throw new IOException("Error setting control byte");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDSR() throws IOException {
|
||||
return (getStatus() & GCL_DSR) == 0;
|
||||
}
|
||||
@Override
|
||||
public boolean getCD() throws IOException {
|
||||
return (getStatus() & GCL_CD) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getDTR() throws IOException {
|
||||
return dtr;
|
||||
}
|
||||
@Override
|
||||
public boolean getCTS() throws IOException {
|
||||
return (getStatus() & GCL_CTS) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDTR(boolean value) throws IOException {
|
||||
dtr = value;
|
||||
setControlLines();
|
||||
}
|
||||
@Override
|
||||
public boolean getDSR() throws IOException {
|
||||
return (getStatus() & GCL_DSR) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRI() throws IOException {
|
||||
return (getStatus() & GCL_RI) == 0;
|
||||
}
|
||||
@Override
|
||||
public boolean getDTR() throws IOException {
|
||||
return dtr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getRTS() throws IOException {
|
||||
return rts;
|
||||
}
|
||||
@Override
|
||||
public void setDTR(boolean value) throws IOException {
|
||||
dtr = value;
|
||||
setControlLines();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRTS(boolean value) throws IOException {
|
||||
rts = value;
|
||||
setControlLines();
|
||||
}
|
||||
@Override
|
||||
public boolean getRI() throws IOException {
|
||||
return (getStatus() & GCL_RI) == 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ControlLine> getControlLines() throws IOException {
|
||||
int status = getStatus();
|
||||
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
||||
if(rts) set.add(ControlLine.RTS);
|
||||
if((status & GCL_CTS) == 0) set.add(ControlLine.CTS);
|
||||
if(dtr) set.add(ControlLine.DTR);
|
||||
if((status & GCL_DSR) == 0) set.add(ControlLine.DSR);
|
||||
if((status & GCL_CD) == 0) set.add(ControlLine.CD);
|
||||
if((status & GCL_RI) == 0) set.add(ControlLine.RI);
|
||||
return set;
|
||||
}
|
||||
@Override
|
||||
public boolean getRTS() throws IOException {
|
||||
return rts;
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||
return EnumSet.allOf(ControlLine.class);
|
||||
}
|
||||
@Override
|
||||
public void setRTS(boolean value) throws IOException {
|
||||
rts = value;
|
||||
setControlLines();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBreak(boolean value) throws IOException {
|
||||
byte[] req = new byte[2];
|
||||
if(controlIn(0x95, 0x1805, 0, req) < 0) {
|
||||
throw new IOException("Error getting BREAK condition");
|
||||
}
|
||||
if(value) {
|
||||
req[0] &= ~1;
|
||||
req[1] &= ~0x40;
|
||||
} else {
|
||||
req[0] |= 1;
|
||||
req[1] |= 0x40;
|
||||
}
|
||||
int val = (req[1] & 0xff) << 8 | (req[0] & 0xff);
|
||||
if(controlOut(0x9a, 0x1805, val) < 0) {
|
||||
throw new IOException("Error setting BREAK condition");
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public EnumSet<ControlLine> getControlLines() throws IOException {
|
||||
int status = getStatus();
|
||||
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
||||
if(rts) set.add(ControlLine.RTS);
|
||||
if((status & GCL_CTS) == 0) set.add(ControlLine.CTS);
|
||||
if(dtr) set.add(ControlLine.DTR);
|
||||
if((status & GCL_DSR) == 0) set.add(ControlLine.DSR);
|
||||
if((status & GCL_CD) == 0) set.add(ControlLine.CD);
|
||||
if((status & GCL_RI) == 0) set.add(ControlLine.RI);
|
||||
return set;
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{
|
||||
UsbId.QINHENG_CH340,
|
||||
UsbId.QINHENG_CH341A,
|
||||
});
|
||||
return supportedDevices;
|
||||
}
|
||||
@Override
|
||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||
return EnumSet.allOf(ControlLine.class);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBreak(boolean value) throws IOException {
|
||||
byte[] req = new byte[2];
|
||||
if(controlIn(0x95, 0x1805, 0, req) < 0) {
|
||||
throw new IOException("Error getting BREAK condition");
|
||||
}
|
||||
if(value) {
|
||||
req[0] &= ~1;
|
||||
req[1] &= ~0x40;
|
||||
} else {
|
||||
req[0] |= 1;
|
||||
req[1] |= 0x40;
|
||||
}
|
||||
int val = (req[1] & 0xff) << 8 | (req[0] & 0xff);
|
||||
if(controlOut(0x9a, 0x1805, val) < 0) {
|
||||
throw new IOException("Error setting BREAK condition");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{
|
||||
UsbId.QINHENG_CH340,
|
||||
UsbId.QINHENG_CH341A,
|
||||
});
|
||||
return supportedDevices;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,96 +0,0 @@
|
|||
package org.emulator.calculator.usbserial.driver;
|
||||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class ChromeCcdSerialDriver implements UsbSerialDriver{
|
||||
|
||||
private final String TAG = ChromeCcdSerialDriver.class.getSimpleName();
|
||||
|
||||
private final UsbDevice mDevice;
|
||||
private final List<UsbSerialPort> mPorts;
|
||||
|
||||
@Override
|
||||
public UsbDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UsbSerialPort> getPorts() {
|
||||
return mPorts;
|
||||
}
|
||||
|
||||
public ChromeCcdSerialDriver(UsbDevice mDevice) {
|
||||
this.mDevice = mDevice;
|
||||
mPorts = new ArrayList<UsbSerialPort>();
|
||||
for (int i = 0; i < 3; i++)
|
||||
mPorts.add(new ChromeCcdSerialPort(mDevice, i));
|
||||
}
|
||||
|
||||
public class ChromeCcdSerialPort extends CommonUsbSerialPort {
|
||||
private UsbInterface mDataInterface;
|
||||
|
||||
public ChromeCcdSerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openInt() throws IOException {
|
||||
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
|
||||
mDataInterface = mDevice.getInterface(mPortNumber);
|
||||
if (!mConnection.claimInterface(mDataInterface, true)) {
|
||||
throw new IOException("Could not claim shared control/data interface");
|
||||
}
|
||||
Log.d(TAG, "endpoint count=" + mDataInterface.getEndpointCount());
|
||||
for (int i = 0; i < mDataInterface.getEndpointCount(); ++i) {
|
||||
UsbEndpoint ep = mDataInterface.getEndpoint(i);
|
||||
if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) {
|
||||
mReadEndpoint = ep;
|
||||
} else if ((ep.getDirection() == UsbConstants.USB_DIR_OUT) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) {
|
||||
mWriteEndpoint = ep;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeInt() {
|
||||
try {
|
||||
mConnection.releaseInterface(mDataInterface);
|
||||
} catch(Exception ignored) {}
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsbSerialDriver getDriver() {
|
||||
return ChromeCcdSerialDriver.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||
return EnumSet.noneOf(ControlLine.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_GOOGLE, new int[]{
|
||||
UsbId.GOOGLE_CR50,
|
||||
});
|
||||
return supportedDevices;
|
||||
}
|
||||
}
|
|
@ -25,32 +25,28 @@ import java.util.EnumSet;
|
|||
*/
|
||||
public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||
|
||||
public static boolean DEBUG = false;
|
||||
|
||||
private static final String TAG = CommonUsbSerialPort.class.getSimpleName();
|
||||
private static final int DEFAULT_WRITE_BUFFER_SIZE = 16 * 1024;
|
||||
private static final int MAX_READ_SIZE = 16 * 1024; // = old bulkTransfer limit
|
||||
|
||||
protected final UsbDevice mDevice;
|
||||
protected final int mPortNumber;
|
||||
|
||||
// non-null when open()
|
||||
protected UsbDeviceConnection mConnection;
|
||||
protected UsbDeviceConnection mConnection = null;
|
||||
protected UsbEndpoint mReadEndpoint;
|
||||
protected UsbEndpoint mWriteEndpoint;
|
||||
protected UsbRequest mUsbRequest;
|
||||
|
||||
/**
|
||||
* Internal write buffer.
|
||||
* Guarded by {@link #mWriteBufferLock}.
|
||||
* Default length = mReadEndpoint.getMaxPacketSize()
|
||||
**/
|
||||
protected byte[] mWriteBuffer;
|
||||
protected final Object mWriteBufferLock = new Object();
|
||||
|
||||
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
|
||||
protected byte[] mWriteBuffer;
|
||||
|
||||
public CommonUsbSerialPort(UsbDevice device, int portNumber) {
|
||||
mDevice = device;
|
||||
mPortNumber = portNumber;
|
||||
|
||||
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -89,19 +85,11 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
* Sets the size of the internal buffer used to exchange data with the USB
|
||||
* stack for write operations. Most users should not need to change this.
|
||||
*
|
||||
* @param bufferSize the size in bytes, <= 0 resets original size
|
||||
* @param bufferSize the size in bytes
|
||||
*/
|
||||
public final void setWriteBufferSize(int bufferSize) {
|
||||
synchronized (mWriteBufferLock) {
|
||||
if (bufferSize <= 0) {
|
||||
if (mWriteEndpoint != null) {
|
||||
bufferSize = mWriteEndpoint.getMaxPacketSize();
|
||||
} else {
|
||||
mWriteBuffer = null;
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (mWriteBuffer != null && bufferSize == mWriteBuffer.length) {
|
||||
if (bufferSize == mWriteBuffer.length) {
|
||||
return;
|
||||
}
|
||||
mWriteBuffer = new byte[bufferSize];
|
||||
|
@ -118,7 +106,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
}
|
||||
mConnection = connection;
|
||||
try {
|
||||
openInt();
|
||||
openInt(connection);
|
||||
if (mReadEndpoint == null || mWriteEndpoint == null) {
|
||||
throw new IOException("Could not get read & write endpoints");
|
||||
}
|
||||
|
@ -132,18 +120,17 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
}
|
||||
}
|
||||
|
||||
protected abstract void openInt() throws IOException;
|
||||
protected abstract void openInt(UsbDeviceConnection connection) throws IOException;
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
if (mConnection == null) {
|
||||
throw new IOException("Already closed");
|
||||
}
|
||||
UsbRequest usbRequest = mUsbRequest;
|
||||
mUsbRequest = null;
|
||||
try {
|
||||
usbRequest.cancel();
|
||||
mUsbRequest.cancel();
|
||||
} catch(Exception ignored) {}
|
||||
mUsbRequest = null;
|
||||
try {
|
||||
closeInt();
|
||||
} catch(Exception ignored) {}
|
||||
|
@ -158,40 +145,25 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
/**
|
||||
* use simple USB request supported by all devices to test if connection is still valid
|
||||
*/
|
||||
protected void testConnection(boolean full) throws IOException {
|
||||
testConnection(full, "USB get_status request failed");
|
||||
}
|
||||
|
||||
protected void testConnection(boolean full, String msg) throws IOException {
|
||||
if(mUsbRequest == null) {
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
if(!full) {
|
||||
return;
|
||||
}
|
||||
protected void testConnection() throws IOException {
|
||||
byte[] buf = new byte[2];
|
||||
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
||||
if(len < 0)
|
||||
throw new IOException(msg);
|
||||
throw new IOException("USB get_status request failed");
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] dest, final int timeout) throws IOException {
|
||||
if(dest.length == 0) {
|
||||
throw new IllegalArgumentException("Read buffer too small");
|
||||
}
|
||||
return read(dest, dest.length, timeout);
|
||||
return read(dest, timeout, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] dest, final int length, final int timeout) throws IOException {return read(dest, length, timeout, true);}
|
||||
|
||||
protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException {
|
||||
testConnection(false);
|
||||
if(length <= 0) {
|
||||
throw new IllegalArgumentException("Read length too small");
|
||||
protected int read(final byte[] dest, final int timeout, boolean testConnection) throws IOException {
|
||||
if(mConnection == null) {
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
if(dest.length <= 0) {
|
||||
throw new IllegalArgumentException("Read buffer to small");
|
||||
}
|
||||
length = Math.min(length, dest.length);
|
||||
final int nread;
|
||||
if (timeout != 0) {
|
||||
// bulkTransfer will cause data loss with short timeout + high baud rates + continuous transfer
|
||||
|
@ -203,16 +175,16 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
// /system/lib64/libandroid_runtime.so (android_hardware_UsbDeviceConnection_request_wait(_JNIEnv*, _jobject*, long)+84)
|
||||
// data loss / crashes were observed with timeout up to 200 msec
|
||||
long endTime = testConnection ? MonotonicClock.millis() + timeout : 0;
|
||||
int readMax = Math.min(length, MAX_READ_SIZE);
|
||||
int readMax = Math.min(dest.length, MAX_READ_SIZE);
|
||||
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
|
||||
// Android error propagation is improvable:
|
||||
// nread == -1 can be: timeout, connection lost, buffer to small, ???
|
||||
if(nread == -1 && testConnection)
|
||||
testConnection(MonotonicClock.millis() < endTime);
|
||||
if(nread == -1 && testConnection && MonotonicClock.millis() < endTime)
|
||||
testConnection();
|
||||
|
||||
} else {
|
||||
final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length);
|
||||
if (!mUsbRequest.queue(buf, length)) {
|
||||
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||
if (!mUsbRequest.queue(buf, dest.length)) {
|
||||
throw new IOException("Queueing USB request failed");
|
||||
}
|
||||
final UsbRequest response = mConnection.requestWait();
|
||||
|
@ -223,23 +195,21 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
// Android error propagation is improvable:
|
||||
// response != null & nread == 0 can be: connection lost, buffer to small, ???
|
||||
if(nread == 0) {
|
||||
testConnection(true);
|
||||
testConnection();
|
||||
}
|
||||
}
|
||||
return Math.max(nread, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void write(byte[] src, int timeout) throws IOException {write(src, src.length, timeout);}
|
||||
|
||||
@Override
|
||||
public void write(final byte[] src, int length, final int timeout) throws IOException {
|
||||
public void write(final byte[] src, final int timeout) throws IOException {
|
||||
int offset = 0;
|
||||
long startTime = MonotonicClock.millis();
|
||||
length = Math.min(length, src.length);
|
||||
final long endTime = (timeout == 0) ? 0 : (MonotonicClock.millis() + timeout);
|
||||
|
||||
testConnection(false);
|
||||
while (offset < length) {
|
||||
if(mConnection == null) {
|
||||
throw new IOException("Connection closed");
|
||||
}
|
||||
while (offset < src.length) {
|
||||
int requestTimeout;
|
||||
final int requestLength;
|
||||
final int actualLength;
|
||||
|
@ -247,10 +217,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
synchronized (mWriteBufferLock) {
|
||||
final byte[] writeBuffer;
|
||||
|
||||
if (mWriteBuffer == null) {
|
||||
mWriteBuffer = new byte[mWriteEndpoint.getMaxPacketSize()];
|
||||
}
|
||||
requestLength = Math.min(length - offset, mWriteBuffer.length);
|
||||
requestLength = Math.min(src.length - offset, mWriteBuffer.length);
|
||||
if (offset == 0) {
|
||||
writeBuffer = src;
|
||||
} else {
|
||||
|
@ -261,7 +228,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
if (timeout == 0 || offset == 0) {
|
||||
requestTimeout = timeout;
|
||||
} else {
|
||||
requestTimeout = (int)(startTime + timeout - MonotonicClock.millis());
|
||||
requestTimeout = (int)(endTime - MonotonicClock.millis());
|
||||
if(requestTimeout == 0)
|
||||
requestTimeout = -1;
|
||||
}
|
||||
|
@ -271,18 +238,14 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
actualLength = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, requestLength, requestTimeout);
|
||||
}
|
||||
}
|
||||
long elapsed = MonotonicClock.millis() - startTime;
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + length + " time " + elapsed + "/" + requestTimeout);
|
||||
}
|
||||
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + src.length + " timeout " + requestTimeout);
|
||||
if (actualLength <= 0) {
|
||||
String msg = "Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length + " after " + elapsed + "msec, rc=" + actualLength;
|
||||
if (timeout != 0) {
|
||||
testConnection(elapsed < timeout, msg);
|
||||
throw new SerialTimeoutException(msg, offset);
|
||||
if (timeout != 0 && MonotonicClock.millis() >= endTime) {
|
||||
SerialTimeoutException ex = new SerialTimeoutException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length + ", rc=" + actualLength);
|
||||
ex.bytesTransferred = offset;
|
||||
throw ex;
|
||||
} else {
|
||||
throw new IOException(msg);
|
||||
|
||||
throw new IOException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length);
|
||||
}
|
||||
}
|
||||
offset += actualLength;
|
||||
|
@ -291,7 +254,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
|
||||
@Override
|
||||
public boolean isOpen() {
|
||||
return mUsbRequest != null;
|
||||
return mConnection != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -322,7 +285,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
|||
public void setRTS(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
||||
|
||||
@Override
|
||||
public EnumSet<ControlLine> getControlLines() throws IOException { throw new UnsupportedOperationException(); }
|
||||
public abstract EnumSet<ControlLine> getControlLines() throws IOException;
|
||||
|
||||
@Override
|
||||
public abstract EnumSet<ControlLine> getSupportedControlLines() throws IOException;
|
||||
|
|
|
@ -8,6 +8,7 @@ package org.emulator.calculator.usbserial.driver;
|
|||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
|
||||
|
@ -118,14 +119,14 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
byte[] buffer = new byte[1];
|
||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, SILABSER_GET_MDMSTS_REQUEST_CODE, 0,
|
||||
mPortNumber, buffer, buffer.length, USB_WRITE_TIMEOUT_MILLIS);
|
||||
if (result != buffer.length) {
|
||||
if (result != 1) {
|
||||
throw new IOException("Control transfer failed: " + SILABSER_GET_MDMSTS_REQUEST_CODE + " / " + 0 + " -> " + result);
|
||||
}
|
||||
return buffer[0];
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openInt() throws IOException {
|
||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
|
||||
if(mPortNumber >= mDevice.getInterfaceCount()) {
|
||||
throw new IOException("Unknown port number");
|
||||
|
@ -320,7 +321,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_SILABS,
|
||||
|
|
|
@ -9,6 +9,7 @@ package org.emulator.calculator.usbserial.driver;
|
|||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.util.Log;
|
||||
|
||||
import org.emulator.calculator.usbserial.util.MonotonicClock;
|
||||
|
@ -98,8 +99,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
|
||||
|
||||
@Override
|
||||
protected void openInt() throws IOException {
|
||||
if (!mConnection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
||||
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||
if (!connection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
||||
throw new IOException("Could not claim interface " + mPortNumber);
|
||||
}
|
||||
if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) {
|
||||
|
@ -122,13 +123,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
|
||||
// mDevice.getVersion() would require API 23
|
||||
byte[] rawDescriptors = mConnection.getRawDescriptors();
|
||||
byte[] rawDescriptors = connection.getRawDescriptors();
|
||||
if(rawDescriptors == null || rawDescriptors.length < 14) {
|
||||
throw new IOException("Could not get device descriptors");
|
||||
}
|
||||
int deviceType = rawDescriptors[13];
|
||||
baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9 // ...H devices
|
||||
|| mDevice.getInterfaceCount() > 1; // FT2232C
|
||||
baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9; // ...H devices
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -139,37 +139,24 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] dest, final int timeout) throws IOException
|
||||
{
|
||||
public int read(final byte[] dest, final int timeout) throws IOException {
|
||||
if(dest.length <= READ_HEADER_LENGTH) {
|
||||
throw new IllegalArgumentException("Read buffer too small");
|
||||
throw new IllegalArgumentException("Read buffer to small");
|
||||
// could allocate larger buffer, including space for 2 header bytes, but this would
|
||||
// result in buffers not being 64 byte aligned any more, causing data loss at continuous
|
||||
// data transfer at high baud rates when buffers are fully filled.
|
||||
}
|
||||
return read(dest, dest.length, timeout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int read(final byte[] dest, int length, final int timeout) throws IOException {
|
||||
if(length <= READ_HEADER_LENGTH) {
|
||||
throw new IllegalArgumentException("Read length too small");
|
||||
// could allocate larger buffer, including space for 2 header bytes, but this would
|
||||
// result in buffers not being 64 byte aligned any more, causing data loss at continuous
|
||||
// data transfer at high baud rates when buffers are fully filled.
|
||||
}
|
||||
length = Math.min(length, dest.length);
|
||||
int nread;
|
||||
if (timeout != 0) {
|
||||
long endTime = MonotonicClock.millis() + timeout;
|
||||
do {
|
||||
nread = super.read(dest, length, Math.max(1, (int)(endTime - MonotonicClock.millis())), false);
|
||||
nread = super.read(dest, Math.max(1, (int)(endTime - MonotonicClock.millis())), false);
|
||||
} while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime);
|
||||
if(nread <= 0)
|
||||
testConnection(MonotonicClock.millis() < endTime);
|
||||
if(nread <= 0 && MonotonicClock.millis() < endTime)
|
||||
testConnection();
|
||||
} else {
|
||||
do {
|
||||
nread = super.read(dest, length, timeout);
|
||||
nread = super.read(dest, timeout, false);
|
||||
} while (nread == READ_HEADER_LENGTH);
|
||||
}
|
||||
return readFilter(dest, nread);
|
||||
|
@ -303,7 +290,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
byte[] data = new byte[2];
|
||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_MODEM_STATUS_REQUEST,
|
||||
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
||||
if (result != data.length) {
|
||||
if (result != 2) {
|
||||
throw new IOException("Get modem status failed: result=" + result);
|
||||
}
|
||||
return data[0];
|
||||
|
@ -419,7 +406,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
byte[] data = new byte[1];
|
||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_LATENCY_TIMER_REQUEST,
|
||||
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
||||
if (result != data.length) {
|
||||
if (result != 1) {
|
||||
throw new IOException("Get latency timer failed: result=" + result);
|
||||
}
|
||||
return data[0];
|
||||
|
@ -427,7 +414,6 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
|||
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_FTDI,
|
||||
|
|
|
@ -1,106 +0,0 @@
|
|||
package org.emulator.calculator.usbserial.driver;
|
||||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.util.Log;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.Collections;
|
||||
import java.util.EnumSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class GsmModemSerialDriver implements UsbSerialDriver{
|
||||
|
||||
private final String TAG = GsmModemSerialDriver.class.getSimpleName();
|
||||
|
||||
private final UsbDevice mDevice;
|
||||
private final UsbSerialPort mPort;
|
||||
|
||||
@Override
|
||||
public UsbDevice getDevice() {
|
||||
return mDevice;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<UsbSerialPort> getPorts() {
|
||||
return Collections.singletonList(mPort);
|
||||
}
|
||||
|
||||
public GsmModemSerialDriver(UsbDevice mDevice) {
|
||||
this.mDevice = mDevice;
|
||||
mPort = new GsmModemSerialPort(mDevice, 0);
|
||||
}
|
||||
|
||||
public class GsmModemSerialPort extends CommonUsbSerialPort {
|
||||
|
||||
private UsbInterface mDataInterface;
|
||||
|
||||
public GsmModemSerialPort(UsbDevice device, int portNumber) {
|
||||
super(device, portNumber);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void openInt() throws IOException {
|
||||
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
|
||||
mDataInterface = mDevice.getInterface(0);
|
||||
if (!mConnection.claimInterface(mDataInterface, true)) {
|
||||
throw new IOException("Could not claim shared control/data interface");
|
||||
}
|
||||
Log.d(TAG, "endpoint count=" + mDataInterface.getEndpointCount());
|
||||
for (int i = 0; i < mDataInterface.getEndpointCount(); ++i) {
|
||||
UsbEndpoint ep = mDataInterface.getEndpoint(i);
|
||||
if ((ep.getDirection() == UsbConstants.USB_DIR_IN) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) {
|
||||
mReadEndpoint = ep;
|
||||
} else if ((ep.getDirection() == UsbConstants.USB_DIR_OUT) && (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)) {
|
||||
mWriteEndpoint = ep;
|
||||
}
|
||||
}
|
||||
initGsmModem();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void closeInt() {
|
||||
try {
|
||||
mConnection.releaseInterface(mDataInterface);
|
||||
} catch(Exception ignored) {}
|
||||
|
||||
}
|
||||
|
||||
private int initGsmModem() throws IOException {
|
||||
int len = mConnection.controlTransfer(
|
||||
0x21, 0x22, 0x01, 0, null, 0, 5000);
|
||||
if(len < 0) {
|
||||
throw new IOException("init failed");
|
||||
}
|
||||
return len;
|
||||
}
|
||||
|
||||
@Override
|
||||
public UsbSerialDriver getDriver() {
|
||||
return GsmModemSerialDriver.this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setParameters(int baudRate, int dataBits, int stopBits, int parity) throws IOException {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||
return EnumSet.noneOf(ControlLine.class);
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_UNISOC, new int[]{
|
||||
UsbId.FIBOCOM_L610,
|
||||
UsbId.FIBOCOM_L612,
|
||||
});
|
||||
return supportedDevices;
|
||||
}
|
||||
}
|
|
@ -6,7 +6,6 @@
|
|||
|
||||
package org.emulator.calculator.usbserial.driver;
|
||||
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
@ -15,14 +14,14 @@ import java.util.LinkedHashMap;
|
|||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Maps (vendor id, product id) pairs to the corresponding serial driver,
|
||||
* or invoke 'probe' method to check actual USB devices for matching interfaces.
|
||||
* Maps (vendor id, product id) pairs to the corresponding serial driver.
|
||||
*
|
||||
* @author mike wakerly (opensource@hoho.com)
|
||||
*/
|
||||
public class ProbeTable {
|
||||
|
||||
private final Map<Pair<Integer, Integer>, Class<? extends UsbSerialDriver>> mVidPidProbeTable =
|
||||
private final Map<Pair<Integer, Integer>, Class<? extends UsbSerialDriver>> mProbeTable =
|
||||
new LinkedHashMap<>();
|
||||
private final Map<Method, Class<? extends UsbSerialDriver>> mMethodProbeTable = new LinkedHashMap<>();
|
||||
|
||||
/**
|
||||
* Adds or updates a (vendor, product) pair in the table.
|
||||
|
@ -34,7 +33,7 @@ public class ProbeTable {
|
|||
*/
|
||||
public ProbeTable addProduct(int vendorId, int productId,
|
||||
Class<? extends UsbSerialDriver> driverClass) {
|
||||
mVidPidProbeTable.put(Pair.create(vendorId, productId), driverClass);
|
||||
mProbeTable.put(Pair.create(vendorId, productId), driverClass);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
@ -42,11 +41,12 @@ public class ProbeTable {
|
|||
* Internal method to add all supported products from
|
||||
* {@code getSupportedProducts} static method.
|
||||
*
|
||||
* @param driverClass to be added
|
||||
* @param driverClass
|
||||
* @return
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
void addDriver(Class<? extends UsbSerialDriver> driverClass) {
|
||||
Method method;
|
||||
ProbeTable addDriver(Class<? extends UsbSerialDriver> driverClass) {
|
||||
final Method method;
|
||||
|
||||
try {
|
||||
method = driverClass.getMethod("getSupportedDevices");
|
||||
|
@ -68,35 +68,20 @@ public class ProbeTable {
|
|||
}
|
||||
}
|
||||
|
||||
try {
|
||||
method = driverClass.getMethod("probe", UsbDevice.class);
|
||||
mMethodProbeTable.put(method, driverClass);
|
||||
} catch (SecurityException | NoSuchMethodException ignored) {
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the driver for the given USB device, or {@code null} if no match.
|
||||
* Returns the driver for the given (vendor, product) pair, or {@code null}
|
||||
* if no match.
|
||||
*
|
||||
* @param usbDevice the USB device to be probed
|
||||
* @param vendorId the USB vendor id
|
||||
* @param productId the USB product id
|
||||
* @return the driver class matching this pair, or {@code null}
|
||||
*/
|
||||
public Class<? extends UsbSerialDriver> findDriver(final UsbDevice usbDevice) {
|
||||
final Pair<Integer, Integer> pair = Pair.create(usbDevice.getVendorId(), usbDevice.getProductId());
|
||||
Class<? extends UsbSerialDriver> driverClass = mVidPidProbeTable.get(pair);
|
||||
if (driverClass != null)
|
||||
return driverClass;
|
||||
for (Map.Entry<Method, Class<? extends UsbSerialDriver>> entry : mMethodProbeTable.entrySet()) {
|
||||
try {
|
||||
Method method = entry.getKey();
|
||||
Object o = method.invoke(null, usbDevice);
|
||||
if((boolean)o)
|
||||
return entry.getValue();
|
||||
} catch (IllegalArgumentException | IllegalAccessException | InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
public Class<? extends UsbSerialDriver> findDriver(int vendorId, int productId) {
|
||||
final Pair<Integer, Integer> pair = Pair.create(vendorId, productId);
|
||||
return mProbeTable.get(pair);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -11,6 +11,7 @@ package org.emulator.calculator.usbserial.driver;
|
|||
|
||||
import android.hardware.usb.UsbConstants;
|
||||
import android.hardware.usb.UsbDevice;
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
import android.hardware.usb.UsbEndpoint;
|
||||
import android.hardware.usb.UsbInterface;
|
||||
import android.util.Log;
|
||||
|
@ -34,7 +35,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
|
||||
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000
|
||||
};
|
||||
protected enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_T, DEVICE_TYPE_HX, DEVICE_TYPE_HXN }
|
||||
protected enum DeviceType { DEVICE_TYPE_01, DEVICE_TYPE_T, DEVICE_TYPE_HX, DEVICE_TYPE_HXN}
|
||||
|
||||
private final UsbDevice mDevice;
|
||||
private final UsbSerialPort mPort;
|
||||
|
@ -122,7 +123,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
private volatile Thread mReadStatusThread = null;
|
||||
private final Object mReadStatusThreadLock = new Object();
|
||||
private boolean mStopReadStatusThread = false;
|
||||
private Exception mReadStatusException = null;
|
||||
private IOException mReadStatusException = null;
|
||||
|
||||
|
||||
public ProlificSerialPort(UsbDevice device, int portNumber) {
|
||||
|
@ -138,7 +139,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
byte[] buffer = new byte[length];
|
||||
int result = mConnection.controlTransfer(requestType, request, value, index, buffer, length, USB_READ_TIMEOUT_MILLIS);
|
||||
if (result != length) {
|
||||
throw new IOException(String.format("ControlTransfer %s 0x%x failed: %d",mDeviceType.name(), value, result));
|
||||
throw new IOException(String.format("ControlTransfer 0x%x failed: %d",value, result));
|
||||
}
|
||||
return buffer;
|
||||
}
|
||||
|
@ -147,7 +148,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
int length = (data == null) ? 0 : data.length;
|
||||
int result = mConnection.controlTransfer(requestType, request, value, index, data, length, USB_WRITE_TIMEOUT_MILLIS);
|
||||
if (result != length) {
|
||||
throw new IOException( String.format("ControlTransfer %s 0x%x failed: %d", mDeviceType.name(), value, result));
|
||||
throw new IOException( String.format("ControlTransfer 0x%x failed: %d", value, result));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -201,12 +202,12 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
|
||||
private void readStatusThreadFunction() {
|
||||
try {
|
||||
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
|
||||
while (!mStopReadStatusThread) {
|
||||
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
|
||||
long endTime = MonotonicClock.millis() + 500;
|
||||
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
|
||||
if(readBytesCount == -1)
|
||||
testConnection(MonotonicClock.millis() < endTime);
|
||||
if(readBytesCount == -1 && MonotonicClock.millis() < endTime)
|
||||
testConnection();
|
||||
if (readBytesCount > 0) {
|
||||
if (readBytesCount != STATUS_BUFFER_SIZE) {
|
||||
throw new IOException("Invalid status notification, expected " + STATUS_BUFFER_SIZE + " bytes, got " + readBytesCount);
|
||||
|
@ -217,9 +218,8 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (isOpen())
|
||||
mReadStatusException = e;
|
||||
} catch (IOException e) {
|
||||
mReadStatusException = e;
|
||||
}
|
||||
//Log.d(TAG, "end control line status thread " + mStopReadStatusThread + " " + (mReadStatusException == null ? "-" : mReadStatusException.getMessage()));
|
||||
}
|
||||
|
@ -250,8 +250,8 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
/* throw and clear an exception which occurred in the status read thread */
|
||||
Exception readStatusException = mReadStatusException;
|
||||
/* throw and clear an exception which occured in the status read thread */
|
||||
IOException readStatusException = mReadStatusException;
|
||||
if (mReadStatusException != null) {
|
||||
mReadStatusException = null;
|
||||
throw new IOException(readStatusException);
|
||||
|
@ -265,10 +265,10 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
|
||||
@Override
|
||||
public void openInt() throws IOException {
|
||||
public void openInt(UsbDeviceConnection connection) throws IOException {
|
||||
UsbInterface usbInterface = mDevice.getInterface(0);
|
||||
|
||||
if (!mConnection.claimInterface(usbInterface, true)) {
|
||||
if (!connection.claimInterface(usbInterface, true)) {
|
||||
throw new IOException("Error claiming Prolific interface 0");
|
||||
}
|
||||
|
||||
|
@ -290,7 +290,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
byte[] rawDescriptors = mConnection.getRawDescriptors();
|
||||
byte[] rawDescriptors = connection.getRawDescriptors();
|
||||
if(rawDescriptors == null || rawDescriptors.length < 14) {
|
||||
throw new IOException("Could not get device descriptors");
|
||||
}
|
||||
|
@ -299,19 +299,15 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
byte maxPacketSize0 = rawDescriptors[7];
|
||||
if (mDevice.getDeviceClass() == 0x02 || maxPacketSize0 != 64) {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_01;
|
||||
} else if(usbVersion == 0x200) {
|
||||
if(deviceVersion == 0x300 && testHxStatus()) {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_T; // TA
|
||||
} else if(deviceVersion == 0x500 && testHxStatus()) {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_T; // TB
|
||||
} else {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_HXN;
|
||||
}
|
||||
} else if(deviceVersion == 0x300 && usbVersion == 0x200) {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_T; // TA
|
||||
} else if(deviceVersion == 0x500) {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_T; // TB
|
||||
} else if(usbVersion == 0x200 && !testHxStatus()) {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_HXN;
|
||||
} else {
|
||||
mDeviceType = DeviceType.DEVICE_TYPE_HX;
|
||||
}
|
||||
Log.d(TAG, String.format("usbVersion=%x, deviceVersion=%x, deviceClass=%d, packetSize=%d => deviceType=%s",
|
||||
usbVersion, deviceVersion, mDevice.getDeviceClass(), maxPacketSize0, mDeviceType.name()));
|
||||
resetDevice();
|
||||
doBlackMagic();
|
||||
setControlLines(mControlLinesValue);
|
||||
|
@ -567,7 +563,6 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings({"unused"})
|
||||
public static Map<Integer, int[]> getSupportedDevices() {
|
||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||
supportedDevices.put(UsbId.VENDOR_PROLIFIC,
|
||||
|
@ -576,6 +571,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
|||
UsbId.PROLIFIC_PL2303GC,
|
||||
UsbId.PROLIFIC_PL2303GB,
|
||||
UsbId.PROLIFIC_PL2303GT,
|
||||
UsbId.PROLIFIC_PL2303GT3,
|
||||
UsbId.PROLIFIC_PL2303GL,
|
||||
UsbId.PROLIFIC_PL2303GE,
|
||||
UsbId.PROLIFIC_PL2303GS,
|
||||
|
|
|
@ -9,8 +9,7 @@ import java.io.InterruptedIOException;
|
|||
* {@see InterruptedIOException#bytesTransferred} may contain bytes transferred
|
||||
*/
|
||||
public class SerialTimeoutException extends InterruptedIOException {
|
||||
public SerialTimeoutException(String s, int bytesTransferred) {
|
||||
public SerialTimeoutException(String s) {
|
||||
super(s);
|
||||
this.bytesTransferred = bytesTransferred;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,27 @@ public final class UsbId {
|
|||
public static final int FTDI_FT232H = 0x6014;
|
||||
public static final int FTDI_FT231X = 0x6015; // same ID for FT230X, FT231X, FT234XD
|
||||
|
||||
public static final int VENDOR_ATMEL = 0x03EB;
|
||||
public static final int ATMEL_LUFA_CDC_DEMO_APP = 0x2044;
|
||||
|
||||
public static final int VENDOR_ARDUINO = 0x2341;
|
||||
public static final int ARDUINO_UNO = 0x0001;
|
||||
public static final int ARDUINO_MEGA_2560 = 0x0010;
|
||||
public static final int ARDUINO_SERIAL_ADAPTER = 0x003b;
|
||||
public static final int ARDUINO_MEGA_ADK = 0x003f;
|
||||
public static final int ARDUINO_MEGA_2560_R3 = 0x0042;
|
||||
public static final int ARDUINO_UNO_R3 = 0x0043;
|
||||
public static final int ARDUINO_MEGA_ADK_R3 = 0x0044;
|
||||
public static final int ARDUINO_SERIAL_ADAPTER_R3 = 0x0044;
|
||||
public static final int ARDUINO_LEONARDO = 0x8036;
|
||||
public static final int ARDUINO_MICRO = 0x8037;
|
||||
|
||||
public static final int VENDOR_VAN_OOIJEN_TECH = 0x16c0;
|
||||
public static final int VAN_OOIJEN_TECH_TEENSYDUINO_SERIAL = 0x0483;
|
||||
|
||||
public static final int VENDOR_LEAFLABS = 0x1eaf;
|
||||
public static final int LEAFLABS_MAPLE = 0x0004;
|
||||
|
||||
public static final int VENDOR_SILABS = 0x10c4;
|
||||
public static final int SILABS_CP2102 = 0xea60; // same ID for CP2101, CP2103, CP2104, CP2109
|
||||
public static final int SILABS_CP2105 = 0xea70;
|
||||
|
@ -32,22 +53,22 @@ public final class UsbId {
|
|||
public static final int PROLIFIC_PL2303 = 0x2303; // device type 01, T, HX
|
||||
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
|
||||
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
|
||||
public static final int PROLIFIC_PL2303GT = 0x23c3; // "
|
||||
public static final int PROLIFIC_PL2303GL = 0x23d3; // "
|
||||
public static final int PROLIFIC_PL2303GT = 0x23cd; // "
|
||||
public static final int PROLIFIC_PL2303GT3 = 0x23c3; // "
|
||||
public static final int PROLIFIC_PL2303GL = 0x23e3; // "
|
||||
public static final int PROLIFIC_PL2303GE = 0x23e3; // "
|
||||
public static final int PROLIFIC_PL2303GS = 0x23f3; // "
|
||||
|
||||
public static final int VENDOR_GOOGLE = 0x18d1;
|
||||
public static final int GOOGLE_CR50 = 0x5014;
|
||||
|
||||
public static final int VENDOR_QINHENG = 0x1a86;
|
||||
public static final int QINHENG_CH340 = 0x7523;
|
||||
public static final int QINHENG_CH341A = 0x5523;
|
||||
|
||||
public static final int VENDOR_UNISOC = 0x1782;
|
||||
public static final int FIBOCOM_L610 = 0x4D10;
|
||||
public static final int FIBOCOM_L612 = 0x4D12;
|
||||
// at www.linux-usb.org/usb.ids listed for NXP/LPC1768, but all processors supported by ARM mbed DAPLink firmware report these ids
|
||||
public static final int VENDOR_ARM = 0x0d28;
|
||||
public static final int ARM_MBED = 0x0204;
|
||||
|
||||
public static final int VENDOR_ST = 0x0483;
|
||||
public static final int ST_CDC = 0x5740;
|
||||
|
||||
private UsbId() {
|
||||
throw new IllegalAccessError("Non-instantiable class");
|
||||
|
|
|
@ -10,17 +10,12 @@ import android.hardware.usb.UsbDevice;
|
|||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author mike wakerly (opensource@hoho.com)
|
||||
*/
|
||||
public interface UsbSerialDriver {
|
||||
|
||||
/*
|
||||
* Additional interface properties. Invoked thru reflection.
|
||||
*
|
||||
UsbSerialDriver(UsbDevice device); // constructor with device
|
||||
static Map<Integer, int[]> getSupportedDevices();
|
||||
static boolean probe(UsbDevice device); // optional
|
||||
*/
|
||||
|
||||
|
||||
/**
|
||||
* Returns the raw {@link UsbDevice} backing this port.
|
||||
*
|
||||
|
|
|
@ -58,7 +58,7 @@ public interface UsbSerialPort extends Closeable {
|
|||
int STOPBITS_2 = 2;
|
||||
|
||||
/** Values for get[Supported]ControlLines() */
|
||||
enum ControlLine { RTS, CTS, DTR, DSR, CD, RI }
|
||||
enum ControlLine { RTS, CTS, DTR, DSR, CD, RI }
|
||||
|
||||
/**
|
||||
* Returns the driver used by this port.
|
||||
|
@ -122,17 +122,6 @@ public interface UsbSerialPort extends Closeable {
|
|||
*/
|
||||
int read(final byte[] dest, final int timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Reads bytes with specified length into the destination buffer.
|
||||
*
|
||||
* @param dest the destination byte buffer
|
||||
* @param length the maximum length of the data to read
|
||||
* @param timeout the timeout for reading in milliseconds, 0 is infinite
|
||||
* @return the actual number of bytes read
|
||||
* @throws IOException if an error occurred during reading
|
||||
*/
|
||||
int read(final byte[] dest, int length, final int timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes as many bytes as possible from the source buffer.
|
||||
*
|
||||
|
@ -144,18 +133,6 @@ public interface UsbSerialPort extends Closeable {
|
|||
*/
|
||||
void write(final byte[] src, final int timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Writes bytes with specified length from the source buffer.
|
||||
*
|
||||
* @param src the source byte buffer
|
||||
* @param length the length of the data to write
|
||||
* @param timeout the timeout for writing in milliseconds, 0 is infinite
|
||||
* @throws SerialTimeoutException if timeout reached before sending all data.
|
||||
* ex.bytesTransferred may contain bytes transferred
|
||||
* @throws IOException if an error occurred during writing
|
||||
*/
|
||||
void write(final byte[] src, int length, final int timeout) throws IOException;
|
||||
|
||||
/**
|
||||
* Sets various serial port parameters.
|
||||
*
|
||||
|
|
|
@ -37,8 +37,6 @@ public class UsbSerialProber {
|
|||
probeTable.addDriver(FtdiSerialDriver.class);
|
||||
probeTable.addDriver(ProlificSerialDriver.class);
|
||||
probeTable.addDriver(Ch34xSerialDriver.class);
|
||||
probeTable.addDriver(GsmModemSerialDriver.class);
|
||||
probeTable.addDriver(ChromeCcdSerialDriver.class);
|
||||
return probeTable;
|
||||
}
|
||||
|
||||
|
@ -71,7 +69,11 @@ public class UsbSerialProber {
|
|||
* {@code null} if none available.
|
||||
*/
|
||||
public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {
|
||||
final Class<? extends UsbSerialDriver> driverClass = mProbeTable.findDriver(usbDevice);
|
||||
final int vendorId = usbDevice.getVendorId();
|
||||
final int productId = usbDevice.getProductId();
|
||||
|
||||
final Class<? extends UsbSerialDriver> driverClass =
|
||||
mProbeTable.findDriver(vendorId, productId);
|
||||
if (driverClass != null) {
|
||||
final UsbSerialDriver driver;
|
||||
try {
|
||||
|
|
|
@ -1,158 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.emulator.calculator.usbserial.util;
|
||||
|
||||
import java.security.InvalidParameterException;
|
||||
|
||||
/**
|
||||
* Clone of Android's /core/java/com/android/internal/util/HexDump class, for use in debugging.
|
||||
* Changes: space separated hex strings
|
||||
*/
|
||||
public class HexDump {
|
||||
private final static char[] HEX_DIGITS = {
|
||||
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
|
||||
};
|
||||
|
||||
private HexDump() {
|
||||
}
|
||||
|
||||
public static String dumpHexString(byte[] array) {
|
||||
return dumpHexString(array, 0, array.length);
|
||||
}
|
||||
|
||||
public static String dumpHexString(byte[] array, int offset, int length) {
|
||||
StringBuilder result = new StringBuilder();
|
||||
|
||||
byte[] line = new byte[8];
|
||||
int lineIndex = 0;
|
||||
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
if (lineIndex == line.length) {
|
||||
for (int j = 0; j < line.length; j++) {
|
||||
if (line[j] > ' ' && line[j] < '~') {
|
||||
result.append(new String(line, j, 1));
|
||||
} else {
|
||||
result.append(".");
|
||||
}
|
||||
}
|
||||
|
||||
result.append("\n");
|
||||
lineIndex = 0;
|
||||
}
|
||||
|
||||
byte b = array[i];
|
||||
result.append(HEX_DIGITS[(b >>> 4) & 0x0F]);
|
||||
result.append(HEX_DIGITS[b & 0x0F]);
|
||||
result.append(" ");
|
||||
|
||||
line[lineIndex++] = b;
|
||||
}
|
||||
|
||||
for (int i = 0; i < (line.length - lineIndex); i++) {
|
||||
result.append(" ");
|
||||
}
|
||||
for (int i = 0; i < lineIndex; i++) {
|
||||
if (line[i] > ' ' && line[i] < '~') {
|
||||
result.append(new String(line, i, 1));
|
||||
} else {
|
||||
result.append(".");
|
||||
}
|
||||
}
|
||||
|
||||
return result.toString();
|
||||
}
|
||||
|
||||
public static String toHexString(byte b) {
|
||||
return toHexString(toByteArray(b));
|
||||
}
|
||||
|
||||
public static String toHexString(byte[] array) {
|
||||
return toHexString(array, 0, array.length);
|
||||
}
|
||||
|
||||
public static String toHexString(byte[] array, int offset, int length) {
|
||||
char[] buf = new char[length > 0 ? length * 3 - 1 : 0];
|
||||
|
||||
int bufIndex = 0;
|
||||
for (int i = offset; i < offset + length; i++) {
|
||||
if (i > offset)
|
||||
buf[bufIndex++] = ' ';
|
||||
byte b = array[i];
|
||||
buf[bufIndex++] = HEX_DIGITS[(b >>> 4) & 0x0F];
|
||||
buf[bufIndex++] = HEX_DIGITS[b & 0x0F];
|
||||
}
|
||||
|
||||
return new String(buf);
|
||||
}
|
||||
|
||||
public static String toHexString(int i) {
|
||||
return toHexString(toByteArray(i));
|
||||
}
|
||||
|
||||
public static String toHexString(short i) {
|
||||
return toHexString(toByteArray(i));
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(byte b) {
|
||||
byte[] array = new byte[1];
|
||||
array[0] = b;
|
||||
return array;
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(int i) {
|
||||
byte[] array = new byte[4];
|
||||
|
||||
array[3] = (byte) (i & 0xFF);
|
||||
array[2] = (byte) ((i >> 8) & 0xFF);
|
||||
array[1] = (byte) ((i >> 16) & 0xFF);
|
||||
array[0] = (byte) ((i >> 24) & 0xFF);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
public static byte[] toByteArray(short i) {
|
||||
byte[] array = new byte[2];
|
||||
|
||||
array[1] = (byte) (i & 0xFF);
|
||||
array[0] = (byte) ((i >> 8) & 0xFF);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
private static int toByte(char c) {
|
||||
if (c >= '0' && c <= '9')
|
||||
return (c - '0');
|
||||
if (c >= 'A' && c <= 'F')
|
||||
return (c - 'A' + 10);
|
||||
if (c >= 'a' && c <= 'f')
|
||||
return (c - 'a' + 10);
|
||||
|
||||
throw new InvalidParameterException("Invalid hex char '" + c + "'");
|
||||
}
|
||||
|
||||
/** accepts any separator, e.g. space or newline */
|
||||
public static byte[] hexStringToByteArray(String hexString) {
|
||||
int length = hexString.length();
|
||||
byte[] buffer = new byte[(length + 1) / 3];
|
||||
|
||||
for (int i = 0; i < length; i += 3) {
|
||||
buffer[i / 3] = (byte) ((toByte(hexString.charAt(i)) << 4) | toByte(hexString.charAt(i + 1)));
|
||||
}
|
||||
|
||||
return buffer;
|
||||
}
|
||||
}
|
|
@ -9,7 +9,6 @@ package org.emulator.calculator.usbserial.util;
|
|||
import android.os.Process;
|
||||
import android.util.Log;
|
||||
|
||||
import org.emulator.calculator.usbserial.driver.SerialTimeoutException;
|
||||
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
||||
|
||||
import java.io.IOException;
|
||||
|
@ -22,15 +21,8 @@ import java.nio.ByteBuffer;
|
|||
*/
|
||||
public class SerialInputOutputManager implements Runnable {
|
||||
|
||||
public enum State {
|
||||
STOPPED,
|
||||
RUNNING,
|
||||
STOPPING
|
||||
}
|
||||
|
||||
public static boolean DEBUG = false;
|
||||
|
||||
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
|
||||
public static boolean DEBUG = false;
|
||||
private static final int BUFSIZ = 4096;
|
||||
|
||||
/**
|
||||
|
@ -45,6 +37,12 @@ public class SerialInputOutputManager implements Runnable {
|
|||
private ByteBuffer mReadBuffer; // default size = getReadEndpoint().getMaxPacketSize()
|
||||
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
||||
|
||||
public enum State {
|
||||
STOPPED,
|
||||
RUNNING,
|
||||
STOPPING
|
||||
}
|
||||
|
||||
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
|
||||
private State mState = State.STOPPED; // Synchronized by 'this'
|
||||
private Listener mListener; // Synchronized by 'this'
|
||||
|
@ -204,11 +202,7 @@ public class SerialInputOutputManager implements Runnable {
|
|||
step();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if(mSerialPort.isOpen()) {
|
||||
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
||||
} else {
|
||||
Log.i(TAG, "Socket closed");
|
||||
}
|
||||
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
||||
final Listener listener = getListener();
|
||||
if (listener != null) {
|
||||
listener.onRunError(e);
|
||||
|
@ -229,9 +223,7 @@ public class SerialInputOutputManager implements Runnable {
|
|||
}
|
||||
int len = mSerialPort.read(buffer, mReadTimeout);
|
||||
if (len > 0) {
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "Read data len=" + len);
|
||||
}
|
||||
if (DEBUG) Log.d(TAG, "Read data len=" + len);
|
||||
final Listener listener = getListener();
|
||||
if (listener != null) {
|
||||
final byte[] data = new byte[len];
|
||||
|
@ -255,23 +247,7 @@ public class SerialInputOutputManager implements Runnable {
|
|||
if (DEBUG) {
|
||||
Log.d(TAG, "Writing data len=" + len);
|
||||
}
|
||||
try {
|
||||
mSerialPort.write(buffer, mWriteTimeout);
|
||||
} catch (SerialTimeoutException ex) {
|
||||
synchronized (mWriteBufferLock) {
|
||||
byte[] buffer2 = null;
|
||||
int len2 = mWriteBuffer.position();
|
||||
if (len2 > 0) {
|
||||
buffer2 = new byte[len2];
|
||||
mWriteBuffer.rewind();
|
||||
mWriteBuffer.get(buffer2, 0, len2);
|
||||
mWriteBuffer.clear();
|
||||
}
|
||||
mWriteBuffer.put(buffer, ex.bytesTransferred, buffer.length - ex.bytesTransferred);
|
||||
if (buffer2 != null)
|
||||
mWriteBuffer.put(buffer2);
|
||||
}
|
||||
}
|
||||
mSerialPort.write(buffer, mWriteTimeout);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,33 +0,0 @@
|
|||
package org.emulator.calculator.usbserial.util;
|
||||
|
||||
import android.hardware.usb.UsbDeviceConnection;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
public class UsbUtils {
|
||||
|
||||
private UsbUtils() {
|
||||
}
|
||||
|
||||
public static ArrayList<byte[]> getDescriptors(UsbDeviceConnection connection) {
|
||||
ArrayList<byte[]> descriptors = new ArrayList<>();
|
||||
byte[] rawDescriptors = connection.getRawDescriptors();
|
||||
if (rawDescriptors != null) {
|
||||
int pos = 0;
|
||||
while (pos < rawDescriptors.length) {
|
||||
int len = rawDescriptors[pos] & 0xFF;
|
||||
if (len == 0)
|
||||
break;
|
||||
if (pos + len > rawDescriptors.length)
|
||||
len = rawDescriptors.length - pos;
|
||||
byte[] descriptor = new byte[len];
|
||||
System.arraycopy(rawDescriptors, pos, descriptor, 0, len);
|
||||
descriptors.add(descriptor);
|
||||
pos += len;
|
||||
}
|
||||
}
|
||||
return descriptors;
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -140,13 +140,13 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
// Most Recently Used state files
|
||||
private final int MRU_ID_START = 10000;
|
||||
private final int MAX_MRU = 5;
|
||||
private LinkedHashMap<String, String> mruLinkedHashMap = new LinkedHashMap<String, String>(5, 1.0f, true) {
|
||||
private final LinkedHashMap<String, String> mruLinkedHashMap = new LinkedHashMap<String, String>(5, 1.0f, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry eldest) {
|
||||
return size() > MAX_MRU;
|
||||
}
|
||||
};
|
||||
private HashMap<Integer, String> mruByMenuId = new HashMap<>();
|
||||
private final HashMap<Integer, String> mruByMenuId = new HashMap<>();
|
||||
|
||||
private final PrinterSimulator printerSimulator = new PrinterSimulator();
|
||||
private final PrinterSimulatorFragment fragmentPrinterSimulator = new PrinterSimulatorFragment();
|
||||
|
@ -246,7 +246,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
}
|
||||
|
||||
if(documentToOpenUrl != null && documentToOpenUrl.length() > 0)
|
||||
if(documentToOpenUrl != null && !documentToOpenUrl.isEmpty())
|
||||
try {
|
||||
// FileOpen auto-open.
|
||||
onFileOpen(documentToOpenUrl, intent, null);
|
||||
|
@ -276,7 +276,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
for (int i = mrus.length - 1; i >= 0; i--) {
|
||||
String mostRecentlyUsedFile = mrus[i];
|
||||
String displayName = getFilenameFromURL(mostRecentlyUsedFile);
|
||||
if(displayName == null || displayName.equals("") || displayName.equals(mostRecentlyUsedFile)) {
|
||||
if(displayName == null || displayName.isEmpty() || displayName.equals(mostRecentlyUsedFile)) {
|
||||
// We should remove this file because it seems impossible to get the display name of this Most Recently Used state file.
|
||||
// It might be deleted or the permissions does not allow to reach it anymore.
|
||||
mruLinkedHashMap.remove(mostRecentlyUsedFile);
|
||||
|
@ -301,7 +301,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
|
||||
if (NativeLib.isDocumentAvailable() && settings.getBoolean("settings_autosave", true)) {
|
||||
String currentFilename = NativeLib.getCurrentFilename();
|
||||
if (currentFilename != null && currentFilename.length() > 0)
|
||||
if (currentFilename != null && !currentFilename.isEmpty())
|
||||
onFileSave();
|
||||
}
|
||||
|
||||
|
@ -1140,7 +1140,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
saveWhenLaunchingActivity = false;
|
||||
startActivityForResult(intent, INTENT_LOAD_FLASH_ROM);
|
||||
};
|
||||
if(currentFlashPort2Url != null && currentFlashPort2Url.length() > 0)
|
||||
if(currentFlashPort2Url != null && !currentFlashPort2Url.isEmpty())
|
||||
new AlertDialog.Builder(this)
|
||||
.setTitle(getString(R.string.alert_losing_flash_rom_title))
|
||||
.setMessage(getString(R.string.alert_losing_flash_rom_message))
|
||||
|
@ -1165,8 +1165,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
// Reset to default Flash ROM from the KML file
|
||||
settings.putString("settings_flash_port2", null);
|
||||
String kmlFilename = NativeLib.getCurrentKml();
|
||||
if(kmlFilename.length() > 0) {
|
||||
String kmlFolder = kmlFolderURL == null || kmlFolderURL.length() == 0 ? null : kmlFolderURL;
|
||||
if(!kmlFilename.isEmpty()) {
|
||||
String kmlFolder = kmlFolderURL == null || kmlFolderURL.isEmpty() ? null : kmlFolderURL;
|
||||
// Reset the flashROM
|
||||
NativeLib.onLoadFlashROM("");
|
||||
// Load the KML file again. TODO If it goes wrong, we are lost.
|
||||
|
@ -1237,7 +1237,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
updateFromPreferences("settings_flash_port2", true);
|
||||
displayFilename(url);
|
||||
String settingsFlashPort2Url = settings.getString("settings_flash_port2", null);
|
||||
if(settingsFlashPort2Url != null && settingsFlashPort2Url.length() > 0)
|
||||
if(settingsFlashPort2Url != null && !settingsFlashPort2Url.isEmpty())
|
||||
showAlert(String.format(Locale.US, getString(R.string.message_state_and_flash_saved), getFilenameFromURL(url), getFilenameFromURL(settingsFlashPort2Url)));
|
||||
else
|
||||
showAlert(String.format(Locale.US, getString(R.string.message_state_saved), getFilenameFromURL(url)));
|
||||
|
@ -1344,8 +1344,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
// Not possible to save the current FlashROM :-( [NativeLib.onSaveFlashROM(url);]
|
||||
// So, we are going to create a new one from the ROM loaded by the current KML script!
|
||||
String kmlFilename = NativeLib.getCurrentKml();
|
||||
if(kmlFilename != null && kmlFilename.length() > 0) {
|
||||
if(kmlFolderURL != null && kmlFolderURL.length() > 0)
|
||||
if(kmlFilename != null && !kmlFilename.isEmpty()) {
|
||||
if(kmlFolderURL != null && !kmlFolderURL.isEmpty())
|
||||
copyROMFromFolder(kmlFilename, uri);
|
||||
else
|
||||
copyROMFromAsset(kmlFilename, uri);
|
||||
|
@ -1453,7 +1453,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
}
|
||||
}
|
||||
if(romFilename != null && romFilename.length() > 0) {
|
||||
if(romFilename != null && !romFilename.isEmpty()) {
|
||||
ParcelFileDescriptor pfdROM = openFileInFolderFromContentResolverPFD(romFilename, kmlFolderURL, GENERIC_READ);
|
||||
if(pfdROM != null) {
|
||||
try {
|
||||
|
@ -1479,7 +1479,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
try {
|
||||
kmlInputStream = assetManager.open("calculators/" + kmlFilename);
|
||||
String romFilename = extractROMFilename(kmlInputStream);
|
||||
if(romFilename != null && romFilename.length() > 0) {
|
||||
if(romFilename != null && !romFilename.isEmpty()) {
|
||||
InputStream romInputStream = assetManager.open("calculators/" + romFilename);
|
||||
copyROMtoFlashROM(romInputStream, uri);
|
||||
}
|
||||
|
@ -1583,7 +1583,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
if(getPackageName().contains("org.emulator.forty.eight") && settings.getBoolean("settings_port2en", false)) {
|
||||
// Check if the access to the port2 shared file is still possible.
|
||||
String port2Url = settings.getString("settings_port2load", "");
|
||||
if(port2Url != null && port2Url.length() > 0) {
|
||||
if(port2Url != null && !port2Url.isEmpty()) {
|
||||
Uri port2Uri = Uri.parse(port2Url);
|
||||
DocumentFile port2DocumentFile = DocumentFile.fromSingleUri(this, port2Uri);
|
||||
if (port2DocumentFile == null || !port2DocumentFile.exists()) {
|
||||
|
@ -1706,7 +1706,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
updateFromPreferences("settings_flash_port2", true);
|
||||
|
||||
String settingsFlashPort2Url = settings.getString("settings_flash_port2", null);
|
||||
if(settingsFlashPort2Url != null && settingsFlashPort2Url.length() > 0)
|
||||
if(settingsFlashPort2Url != null && !settingsFlashPort2Url.isEmpty())
|
||||
showAlert(String.format(Locale.US, getString(R.string.message_state_and_flash_saved), getFilenameFromURL(currentFilenameUrl), getFilenameFromURL(settingsFlashPort2Url)));
|
||||
else
|
||||
showAlert(String.format(Locale.US, getString(R.string.message_state_saved), getFilenameFromURL(currentFilenameUrl)));
|
||||
|
@ -1716,7 +1716,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
private void displayFilename(String stateFileURL) {
|
||||
String displayName = getFilenameFromURL(stateFileURL == null ? "" : stateFileURL);
|
||||
String port2FileURL = settings.getString("settings_flash_port2", null);
|
||||
if(port2FileURL != null && port2FileURL.length() > 0)
|
||||
if(port2FileURL != null && !port2FileURL.isEmpty())
|
||||
displayName += " " + getFilenameFromURL(port2FileURL);
|
||||
View headerView = displayKMLTitle();
|
||||
if(headerView != null) {
|
||||
|
@ -2082,14 +2082,14 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
|
||||
private int serialIndex = 1;
|
||||
private HashMap<Integer, Serial> serialsById = new HashMap<>();
|
||||
private final HashMap<Integer, Serial> serialsById = new HashMap<>();
|
||||
|
||||
@SuppressWarnings("UnusedDeclaration")
|
||||
int openSerialPort(String serialPort) {
|
||||
// Search if this same serial port is not already opened
|
||||
|
||||
|
||||
Integer serialPortId = serialIndex;
|
||||
int serialPortId = serialIndex;
|
||||
Serial serial = new Serial(this, serialPortId);
|
||||
if(serial.connect(serialPort)) {
|
||||
serialsById.put(serialPortId, serial);
|
||||
|
@ -2104,10 +2104,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
String connectionStatus = serial.getConnectionStatus();
|
||||
try {
|
||||
int resId = Utils.resId(MainActivity.this, "string", connectionStatus);
|
||||
Toast.makeText(MainActivity.this, resId, Toast.LENGTH_LONG).show();
|
||||
Toast.makeText(MainActivity.this, resId, Toast.LENGTH_SHORT).show();
|
||||
} catch (Exception ex) {
|
||||
Log.e(TAG, ex.getMessage());
|
||||
Toast.makeText(MainActivity.this, "Unknown error, connectionStatus: " + connectionStatus, Toast.LENGTH_LONG).show();
|
||||
Log.e(TAG, "Unknown error, connectionStatus: " + connectionStatus + ", " + ex.getMessage());
|
||||
Toast.makeText(MainActivity.this, "Unknown error, connectionStatus: " + connectionStatus, Toast.LENGTH_SHORT).show();
|
||||
}
|
||||
});
|
||||
return 0;
|
||||
|
@ -2200,7 +2200,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
}
|
||||
|
||||
private void setPort1Settings(boolean port1Plugged, boolean port1Writable) {
|
||||
if(this.getClass().getPackage().getName().equals("org.emulator.forty.eight")) {
|
||||
Package pack = this.getClass().getPackage();
|
||||
if(pack != null && pack.getName().equals("org.emulator.forty.eight")) {
|
||||
settings.putBoolean("settings_port1en", port1Plugged);
|
||||
settings.putBoolean("settings_port1wr", port1Writable);
|
||||
updateFromPreferences("settings_port1", true);
|
||||
|
@ -2224,7 +2225,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
switch (key) {
|
||||
case "settings_realspeed":
|
||||
case "settings_grayscale":
|
||||
NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null);
|
||||
case "settings_serial_slowdown":
|
||||
NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null);
|
||||
break;
|
||||
|
||||
case "settings_rotation":
|
||||
|
@ -2347,9 +2349,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
|||
NativeLib.setConfiguration("settings_serial_ports_ir", isDynamicValue, 0, 0,
|
||||
DevicesFragment.SerialConnectParameters.fromSettingsString(settings.getString("settings_serial_ports_ir", "")).toWin32String());
|
||||
break;
|
||||
case "settings_serial_slowdown":
|
||||
NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
|||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:8.4.2'
|
||||
classpath 'com.android.tools.build:gradle:8.6.1'
|
||||
|
||||
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||
# Specifies the JVM arguments used for the daemon process.
|
||||
# The setting is particularly useful for tweaking memory settings.
|
||||
android.defaults.buildfeatures.buildconfig=true
|
||||
#android.defaults.buildfeatures.buildconfig=true
|
||||
android.enableJetifier=true
|
||||
android.nonFinalResIds=true
|
||||
android.nonTransitiveRClass=true
|
||||
|
|
2
gradle/wrapper/gradle-wrapper.properties
vendored
2
gradle/wrapper/gradle-wrapper.properties
vendored
|
@ -1,6 +1,6 @@
|
|||
#Sat Jan 28 21:16:38 CET 2023
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
|
Loading…
Reference in a new issue