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)
|
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)
|
Version 2.7 (2024-06-14)
|
||||||
|
@ -277,6 +277,7 @@ FAQ
|
||||||
TODO
|
TODO
|
||||||
|
|
||||||
- NDK 26 does not compile
|
- 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).
|
- 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 an "haptic" feedback with a sound instead of a vibration (F. Giampietro).
|
||||||
- Add a Cancel button to the HP48 memory card creator dialog.
|
- 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/disrpl.c
|
||||||
# src/main/cpp/core/Emu48.c #-> To rewrite
|
# src/main/cpp/core/Emu48.c #-> To rewrite
|
||||||
src/main/cpp/core/engine.c
|
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/fetch.c
|
||||||
src/main/cpp/core/files.c
|
src/main/cpp/core/files.c
|
||||||
src/main/cpp/core/i28f160.c
|
src/main/cpp/core/i28f160.c
|
||||||
|
|
|
@ -34,8 +34,8 @@ android {
|
||||||
applicationId "org.emulator.forty.eight"
|
applicationId "org.emulator.forty.eight"
|
||||||
minSdk 21
|
minSdk 21
|
||||||
targetSdk 34
|
targetSdk 34
|
||||||
versionCode 27
|
versionCode 26
|
||||||
versionName "2.8"
|
versionName "2.7"
|
||||||
setProperty("archivesBaseName", "Emu48-v$versionName")
|
setProperty("archivesBaseName", "Emu48-v$versionName")
|
||||||
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
|
|
|
@ -16,7 +16,6 @@
|
||||||
android:fullBackupContent="@xml/backup_descriptor">
|
android:fullBackupContent="@xml/backup_descriptor">
|
||||||
<activity
|
<activity
|
||||||
android:name=".MainActivity"
|
android:name=".MainActivity"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
|
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
|
||||||
android:launchMode="singleTop"
|
android:launchMode="singleTop"
|
||||||
android:theme="@style/AppTheme.NoActionBar"
|
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
|
"String" object in stack level 1 to the clipboard. On all
|
||||||
other objects, the command will be ignored. This prevents sending
|
other objects, the command will be ignored. This prevents sending
|
||||||
binary objects to the clipboard.</p>
|
binary objects to the clipboard.</p>
|
||||||
<p>The decimal point (radix mark) of "Real Numbers" in the
|
<p>The decimal point of "Real Numbers" in the clipboard is
|
||||||
clipboard is equal to the calculator setting. This is important when
|
equal to the calculator setting. This is important when you try to
|
||||||
you try to paste the numbers into a program using the locale settings
|
paste the numbers into a program using the locale settings of the host
|
||||||
of the host operating system.</p>
|
operating system.</p>
|
||||||
<h2><a name=ss9.5>9.5 Paste Stack</a></h2>
|
<h2><a name=ss9.5>9.5 Paste Stack</a></h2>
|
||||||
<p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
|
<p>This menu item is enabled for the HP48SX, HP48GX and the HP49G
|
||||||
emulation.</p>
|
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
|
object. Is the content a complex number object, the number will be
|
||||||
saved as "Complex Number" object, otherwise cases as
|
saved as "Complex Number" object, otherwise cases as
|
||||||
"String" object.</p>
|
"String" object.</p>
|
||||||
<p>To import "Real or Complex Numbers" from the clipboard, the
|
<p>To import "Real Numbers" from the clipboard, the decimal
|
||||||
decimal point (radix mark) of the clipboard and calculator <u>must</u>
|
point character of the clipboard and calculator <u>must not match</u> any
|
||||||
match. A real or complex number is only detected in the case of valid
|
more. There's an auto detection for decoding the thousands separator and
|
||||||
real number characters in the clipboard. Especially heading and tailing
|
decimal point character. The thousands separator is removed at decoding.
|
||||||
white spaces aren't valid number characters also.</p>
|
A real number is detected in the case of valid real number characters in
|
||||||
<p>Complex numbers must be in the form <i>(a,b)</i> when using the point
|
the clipboard.</p>
|
||||||
radix mark or in the form <i>(a;b)</i> when using the comma radix mark.
|
<p>"Complex Numbers" must be in the form <i>(a,b)</i> when
|
||||||
The Cartesian or algebraic form <i>a+bi</i> is not supported.</p>
|
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>
|
<h2><a name=ss9.6>9.6 Reset Calculator</a></h2>
|
||||||
<p>This emulates the Reset pin of the internal CPU.</p>
|
<p>This emulates the Reset pin of the internal CPU.</p>
|
||||||
<h2><a name=ss9.7>9.7 Backup</a></h2>
|
<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>
|
Cyrille de Brebisson of Hewlett-Packard.</p>
|
||||||
<h1><a name=s15>15. License</a></h1>
|
<h1><a name=s15>15. License</a></h1>
|
||||||
<p>Emu48 - A HP38G/39G/40G/48SX/48GX/49G Emulator<br>
|
<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
|
<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
|
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)
|
Software Foundation; either version 2 of the License, or (at your option)
|
||||||
|
|
|
@ -58,11 +58,6 @@ LINKS
|
||||||
|
|
||||||
CHANGES
|
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)
|
Version 2.7 (2024-06-14)
|
||||||
|
|
||||||
- Updated source code with Emu48 version 1.65+. This new version improve the serial communication.
|
- Updated source code with Emu48 version 1.65+. This new version improve the serial communication.
|
||||||
|
|
|
@ -13,7 +13,7 @@
|
||||||
#include "kml.h"
|
#include "kml.h"
|
||||||
#include "debugger.h"
|
#include "debugger.h"
|
||||||
|
|
||||||
#define VERSION "1.65+"
|
#define VERSION "1.66+"
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
LPCTSTR szNoTitle = _T("Emu48 ")_T(VERSION)_T(" 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;
|
MSG msg;
|
||||||
WNDCLASS wc;
|
WNDCLASS wc;
|
||||||
ATOM classAtom;
|
ATOM classAtom;
|
||||||
|
WSADATA wsd;
|
||||||
RECT rectWindow;
|
RECT rectWindow;
|
||||||
HACCEL hAccel;
|
HACCEL hAccel;
|
||||||
DWORD dwThreadId;
|
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);
|
_CrtSetDbgFlag(_CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF);
|
||||||
|
|
||||||
hApp = hInst;
|
hApp = hInst;
|
||||||
#if defined _UNICODE
|
nArgc = __argc; // no. of command line arguments
|
||||||
{
|
ppArgv = __targv; // command line arguments
|
||||||
ppArgv = (LPCTSTR*) CommandLineToArgvW(GetCommandLine(),&nArgc);
|
|
||||||
}
|
|
||||||
#else
|
|
||||||
{
|
|
||||||
nArgc = __argc; // no. of command line arguments
|
|
||||||
ppArgv = (LPCTSTR*) __argv; // command line arguments
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
wc.style = CS_BYTEALIGNCLIENT;
|
wc.style = CS_BYTEALIGNCLIENT;
|
||||||
wc.lpfnWndProc = (WNDPROC)MainWndProc;
|
wc.lpfnWndProc = (WNDPROC)MainWndProc;
|
||||||
|
@ -2298,6 +2291,7 @@ int WINAPI WinMain(HINSTANCE hInst, HINSTANCE hPrevInst, LPSTR lpCmdLine, int nC
|
||||||
if (NewDocument()) SetWindowTitle(_T("Untitled"));
|
if (NewDocument()) SetWindowTitle(_T("Untitled"));
|
||||||
|
|
||||||
start:
|
start:
|
||||||
|
VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0);
|
||||||
if (bStartupBackup) SaveBackup(); // make a RAM backup at startup
|
if (bStartupBackup) SaveBackup(); // make a RAM backup at startup
|
||||||
if (pbyRom) SwitchToState(SM_RUN);
|
if (pbyRom) SwitchToState(SM_RUN);
|
||||||
|
|
||||||
|
@ -2313,6 +2307,7 @@ start:
|
||||||
DispatchMessage(&msg);
|
DispatchMessage(&msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
WSACleanup(); // cleanup network stack
|
||||||
|
|
||||||
// clean up DDE server
|
// clean up DDE server
|
||||||
DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER);
|
DdeNameService(idDdeInst, hszService, NULL, DNS_UNREGISTER);
|
||||||
|
|
|
@ -369,6 +369,7 @@ extern BOOL SendByteUdp(BYTE byData);
|
||||||
|
|
||||||
// Stack.c
|
// Stack.c
|
||||||
extern BOOL bDetectClpObject;
|
extern BOOL bDetectClpObject;
|
||||||
|
extern BOOL bLocaleDecimalPoint;
|
||||||
extern LRESULT OnStackCopy(VOID);
|
extern LRESULT OnStackCopy(VOID);
|
||||||
extern LRESULT OnStackPaste(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('8'),_T('9'),_T('A'),_T('B'),
|
||||||
_T('C'),_T('D'),_T('E'),_T('F') };
|
_T('C'),_T('D'),_T('E'),_T('F') };
|
||||||
|
|
||||||
static INT nDbgPosX = 0; // position of debugger window
|
static INT nDbgPosX = CW_USEDEFAULT; // position of debugger window
|
||||||
static INT nDbgPosY = 0;
|
static INT nDbgPosY = CW_USEDEFAULT;
|
||||||
|
|
||||||
static WORD wBreakpointCount = 0; // number of breakpoints
|
static WORD wBreakpointCount = 0; // number of breakpoints
|
||||||
static BP_T sBreakpoint[MAXBREAKPOINTS]; // breakpoint table
|
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)
|
switch (message)
|
||||||
{
|
{
|
||||||
case WM_INITDIALOG:
|
case WM_INITDIALOG:
|
||||||
|
if (nDbgPosX != CW_USEDEFAULT) // not default window position
|
||||||
|
{
|
||||||
SetWindowLocation(hDlg,nDbgPosX,nDbgPosY);
|
SetWindowLocation(hDlg,nDbgPosX,nDbgPosY);
|
||||||
|
}
|
||||||
if (bAlwaysOnTop) SetWindowPos(hDlg,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
|
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)));
|
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
|
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)
|
(DLGPROC)Debugger)) == NULL)
|
||||||
AbortMessage(_T("Debugger Dialog Box Creation Error !"));
|
AbortMessage(_T("Debugger Dialog Box Creation Error !"));
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -3501,46 +3504,79 @@ static BOOL OnBrowseSaveMem(HWND hDlg)
|
||||||
//
|
//
|
||||||
// write file to memory
|
// write file to memory
|
||||||
//
|
//
|
||||||
static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr)
|
static BOOL LoadMemData(LPCTSTR lpszFilename,DWORD dwStartAddr,UINT uBitMode)
|
||||||
{
|
{
|
||||||
HANDLE hFile;
|
HANDLE hFile;
|
||||||
DWORD dwRead;
|
DWORD dwFileSize,dwRead;
|
||||||
BYTE byData;
|
LPBYTE pbyData;
|
||||||
|
|
||||||
hFile = CreateFile(lpszFilename,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,FILE_FLAG_SEQUENTIAL_SCAN,NULL);
|
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
|
if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file
|
||||||
return FALSE;
|
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);
|
ReadFile(hFile,pbyData,dwFileSize,&dwRead,NULL);
|
||||||
if (dwRead == 0) break; // EOF
|
if (uBitMode == 2) // auto mode (0=8-bit, 1=4-bit, 2=auto)
|
||||||
|
|
||||||
if (dwStartAddr < 0xFFFFF)
|
|
||||||
{
|
{
|
||||||
Write2(dwStartAddr,byData); // write byte in map mode
|
BOOL bPacked = FALSE; // data not packed
|
||||||
dwStartAddr += 2;
|
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
|
else // special handling to avoid address wrap around
|
||||||
{
|
{
|
||||||
byData &= 0xF;
|
free(pbyData);
|
||||||
Nwrite(&byData,dwStartAddr,1); // write nibble in map mode
|
pbyData = NULL;
|
||||||
++dwStartAddr;
|
}
|
||||||
|
}
|
||||||
|
if (pbyData) // have data to save
|
||||||
|
{
|
||||||
|
LPBYTE p = pbyData;
|
||||||
|
while (dwFileSize > 0 && dwStartAddr <= 0xFFFFF)
|
||||||
|
{
|
||||||
|
Nwrite(p++,dwStartAddr++,1);
|
||||||
|
--dwFileSize;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
free(pbyData);
|
||||||
|
}
|
||||||
CloseHandle(hFile);
|
CloseHandle(hFile);
|
||||||
return TRUE;
|
return pbyData != NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
//
|
//
|
||||||
// write memory data to file
|
// 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;
|
HANDLE hFile;
|
||||||
DWORD dwAddr,dwWritten;
|
DWORD dwAddr,dwSend,dwWritten;
|
||||||
BYTE byData;
|
BYTE byData[2];
|
||||||
|
|
||||||
hFile = CreateFile(lpszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
hFile = CreateFile(lpszFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL);
|
||||||
if (hFile == INVALID_HANDLE_VALUE) // error, couldn't create a new file
|
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)
|
for (dwAddr = dwStartAddr; dwAddr <= dwEndAddr; dwAddr += 2)
|
||||||
{
|
{
|
||||||
_ASSERT(dwAddr <= 0xFFFFF);
|
_ASSERT(dwAddr <= 0xFFFFF);
|
||||||
byData = Read2(dwAddr); // read byte in map mode
|
Npeek(byData,dwAddr,2); // read two nibble in map mode
|
||||||
WriteFile(hFile,&byData,sizeof(byData),&dwWritten,NULL);
|
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);
|
CloseHandle(hFile);
|
||||||
|
@ -3564,9 +3606,14 @@ static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
{
|
{
|
||||||
TCHAR szFilename[MAX_PATH];
|
TCHAR szFilename[MAX_PATH];
|
||||||
DWORD dwStartAddr;
|
DWORD dwStartAddr;
|
||||||
|
int nButton;
|
||||||
|
UINT uBitMode;
|
||||||
|
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
CheckDlgButton(hDlg,IDC_DEBUG_DATA_LOAD_ABIT,BST_CHECKED);
|
||||||
|
return TRUE;
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
switch(LOWORD(wParam))
|
switch(LOWORD(wParam))
|
||||||
{
|
{
|
||||||
|
@ -3586,8 +3633,14 @@ static INT_PTR CALLBACK DebugMemLoad(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
|
|
||||||
_ASSERT(dwStartAddr <= 0xFFFFF);
|
_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
|
// load memory dump file
|
||||||
if (!LoadMemData(szFilename,dwStartAddr))
|
if (!LoadMemData(szFilename,dwStartAddr,uBitMode))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// update memory window
|
// update memory window
|
||||||
|
@ -3617,9 +3670,13 @@ static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
{
|
{
|
||||||
TCHAR szFilename[MAX_PATH];
|
TCHAR szFilename[MAX_PATH];
|
||||||
DWORD dwStartAddr,dwEndAddr;
|
DWORD dwStartAddr,dwEndAddr;
|
||||||
|
UINT uBitMode;
|
||||||
|
|
||||||
switch (message)
|
switch (message)
|
||||||
{
|
{
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
CheckDlgButton(hDlg,IDC_DEBUG_DATA_SAVE_8BIT,BST_CHECKED);
|
||||||
|
return TRUE;
|
||||||
case WM_COMMAND:
|
case WM_COMMAND:
|
||||||
switch(LOWORD(wParam))
|
switch(LOWORD(wParam))
|
||||||
{
|
{
|
||||||
|
@ -3643,8 +3700,9 @@ static INT_PTR CALLBACK DebugMemSave(HWND hDlg, UINT message, WPARAM wParam, LPA
|
||||||
_ASSERT(dwStartAddr <= 0xFFFFF);
|
_ASSERT(dwStartAddr <= 0xFFFFF);
|
||||||
_ASSERT(dwEndAddr <= 0xFFFFF);
|
_ASSERT(dwEndAddr <= 0xFFFFF);
|
||||||
|
|
||||||
|
uBitMode = IsDlgButtonChecked(hDlg,IDC_DEBUG_DATA_SAVE_4BIT);
|
||||||
// save memory dump file
|
// save memory dump file
|
||||||
if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr))
|
if (!SaveMemData(szFilename,dwStartAddr,dwEndAddr,uBitMode))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
// no break
|
// 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 unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
||||||
static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/
|
static const unsigned headsize = 1u << FIRSTBITS; /*size of the first table*/
|
||||||
static const unsigned mask = (1u << FIRSTBITS) /*headsize*/ - 1u;
|
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));
|
unsigned* maxlens = (unsigned*)lodepng_malloc(headsize * sizeof(unsigned));
|
||||||
if(!maxlens) return 83; /*alloc fail*/
|
if(!maxlens) return 83; /*alloc fail*/
|
||||||
|
|
||||||
|
@ -683,7 +683,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
||||||
size = headsize;
|
size = headsize;
|
||||||
for(i = 0; i < headsize; ++i) {
|
for(i = 0; i < headsize; ++i) {
|
||||||
unsigned l = maxlens[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_len = (unsigned char*)lodepng_malloc(size * sizeof(*tree->table_len));
|
||||||
tree->table_value = (unsigned short*)lodepng_malloc(size * sizeof(*tree->table_value));
|
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];
|
unsigned l = maxlens[i];
|
||||||
if(l <= FIRSTBITS) continue;
|
if(l <= FIRSTBITS) continue;
|
||||||
tree->table_len[i] = l;
|
tree->table_len[i] = l;
|
||||||
tree->table_value[i] = pointer;
|
tree->table_value[i] = (unsigned short)pointer;
|
||||||
pointer += (1u << (l - FIRSTBITS));
|
pointer += (((size_t)1) << (l - FIRSTBITS));
|
||||||
}
|
}
|
||||||
lodepng_free(maxlens);
|
lodepng_free(maxlens);
|
||||||
|
|
||||||
|
@ -726,7 +726,7 @@ static unsigned HuffmanTree_makeTable(HuffmanTree* tree) {
|
||||||
unsigned index = reverse | (j << l);
|
unsigned index = reverse | (j << l);
|
||||||
if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
|
if(tree->table_len[index] != 16) return 55; /*invalid tree: long symbol shares prefix with short symbol*/
|
||||||
tree->table_len[index] = l;
|
tree->table_len[index] = l;
|
||||||
tree->table_value[index] = i;
|
tree->table_value[index] = (unsigned short)i;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
/*long symbol, shares prefix with other long symbols in first lookup table, needs second lookup*/
|
/*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 reverse2 = reverse >> FIRSTBITS; /* l - FIRSTBITS bits */
|
||||||
unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS)));
|
unsigned index2 = start + (reverse2 | (j << (l - FIRSTBITS)));
|
||||||
tree->table_len[index2] = l;
|
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 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);
|
ucvector v = ucvector_init(*out, *outsize);
|
||||||
unsigned error = lodepng_chunk_createv(&v, length, type, data);
|
unsigned error = lodepng_chunk_createv(&v, length, type, data);
|
||||||
*out = v.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) {
|
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*/
|
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*/
|
/*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 &= (1u << bits) - 1u; /*filter out any other bits of the input value*/
|
||||||
in = in << (bits * (m - p));
|
in = in << (bits * (m - p));
|
||||||
if(p == 0) out[index * bits / 8u] = in;
|
if(p == 0) out[index * bits / 8u] = in;
|
||||||
|
@ -5889,7 +5889,7 @@ static size_t ilog2i(size_t i) {
|
||||||
l = ilog2(i);
|
l = ilog2(i);
|
||||||
/* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u)
|
/* approximate i*log2(i): l is integer logarithm, ((i - (1u << l)) << 1u)
|
||||||
linearly approximates the missing fractional part multiplied by i */
|
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,
|
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.
|
The out variable and outsize are updated to reflect the new reallocated buffer.
|
||||||
Returne error code (0 if it went ok)
|
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);
|
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
|
// maybe CPU speed measurement, slow down the next 10 CPU opcodes
|
||||||
if (dwCycDif < 150)
|
if (dwCycDif < 150)
|
||||||
{
|
{
|
||||||
InitAdjustSpeed(); // init variables if necessary
|
|
||||||
EnterCriticalSection(&csSlowLock);
|
EnterCriticalSection(&csSlowLock);
|
||||||
{
|
{
|
||||||
|
InitAdjustSpeed(); // init variables if necessary
|
||||||
nOpcSlow = 10; // slow down next 10 opcodes
|
nOpcSlow = 10; // slow down next 10 opcodes
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&csSlowLock);
|
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
|
// CPU running with max. speed we may get a timeout overflow
|
||||||
// -> to avoid this slow down CPU speed on transmit buffer full
|
// -> to avoid this slow down CPU speed on transmit buffer full
|
||||||
|
|
||||||
InitAdjustSpeed(); // init variables if necessary
|
|
||||||
EnterCriticalSection(&csSlowLock);
|
EnterCriticalSection(&csSlowLock);
|
||||||
{
|
{
|
||||||
|
InitAdjustSpeed(); // init variables if necessary
|
||||||
nOpcSlow = 10; // slow down next 10 opcodes
|
nOpcSlow = 10; // slow down next 10 opcodes
|
||||||
}
|
}
|
||||||
LeaveCriticalSection(&csSlowLock);
|
LeaveCriticalSection(&csSlowLock);
|
||||||
|
|
|
@ -121,62 +121,67 @@
|
||||||
#define IDC_DEBUG_DATA_BUT 1084
|
#define IDC_DEBUG_DATA_BUT 1084
|
||||||
#define IDC_DEBUG_DATA_STARTADDR 1085
|
#define IDC_DEBUG_DATA_STARTADDR 1085
|
||||||
#define IDC_DEBUG_DATA_ENDADDR 1086
|
#define IDC_DEBUG_DATA_ENDADDR 1086
|
||||||
#define IDC_DEBUG_SET_SYMB 1087
|
#define IDC_DEBUG_DATA_SAVE_8BIT 1087
|
||||||
#define IDC_DEBUG_SET_MODEL 1088
|
#define IDC_DEBUG_DATA_SAVE_4BIT 1088
|
||||||
#define IDC_DEBUG_SET_FILE 1089
|
#define IDC_DEBUG_DATA_LOAD_8BIT 1089
|
||||||
#define IDC_DEBUG_SET_BROWSE 1090
|
#define IDC_DEBUG_DATA_LOAD_4BIT 1090
|
||||||
#define IDC_DEBUG_STACK 1091
|
#define IDC_DEBUG_DATA_LOAD_ABIT 1091
|
||||||
#define IDC_STATIC_BREAKPOINT 1092
|
#define IDC_DEBUG_SET_SYMB 1092
|
||||||
#define IDC_BREAKEDIT_ADD 1093
|
#define IDC_DEBUG_SET_MODEL 1093
|
||||||
#define IDC_BREAKEDIT_DELETE 1094
|
#define IDC_DEBUG_SET_FILE 1094
|
||||||
#define IDC_BREAKEDIT_WND 1095
|
#define IDC_DEBUG_SET_BROWSE 1095
|
||||||
#define IDC_STATIC_MMU 1096
|
#define IDC_DEBUG_STACK 1096
|
||||||
#define IDC_MMU_IO_A 1097
|
#define IDC_STATIC_BREAKPOINT 1097
|
||||||
#define IDC_MMU_NCE2_A 1098
|
#define IDC_BREAKEDIT_ADD 1098
|
||||||
#define IDC_MMU_CE1_A 1099
|
#define IDC_BREAKEDIT_DELETE 1099
|
||||||
#define IDC_MMU_CE2_A 1100
|
#define IDC_BREAKEDIT_WND 1100
|
||||||
#define IDC_MMU_NCE3_A 1101
|
#define IDC_STATIC_MMU 1101
|
||||||
#define IDC_MMU_IO_S 1102
|
#define IDC_MMU_IO_A 1102
|
||||||
#define IDC_MMU_CE1_S 1103
|
#define IDC_MMU_NCE2_A 1103
|
||||||
#define IDC_MMU_CE2_S 1104
|
#define IDC_MMU_CE1_A 1104
|
||||||
#define IDC_MMU_NCE2_S 1105
|
#define IDC_MMU_CE2_A 1105
|
||||||
#define IDC_MMU_NCE3_S 1106
|
#define IDC_MMU_NCE3_A 1106
|
||||||
#define IDC_STATIC_MISC 1107
|
#define IDC_MMU_IO_S 1107
|
||||||
#define IDC_MISC_BS_TXT 1108
|
#define IDC_MMU_CE1_S 1108
|
||||||
#define IDC_INSTR_TEXT 1109
|
#define IDC_MMU_CE2_S 1109
|
||||||
#define IDC_INSTR_CODE 1110
|
#define IDC_MMU_NCE2_S 1110
|
||||||
#define IDC_INSTR_COPY 1111
|
#define IDC_MMU_NCE3_S 1111
|
||||||
#define IDC_INSTR_CLEAR 1112
|
#define IDC_STATIC_MISC 1112
|
||||||
#define IDC_PROFILE_LASTCYCLES 1113
|
#define IDC_MISC_BS_TXT 1113
|
||||||
#define IDC_PROFILE_LASTTIME 1114
|
#define IDC_INSTR_TEXT 1114
|
||||||
#define IDC_BPCODE 1115
|
#define IDC_INSTR_CODE 1115
|
||||||
#define IDC_BPRPL 1116
|
#define IDC_INSTR_COPY 1116
|
||||||
#define IDC_BPACCESS 1117
|
#define IDC_INSTR_CLEAR 1117
|
||||||
#define IDC_BPREAD 1118
|
#define IDC_PROFILE_LASTCYCLES 1118
|
||||||
#define IDC_BPWRITE 1119
|
#define IDC_PROFILE_LASTTIME 1119
|
||||||
#define IDC_FIND_DATA 1120
|
#define IDC_BPCODE 1120
|
||||||
#define IDC_FIND_PREV 1121
|
#define IDC_BPRPL 1121
|
||||||
#define IDC_FIND_NEXT 1122
|
#define IDC_BPACCESS 1122
|
||||||
#define IDC_FIND_ASCII 1123
|
#define IDC_BPREAD 1123
|
||||||
#define IDC_ADDR20_24 1124
|
#define IDC_BPWRITE 1124
|
||||||
#define IDC_ADDR25_27 1125
|
#define IDC_FIND_DATA 1125
|
||||||
#define IDC_ADDR28_29 1126
|
#define IDC_FIND_PREV 1126
|
||||||
#define IDC_ADDR30_34 1127
|
#define IDC_FIND_NEXT 1127
|
||||||
#define IDC_RPLVIEW_DATA 1128
|
#define IDC_FIND_ASCII 1128
|
||||||
#define IDC_MACRO_SLOW 1129
|
#define IDC_ADDR20_24 1129
|
||||||
#define IDC_MACRO_FAST 1130
|
#define IDC_ADDR25_27 1130
|
||||||
#define IDC_MACRO_SLIDER 1131
|
#define IDC_ADDR28_29 1131
|
||||||
#define IDC_MACRO_REAL 1132
|
#define IDC_ADDR30_34 1132
|
||||||
#define IDC_MACRO_MANUAL 1133
|
#define IDC_RPLVIEW_DATA 1133
|
||||||
#define IDC_SOUND_SLIDER 1134
|
#define IDC_MACRO_SLOW 1134
|
||||||
#define IDC_SOUND_DEVICE 1135
|
#define IDC_MACRO_FAST 1135
|
||||||
#define IDC_TRACE_FILE 1136
|
#define IDC_MACRO_SLIDER 1136
|
||||||
#define IDC_TRACE_BROWSE 1137
|
#define IDC_MACRO_REAL 1137
|
||||||
#define IDC_TRACE_NEW 1138
|
#define IDC_MACRO_MANUAL 1138
|
||||||
#define IDC_TRACE_APPEND 1139
|
#define IDC_SOUND_SLIDER 1139
|
||||||
#define IDC_TRACE_REGISTER 1140
|
#define IDC_SOUND_DEVICE 1140
|
||||||
#define IDC_TRACE_MMU 1141
|
#define IDC_TRACE_FILE 1141
|
||||||
#define IDC_TRACE_OPCODE 1142
|
#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_NEW 40001
|
||||||
#define ID_FILE_OPEN 40002
|
#define ID_FILE_OPEN 40002
|
||||||
#define ID_FILE_SAVE 40003
|
#define ID_FILE_SAVE 40003
|
||||||
|
@ -257,7 +262,7 @@
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 131
|
#define _APS_NEXT_RESOURCE_VALUE 131
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40074
|
#define _APS_NEXT_COMMAND_VALUE 40074
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1143
|
#define _APS_NEXT_CONTROL_VALUE 1148
|
||||||
#define _APS_NEXT_SYMED_VALUE 109
|
#define _APS_NEXT_SYMED_VALUE 109
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -241,8 +241,8 @@ VOID RebuildRomCrc(VOID)
|
||||||
{
|
{
|
||||||
// has no Crc
|
// has no Crc
|
||||||
}
|
}
|
||||||
// HP49G
|
// HP48GII/49G+/50G/49G
|
||||||
if (cCurrentRomType == 'X' && dwRomSize == _KB(2048))
|
if ((strchr("2QX",cCurrentRomType)) && dwRomSize == _KB(2048))
|
||||||
{
|
{
|
||||||
CorrectAllFlashPages(); // go through all pages
|
CorrectAllFlashPages(); // go through all pages
|
||||||
}
|
}
|
||||||
|
|
|
@ -104,7 +104,6 @@ BOOL CommOpen(LPTSTR strWirePort,LPTSTR strIrPort)
|
||||||
|
|
||||||
LPCTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort;
|
LPCTSTR strPort = (Chipset.IORam[IR_CTRL] & EIRU) ? strIrPort : strWirePort;
|
||||||
|
|
||||||
_ASSERT(Chipset.IORam[IOC] & SON); // UART on
|
|
||||||
CommClose(); // close port if already open
|
CommClose(); // close port if already open
|
||||||
|
|
||||||
dwBytesRead = 0L; // no bytes received
|
dwBytesRead = 0L; // no bytes received
|
||||||
|
|
|
@ -182,23 +182,24 @@ VOID ReadSettings(VOID)
|
||||||
disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
|
disassembler_mode = ReadInt(_T("Disassembler"),_T("Mnemonics"),disassembler_mode);
|
||||||
disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
|
disassembler_symb = ReadInt(_T("Disassembler"),_T("Symbolic"),disassembler_symb);
|
||||||
// Emulator
|
// Emulator
|
||||||
bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle);
|
bShowTitle = ReadInt(_T("Emulator"),_T("ShowTitle"),bShowTitle);
|
||||||
bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu);
|
bShowMenu = ReadInt(_T("Emulator"),_T("ShowMenu"),bShowMenu);
|
||||||
bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
|
bAlwaysOnTop = ReadInt(_T("Emulator"),_T("AlwaysOnTop"),bAlwaysOnTop);
|
||||||
bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
|
bActFollowsMouse = ReadInt(_T("Emulator"),_T("ActivationFollowsMouse"),bActFollowsMouse);
|
||||||
bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove);
|
bClientWinMove = ReadInt(_T("Emulator"),_T("ClientWinMove"),bClientWinMove);
|
||||||
bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance);
|
bSingleInstance = ReadInt(_T("Emulator"),_T("SingleInstance"),bSingleInstance);
|
||||||
bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed);
|
bRealSpeed = ReadInt(_T("Emulator"),_T("RealSpeed"),bRealSpeed);
|
||||||
dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles);
|
dwSXCycles = ReadInt(_T("Emulator"),_T("SXCycles"),dwSXCycles);
|
||||||
dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles);
|
dwGXCycles = ReadInt(_T("Emulator"),_T("GXCycles"),dwGXCycles);
|
||||||
dwGPCycles = ReadInt(_T("Emulator"),_T("GPCycles"),dwGPCycles); // CdB for HP: add apples
|
dwGPCycles = ReadInt(_T("Emulator"),_T("GPCycles"),dwGPCycles); // CdB for HP: add apples
|
||||||
dwG2Cycles = ReadInt(_T("Emulator"),_T("G2Cycles"),dwG2Cycles); // CdB for HP: add apples
|
dwG2Cycles = ReadInt(_T("Emulator"),_T("G2Cycles"),dwG2Cycles); // CdB for HP: add apples
|
||||||
dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay);
|
dwKeyMinDelay = ReadInt(_T("Emulator"),_T("KeyMinDelay"),dwKeyMinDelay);
|
||||||
dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay);
|
dwWakeupDelay = ReadInt(_T("Emulator"),_T("WakeupDelay"),dwWakeupDelay);
|
||||||
bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
|
bGrayscale = ReadInt(_T("Emulator"),_T("Grayscale"),bGrayscale);
|
||||||
uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
uWaveDevId = ReadInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
||||||
dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
dwWaveVol = ReadInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
||||||
dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
dwWaveTime = ReadInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
||||||
|
bLocaleDecimalPoint = ReadInt(_T("Emulator"),_T("LocaleDecimalPoint"),bLocaleDecimalPoint);
|
||||||
// LowBat
|
// LowBat
|
||||||
bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
|
bLowBatDisable = ReadInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
|
||||||
// Macro
|
// Macro
|
||||||
|
@ -254,6 +255,7 @@ VOID WriteSettings(VOID)
|
||||||
WriteInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
WriteInt(_T("Emulator"),_T("WaveDeviceId"),uWaveDevId);
|
||||||
WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
WriteInt(_T("Emulator"),_T("WaveVolume"),dwWaveVol);
|
||||||
WriteInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
WriteInt(_T("Emulator"),_T("WaveTime"),dwWaveTime);
|
||||||
|
WriteInt(_T("Emulator"),_T("LocaleDecimalPoint"),bLocaleDecimalPoint);
|
||||||
// LowBat
|
// LowBat
|
||||||
WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
|
WriteInt(_T("LowBat"),_T("Disable"),bLowBatDisable);
|
||||||
// Macro
|
// Macro
|
||||||
|
|
|
@ -19,6 +19,7 @@
|
||||||
#define DOCSTR 0x02A2C // String
|
#define DOCSTR 0x02A2C // String
|
||||||
|
|
||||||
BOOL bDetectClpObject = TRUE; // try to detect clipboard object
|
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)
|
static LPTSTR Trim(LPCTSTR cp)
|
||||||
{
|
{
|
||||||
LPCTSTR pcWs = _T(" \t\n\r"); // valid whitespace characters
|
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)
|
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];
|
BYTE byNum[80];
|
||||||
INT i,nIp,nDp,nMaxExp;
|
INT i,nIp,nDp,nMaxExp;
|
||||||
LONG lExp;
|
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
|
if ( nMantLen + nExpLen >= nSize // destination buffer too small
|
||||||
|| !*cp // empty string
|
|| !*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
|
|| (SIZE_T) lstrlen(cp) >= ARRAYSIZEOF(byNum)) // ignore too long reals
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
byNum[0] = (*cp != _T('-')) ? 0 : 9; // set sign nibble
|
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++;
|
cp++;
|
||||||
|
|
||||||
// only '.', '0' .. '9' are valid here
|
// 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
|
if (*cp != cDec) // no decimal point
|
||||||
{
|
{
|
||||||
// count integer part
|
// count integer part
|
||||||
while (*cp >= _T('0') && *cp <= _T('9'))
|
for (; (*cp >= _T('0') && *cp <= _T('9')) || *cp == cThousand; ++cp)
|
||||||
byNum[++nIp] = *cp++ - _T('0');
|
{
|
||||||
|
if (*cp != cThousand) // not thousand separator
|
||||||
|
{
|
||||||
|
byNum[++nIp] = *cp - _T('0');
|
||||||
|
}
|
||||||
|
}
|
||||||
if (!nIp) return 0;
|
if (!nIp) return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -376,8 +477,8 @@ static INT RPL_GetComplex(BYTE CONST *pbyNum,INT nMantLen,INT nExpLen,CONST TCHA
|
||||||
TCHAR cSep;
|
TCHAR cSep;
|
||||||
|
|
||||||
cSep = (cDec == _T('.')) // current separator
|
cSep = (cDec == _T('.')) // current separator
|
||||||
? _T(',') // radix mark '.' -> ',' separator
|
? _T(',') // decimal point '.' -> ',' separator
|
||||||
: _T(';'); // radix mark ',' -> ';' separator
|
: _T(';'); // decimal comma ',' -> ';' separator
|
||||||
|
|
||||||
nPos = 0; // write buffer position
|
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
|
nLen = 0; // read data length
|
||||||
|
|
||||||
cSep = (cDec == _T('.')) // current separator
|
cSep = (cDec == _T('.')) // current separator
|
||||||
? _T(',') // radix mark '.' -> ',' separator
|
? _T(',') // decimal point '.' -> ',' separator
|
||||||
: _T(';'); // radix mark ',' -> ';' separator
|
: _T(';'); // decimal comma ',' -> ';' separator
|
||||||
|
|
||||||
if ((pszData = Trim(cp)) != NULL) // create a trimmed working copy of the string
|
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)
|
static TCHAR GetRadix(VOID)
|
||||||
{
|
{
|
||||||
// get locale decimal point
|
if (bLocaleDecimalPoint) // use Windows Locale decimal point character
|
||||||
// GetLocaleInfo(LOCALE_USER_DEFAULT,LOCALE_SDECIMAL,&cDecimal,1);
|
{
|
||||||
|
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('.');
|
return RPL_GetSystemFlag(fnRadix) ? _T(',') : _T('.');
|
||||||
}
|
}
|
||||||
|
@ -683,9 +790,11 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
||||||
|
|
||||||
if ((lpstrClipdata = (LPCTSTR) GlobalLock(hClipObj)))
|
if ((lpstrClipdata = (LPCTSTR) GlobalLock(hClipObj)))
|
||||||
{
|
{
|
||||||
|
TCHAR cDec;
|
||||||
BYTE byNumber[128];
|
BYTE byNumber[128];
|
||||||
DWORD dwAddress;
|
DWORD dwAddress;
|
||||||
INT s;
|
|
||||||
|
INT s = 0; // no valid object
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
@ -715,9 +824,14 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// try to convert string to real format
|
cDec = GetClpbrdDecimalPoint(lpstrClipdata);
|
||||||
_ASSERT(16 <= ARRAYSIZEOF(byNumber));
|
|
||||||
s = RPL_SetBcd(lpstrClipdata,12,3,GetRadix(),byNumber,sizeof(byNumber));
|
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
|
if (s > 0) // is a real number
|
||||||
{
|
{
|
||||||
|
@ -736,9 +850,14 @@ LRESULT OnStackPaste(VOID) // paste data to stack
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// search for ';' as separator
|
||||||
|
cDec = (_tcschr(lpstrClipdata,_T(';')) != NULL)
|
||||||
|
? _T(',') // decimal comma
|
||||||
|
: _T('.'); // decimal point
|
||||||
|
|
||||||
// try to convert string to complex format
|
// try to convert string to complex format
|
||||||
_ASSERT(32 <= ARRAYSIZEOF(byNumber));
|
_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
|
if (s > 0) // is a real complex
|
||||||
{
|
{
|
||||||
|
|
|
@ -247,7 +247,7 @@ VOID SetHP48Time(VOID) // set date and time
|
||||||
ULONGLONG ticks, time;
|
ULONGLONG ticks, time;
|
||||||
DWORD dw;
|
DWORD dw;
|
||||||
WORD crc, i;
|
WORD crc, i;
|
||||||
BYTE p[4];
|
LPBYTE pbyTime;
|
||||||
|
|
||||||
_ASSERT(sizeof(ULONGLONG) == 8); // check size of datatype
|
_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 = ticks; // save for calc. timeout
|
||||||
time += OFF_TIME; // add 10 min for auto off
|
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
|
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;
|
*pbyTime = (BYTE) ticks & 0xf; // time
|
||||||
crc = (crc >> 4) ^ (((crc ^ ((WORD) *p)) & 0xf) * 0x1081);
|
crc = UpCRC(crc,*pbyTime);
|
||||||
Port0[dw] = *p; // always store in port0
|
|
||||||
ticks >>= 4;
|
ticks >>= 4;
|
||||||
}
|
|
||||||
|
|
||||||
Nunpack(p,crc,4); // write crc
|
pbyTime[13+4] = (BYTE) time & 0xf; // auto off
|
||||||
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
|
|
||||||
time >>= 4;
|
time >>= 4;
|
||||||
|
++pbyTime;
|
||||||
}
|
}
|
||||||
|
|
||||||
Port0[dw] = 0xf; // always store in port0
|
Nunpack(pbyTime,crc,4); // write crc
|
||||||
|
|
||||||
|
pbyTime[13+4] = 0xf;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -22,13 +22,10 @@ VOID ResetUdp(VOID)
|
||||||
|
|
||||||
BOOL SendByteUdp(BYTE byData)
|
BOOL SendByteUdp(BYTE byData)
|
||||||
{
|
{
|
||||||
WSADATA wsd;
|
|
||||||
SOCKET sClient;
|
SOCKET sClient;
|
||||||
|
|
||||||
BOOL bErr = TRUE;
|
BOOL bErr = TRUE;
|
||||||
|
|
||||||
VERIFY(WSAStartup(MAKEWORD(1,1),&wsd) == 0);
|
|
||||||
|
|
||||||
// IP address not specified
|
// IP address not specified
|
||||||
if (sServer.sin_addr.s_addr == INADDR_NONE)
|
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;
|
bErr = sendto(sClient, (LPCCH) &byData, sizeof(byData), 0, (LPSOCKADDR) &sServer, sizeof(sServer)) == SOCKET_ERROR;
|
||||||
closesocket(sClient);
|
closesocket(sClient);
|
||||||
}
|
}
|
||||||
|
|
||||||
WSACleanup(); // cleanup network stack
|
|
||||||
return bErr;
|
return bErr;
|
||||||
}
|
}
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1199,9 +1199,12 @@ typedef struct tagCOPYDATASTRUCT {
|
||||||
PVOID lpData;
|
PVOID lpData;
|
||||||
} COPYDATASTRUCT, *PCOPYDATASTRUCT;
|
} 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
|
#ifdef UNICODE
|
||||||
|
|
|
@ -158,7 +158,9 @@ public class Serial {
|
||||||
if(usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
|
if(usbConnection == null && usbPermission == UsbPermission.Unknown && !usbManager.hasPermission(driver.getDevice())) {
|
||||||
usbPermission = UsbPermission.Requested;
|
usbPermission = UsbPermission.Requested;
|
||||||
int flags = Build.VERSION.SDK_INT >= Build.VERSION_CODES.M ? PendingIntent.FLAG_MUTABLE : 0;
|
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);
|
usbManager.requestPermission(driver.getDevice(), usbPermissionIntent);
|
||||||
if(debug) Log.d(TAG, "Request permission");
|
if(debug) Log.d(TAG, "Request permission");
|
||||||
connectionStatus = "serial_connection_failed_user_has_not_given_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.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.emulator.calculator.usbserial.util.HexDump;
|
|
||||||
import org.emulator.calculator.usbserial.util.UsbUtils;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.EnumSet;
|
import java.util.EnumSet;
|
||||||
|
@ -32,8 +30,6 @@ import java.util.Map;
|
||||||
*/
|
*/
|
||||||
public class CdcAcmSerialDriver implements UsbSerialDriver {
|
public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
public static final int USB_SUBCLASS_ACM = 2;
|
|
||||||
|
|
||||||
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
|
private final String TAG = CdcAcmSerialDriver.class.getSimpleName();
|
||||||
|
|
||||||
private final UsbDevice mDevice;
|
private final UsbDevice mDevice;
|
||||||
|
@ -42,31 +38,21 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
public CdcAcmSerialDriver(UsbDevice device) {
|
public CdcAcmSerialDriver(UsbDevice device) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mPorts = new ArrayList<>();
|
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 controlInterfaceCount = 0;
|
||||||
int dataInterfaceCount = 0;
|
int dataInterfaceCount = 0;
|
||||||
for (int i = 0; i < device.getInterfaceCount(); i++) {
|
for( int i = 0; i < device.getInterfaceCount(); i++) {
|
||||||
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_COMM &&
|
if(device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_COMM)
|
||||||
device.getInterface(i).getInterfaceSubclass() == USB_SUBCLASS_ACM)
|
|
||||||
controlInterfaceCount++;
|
controlInterfaceCount++;
|
||||||
if (device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
|
if(device.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
|
||||||
dataInterfaceCount++;
|
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
|
@Override
|
||||||
|
@ -109,11 +95,7 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void openInt() throws IOException {
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
Log.d(TAG, "interfaces:");
|
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
|
||||||
Log.d(TAG, mDevice.getInterface(i).toString());
|
|
||||||
}
|
|
||||||
if (mPortNumber == -1) {
|
if (mPortNumber == -1) {
|
||||||
Log.d(TAG,"device might be castrated ACM device, trying single interface logic");
|
Log.d(TAG,"device might be castrated ACM device, trying single interface logic");
|
||||||
openSingleInterface();
|
openSingleInterface();
|
||||||
|
@ -149,57 +131,38 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void openInterface() throws IOException {
|
private void openInterface() throws IOException {
|
||||||
|
Log.d(TAG, "claiming interfaces, count=" + mDevice.getInterfaceCount());
|
||||||
|
|
||||||
|
int controlInterfaceCount = 0;
|
||||||
|
int dataInterfaceCount = 0;
|
||||||
mControlInterface = null;
|
mControlInterface = null;
|
||||||
mDataInterface = null;
|
mDataInterface = null;
|
||||||
int j = getInterfaceIdFromDescriptors();
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||||
Log.d(TAG, "interface count=" + mDevice.getInterfaceCount() + ", IAD=" + j);
|
UsbInterface usbInterface = mDevice.getInterface(i);
|
||||||
if (j >= 0) {
|
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_COMM) {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
if(controlInterfaceCount == mPortNumber) {
|
||||||
UsbInterface usbInterface = mDevice.getInterface(i);
|
mControlIndex = i;
|
||||||
if (usbInterface.getId() == j || usbInterface.getId() == j+1) {
|
mControlInterface = usbInterface;
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
controlInterfaceCount++;
|
||||||
}
|
}
|
||||||
}
|
if (usbInterface.getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA) {
|
||||||
if (mControlInterface == null || mDataInterface == null) {
|
if(dataInterfaceCount == mPortNumber) {
|
||||||
Log.d(TAG, "no IAD fallback");
|
mDataInterface = usbInterface;
|
||||||
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++;
|
|
||||||
}
|
}
|
||||||
|
dataInterfaceCount++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if(mControlInterface == null) {
|
if(mControlInterface == null) {
|
||||||
throw new IOException("No control interface");
|
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)) {
|
if (!mConnection.claimInterface(mControlInterface, true)) {
|
||||||
throw new IOException("Could not claim control interface");
|
throw new IOException("Could not claim control interface");
|
||||||
}
|
}
|
||||||
|
|
||||||
mControlEndpoint = mControlInterface.getEndpoint(0);
|
mControlEndpoint = mControlInterface.getEndpoint(0);
|
||||||
if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) {
|
if (mControlEndpoint.getDirection() != UsbConstants.USB_DIR_IN || mControlEndpoint.getType() != UsbConstants.USB_ENDPOINT_XFER_INT) {
|
||||||
throw new IOException("Invalid control endpoint");
|
throw new IOException("Invalid control endpoint");
|
||||||
|
@ -208,10 +171,12 @@ public class CdcAcmSerialDriver implements UsbSerialDriver {
|
||||||
if(mDataInterface == null) {
|
if(mDataInterface == null) {
|
||||||
throw new IOException("No data interface");
|
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)) {
|
if (!mConnection.claimInterface(mDataInterface, true)) {
|
||||||
throw new IOException("Could not claim data interface");
|
throw new IOException("Could not claim data interface");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < mDataInterface.getEndpointCount(); i++) {
|
for (int i = 0; i < mDataInterface.getEndpointCount(); i++) {
|
||||||
UsbEndpoint ep = mDataInterface.getEndpoint(i);
|
UsbEndpoint ep = mDataInterface.getEndpoint(i);
|
||||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN && ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
|
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 {
|
private int sendAcmControlMessage(int request, int value, byte[] buf) throws IOException {
|
||||||
int len = mConnection.controlTransfer(
|
int len = mConnection.controlTransfer(
|
||||||
USB_RT_ACM, request, value, mControlIndex, buf, buf != null ? buf.length : 0, 5000);
|
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() {
|
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.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
//import org.emulator.calculator.usbserial.BuildConfig;
|
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
@ -22,366 +20,355 @@ import java.util.Map;
|
||||||
|
|
||||||
public class Ch34xSerialDriver implements UsbSerialDriver {
|
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 UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
private final UsbSerialPort mPort;
|
||||||
|
|
||||||
private static final int LCR_ENABLE_RX = 0x80;
|
private static final int LCR_ENABLE_RX = 0x80;
|
||||||
private static final int LCR_ENABLE_TX = 0x40;
|
private static final int LCR_ENABLE_TX = 0x40;
|
||||||
private static final int LCR_MARK_SPACE = 0x20;
|
private static final int LCR_MARK_SPACE = 0x20;
|
||||||
private static final int LCR_PAR_EVEN = 0x10;
|
private static final int LCR_PAR_EVEN = 0x10;
|
||||||
private static final int LCR_ENABLE_PAR = 0x08;
|
private static final int LCR_ENABLE_PAR = 0x08;
|
||||||
private static final int LCR_STOP_BITS_2 = 0x04;
|
private static final int LCR_STOP_BITS_2 = 0x04;
|
||||||
private static final int LCR_CS8 = 0x03;
|
private static final int LCR_CS8 = 0x03;
|
||||||
private static final int LCR_CS7 = 0x02;
|
private static final int LCR_CS7 = 0x02;
|
||||||
private static final int LCR_CS6 = 0x01;
|
private static final int LCR_CS6 = 0x01;
|
||||||
private static final int LCR_CS5 = 0x00;
|
private static final int LCR_CS5 = 0x00;
|
||||||
|
|
||||||
private static final int GCL_CTS = 0x01;
|
private static final int GCL_CTS = 0x01;
|
||||||
private static final int GCL_DSR = 0x02;
|
private static final int GCL_DSR = 0x02;
|
||||||
private static final int GCL_RI = 0x04;
|
private static final int GCL_RI = 0x04;
|
||||||
private static final int GCL_CD = 0x08;
|
private static final int GCL_CD = 0x08;
|
||||||
private static final int SCL_DTR = 0x20;
|
private static final int SCL_DTR = 0x20;
|
||||||
private static final int SCL_RTS = 0x40;
|
private static final int SCL_RTS = 0x40;
|
||||||
|
|
||||||
public Ch34xSerialDriver(UsbDevice device) {
|
public Ch34xSerialDriver(UsbDevice device) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mPort = new Ch340SerialPort(mDevice, 0);
|
mPort = new Ch340SerialPort(mDevice, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsbDevice getDevice() {
|
public UsbDevice getDevice() {
|
||||||
return mDevice;
|
return mDevice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<UsbSerialPort> getPorts() {
|
public List<UsbSerialPort> getPorts() {
|
||||||
return Collections.singletonList(mPort);
|
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 dtr = false;
|
||||||
private boolean rts = false;
|
private boolean rts = false;
|
||||||
|
|
||||||
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
public Ch340SerialPort(UsbDevice device, int portNumber) {
|
||||||
super(device, portNumber);
|
super(device, portNumber);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public UsbSerialDriver getDriver() {
|
public UsbSerialDriver getDriver() {
|
||||||
return Ch34xSerialDriver.this;
|
return Ch34xSerialDriver.this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void openInt() throws IOException {
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++) {
|
||||||
UsbInterface usbIface = mDevice.getInterface(i);
|
UsbInterface usbIface = mDevice.getInterface(i);
|
||||||
if (!mConnection.claimInterface(usbIface, true)) {
|
if (!mConnection.claimInterface(usbIface, true)) {
|
||||||
throw new IOException("Could not claim data interface");
|
throw new IOException("Could not claim data interface");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
UsbInterface dataIface = mDevice.getInterface(mDevice.getInterfaceCount() - 1);
|
||||||
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
for (int i = 0; i < dataIface.getEndpointCount(); i++) {
|
||||||
UsbEndpoint ep = dataIface.getEndpoint(i);
|
UsbEndpoint ep = dataIface.getEndpoint(i);
|
||||||
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
if (ep.getType() == UsbConstants.USB_ENDPOINT_XFER_BULK) {
|
||||||
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
if (ep.getDirection() == UsbConstants.USB_DIR_IN) {
|
||||||
mReadEndpoint = ep;
|
mReadEndpoint = ep;
|
||||||
} else {
|
} else {
|
||||||
mWriteEndpoint = ep;
|
mWriteEndpoint = ep;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
initialize();
|
initialize();
|
||||||
setBaudRate(DEFAULT_BAUD_RATE);
|
setBaudRate(DEFAULT_BAUD_RATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void closeInt() {
|
protected void closeInt() {
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
|
for (int i = 0; i < mDevice.getInterfaceCount(); i++)
|
||||||
mConnection.releaseInterface(mDevice.getInterface(i));
|
mConnection.releaseInterface(mDevice.getInterface(i));
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
}
|
}
|
||||||
|
|
||||||
private int controlOut(int request, int value, int index) {
|
private int controlOut(int request, int value, int index) {
|
||||||
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
final int REQTYPE_HOST_TO_DEVICE = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_OUT;
|
||||||
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
|
return mConnection.controlTransfer(REQTYPE_HOST_TO_DEVICE, request,
|
||||||
value, index, null, 0, USB_TIMEOUT_MILLIS);
|
value, index, null, 0, USB_TIMEOUT_MILLIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private int controlIn(int request, int value, int index, byte[] buffer) {
|
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;
|
final int REQTYPE_DEVICE_TO_HOST = UsbConstants.USB_TYPE_VENDOR | UsbConstants.USB_DIR_IN;
|
||||||
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
|
return mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, request,
|
||||||
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
|
value, index, buffer, buffer.length, USB_TIMEOUT_MILLIS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
|
private void checkState(String msg, int request, int value, int[] expected) throws IOException {
|
||||||
byte[] buffer = new byte[expected.length];
|
byte[] buffer = new byte[expected.length];
|
||||||
int ret = controlIn(request, value, 0, buffer);
|
int ret = controlIn(request, value, 0, buffer);
|
||||||
|
|
||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
throw new IOException("Failed send cmd [" + msg + "]");
|
throw new IOException("Failed send cmd [" + msg + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ret != expected.length) {
|
if (ret != expected.length) {
|
||||||
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
|
throw new IOException("Expected " + expected.length + " bytes, but get " + ret + " [" + msg + "]");
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < expected.length; i++) {
|
for (int i = 0; i < expected.length; i++) {
|
||||||
if (expected[i] == -1) {
|
if (expected[i] == -1) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
int current = buffer[i] & 0xff;
|
int current = buffer[i] & 0xff;
|
||||||
if (expected[i] != current) {
|
if (expected[i] != current) {
|
||||||
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
throw new IOException("Expected 0x" + Integer.toHexString(expected[i]) + " byte, but get 0x" + Integer.toHexString(current) + " [" + msg + "]");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setControlLines() throws IOException {
|
private void setControlLines() throws IOException {
|
||||||
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
|
if (controlOut(0xa4, ~((dtr ? SCL_DTR : 0) | (rts ? SCL_RTS : 0)), 0) < 0) {
|
||||||
throw new IOException("Failed to set control lines");
|
throw new IOException("Failed to set control lines");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private byte getStatus() throws IOException {
|
private byte getStatus() throws IOException {
|
||||||
byte[] buffer = new byte[2];
|
byte[] buffer = new byte[2];
|
||||||
int ret = controlIn(0x95, 0x0706, 0, buffer);
|
int ret = controlIn(0x95, 0x0706, 0, buffer);
|
||||||
if (ret < 0)
|
if (ret < 0)
|
||||||
throw new IOException("Error getting control lines");
|
throw new IOException("Error getting control lines");
|
||||||
return buffer[0];
|
return buffer[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
private void initialize() throws IOException {
|
private void initialize() throws IOException {
|
||||||
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
|
checkState("init #1", 0x5f, 0, new int[]{-1 /* 0x27, 0x30 */, 0x00});
|
||||||
|
|
||||||
if (controlOut(0xa1, 0, 0) < 0) {
|
if (controlOut(0xa1, 0, 0) < 0) {
|
||||||
throw new IOException("Init failed: #2");
|
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) {
|
if (controlOut(0x9a, 0x2518, LCR_ENABLE_RX | LCR_ENABLE_TX | LCR_CS8) < 0) {
|
||||||
throw new IOException("Init failed: #5");
|
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) {
|
if (controlOut(0xa1, 0x501f, 0xd90a) < 0) {
|
||||||
throw new IOException("Init failed: #7");
|
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 {
|
private void setBaudRate(int baudRate) throws IOException {
|
||||||
long factor;
|
final long CH341_BAUDBASE_FACTOR = 1532620800;
|
||||||
long divisor;
|
final int CH341_BAUDBASE_DIVMAX = 3;
|
||||||
|
|
||||||
if (baudRate == 921600) {
|
long factor = CH341_BAUDBASE_FACTOR / baudRate;
|
||||||
divisor = 7;
|
int divisor = CH341_BAUDBASE_DIVMAX;
|
||||||
factor = 0xf300;
|
|
||||||
} else {
|
|
||||||
final long BAUDBASE_FACTOR = 1532620800;
|
|
||||||
final int BAUDBASE_DIVMAX = 3;
|
|
||||||
|
|
||||||
// if(BuildConfig.DEBUG && (baudRate & (3<<29)) == (1<<29))
|
while ((factor > 0xfff0) && divisor > 0) {
|
||||||
// baudRate &= ~(1<<29); // for testing purpose bypass dedicated baud rate handling
|
factor >>= 3;
|
||||||
factor = BAUDBASE_FACTOR / baudRate;
|
divisor--;
|
||||||
divisor = BAUDBASE_DIVMAX;
|
}
|
||||||
while ((factor > 0xfff0) && divisor > 0) {
|
|
||||||
factor >>= 3;
|
|
||||||
divisor--;
|
|
||||||
}
|
|
||||||
if (factor > 0xfff0) {
|
|
||||||
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
|
|
||||||
}
|
|
||||||
factor = 0x10000 - factor;
|
|
||||||
}
|
|
||||||
|
|
||||||
divisor |= 0x0080; // else ch341a waits until buffer full
|
if (factor > 0xfff0) {
|
||||||
int val1 = (int) ((factor & 0xff00) | divisor);
|
throw new UnsupportedOperationException("Unsupported baud rate: " + baudRate);
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
factor = 0x10000 - factor;
|
||||||
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
divisor |= 0x0080; // else ch341a waits until buffer full
|
||||||
if(baudRate <= 0) {
|
int ret = controlOut(0x9a, 0x1312, (int) ((factor & 0xff00) | divisor));
|
||||||
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
if (ret < 0) {
|
||||||
}
|
throw new IOException("Error setting baud rate: #1)");
|
||||||
setBaudRate(baudRate);
|
}
|
||||||
|
|
||||||
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) {
|
@Override
|
||||||
case DATABITS_5:
|
public void setParameters(int baudRate, int dataBits, int stopBits, @Parity int parity) throws IOException {
|
||||||
lcr |= LCR_CS5;
|
if(baudRate <= 0) {
|
||||||
break;
|
throw new IllegalArgumentException("Invalid baud rate: " + baudRate);
|
||||||
case DATABITS_6:
|
}
|
||||||
lcr |= LCR_CS6;
|
setBaudRate(baudRate);
|
||||||
break;
|
|
||||||
case DATABITS_7:
|
|
||||||
lcr |= LCR_CS7;
|
|
||||||
break;
|
|
||||||
case DATABITS_8:
|
|
||||||
lcr |= LCR_CS8;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (parity) {
|
int lcr = LCR_ENABLE_RX | LCR_ENABLE_TX;
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (stopBits) {
|
switch (dataBits) {
|
||||||
case STOPBITS_1:
|
case DATABITS_5:
|
||||||
break;
|
lcr |= LCR_CS5;
|
||||||
case STOPBITS_1_5:
|
break;
|
||||||
throw new UnsupportedOperationException("Unsupported stop bits: 1.5");
|
case DATABITS_6:
|
||||||
case STOPBITS_2:
|
lcr |= LCR_CS6;
|
||||||
lcr |= LCR_STOP_BITS_2;
|
break;
|
||||||
break;
|
case DATABITS_7:
|
||||||
default:
|
lcr |= LCR_CS7;
|
||||||
throw new IllegalArgumentException("Invalid stop bits: " + stopBits);
|
break;
|
||||||
}
|
case DATABITS_8:
|
||||||
|
lcr |= LCR_CS8;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw new IllegalArgumentException("Invalid data bits: " + dataBits);
|
||||||
|
}
|
||||||
|
|
||||||
int ret = controlOut(0x9a, 0x2518, lcr);
|
switch (parity) {
|
||||||
if (ret < 0) {
|
case PARITY_NONE:
|
||||||
throw new IOException("Error setting control byte");
|
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
|
switch (stopBits) {
|
||||||
public boolean getCD() throws IOException {
|
case STOPBITS_1:
|
||||||
return (getStatus() & GCL_CD) == 0;
|
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
|
int ret = controlOut(0x9a, 0x2518, lcr);
|
||||||
public boolean getCTS() throws IOException {
|
if (ret < 0) {
|
||||||
return (getStatus() & GCL_CTS) == 0;
|
throw new IOException("Error setting control byte");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDSR() throws IOException {
|
public boolean getCD() throws IOException {
|
||||||
return (getStatus() & GCL_DSR) == 0;
|
return (getStatus() & GCL_CD) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getDTR() throws IOException {
|
public boolean getCTS() throws IOException {
|
||||||
return dtr;
|
return (getStatus() & GCL_CTS) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setDTR(boolean value) throws IOException {
|
public boolean getDSR() throws IOException {
|
||||||
dtr = value;
|
return (getStatus() & GCL_DSR) == 0;
|
||||||
setControlLines();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRI() throws IOException {
|
public boolean getDTR() throws IOException {
|
||||||
return (getStatus() & GCL_RI) == 0;
|
return dtr;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean getRTS() throws IOException {
|
public void setDTR(boolean value) throws IOException {
|
||||||
return rts;
|
dtr = value;
|
||||||
}
|
setControlLines();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setRTS(boolean value) throws IOException {
|
public boolean getRI() throws IOException {
|
||||||
rts = value;
|
return (getStatus() & GCL_RI) == 0;
|
||||||
setControlLines();
|
}
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ControlLine> getControlLines() throws IOException {
|
public boolean getRTS() throws IOException {
|
||||||
int status = getStatus();
|
return rts;
|
||||||
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
|
@Override
|
||||||
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
public void setRTS(boolean value) throws IOException {
|
||||||
return EnumSet.allOf(ControlLine.class);
|
rts = value;
|
||||||
}
|
setControlLines();
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setBreak(boolean value) throws IOException {
|
public EnumSet<ControlLine> getControlLines() throws IOException {
|
||||||
byte[] req = new byte[2];
|
int status = getStatus();
|
||||||
if(controlIn(0x95, 0x1805, 0, req) < 0) {
|
EnumSet<ControlLine> set = EnumSet.noneOf(ControlLine.class);
|
||||||
throw new IOException("Error getting BREAK condition");
|
if(rts) set.add(ControlLine.RTS);
|
||||||
}
|
if((status & GCL_CTS) == 0) set.add(ControlLine.CTS);
|
||||||
if(value) {
|
if(dtr) set.add(ControlLine.DTR);
|
||||||
req[0] &= ~1;
|
if((status & GCL_DSR) == 0) set.add(ControlLine.DSR);
|
||||||
req[1] &= ~0x40;
|
if((status & GCL_CD) == 0) set.add(ControlLine.CD);
|
||||||
} else {
|
if((status & GCL_RI) == 0) set.add(ControlLine.RI);
|
||||||
req[0] |= 1;
|
return set;
|
||||||
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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
@Override
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public EnumSet<ControlLine> getSupportedControlLines() throws IOException {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
return EnumSet.allOf(ControlLine.class);
|
||||||
supportedDevices.put(UsbId.VENDOR_QINHENG, new int[]{
|
}
|
||||||
UsbId.QINHENG_CH340,
|
|
||||||
UsbId.QINHENG_CH341A,
|
@Override
|
||||||
});
|
public void setBreak(boolean value) throws IOException {
|
||||||
return supportedDevices;
|
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 abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
|
|
||||||
public static boolean DEBUG = false;
|
|
||||||
|
|
||||||
private static final String TAG = CommonUsbSerialPort.class.getSimpleName();
|
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
|
private static final int MAX_READ_SIZE = 16 * 1024; // = old bulkTransfer limit
|
||||||
|
|
||||||
protected final UsbDevice mDevice;
|
protected final UsbDevice mDevice;
|
||||||
protected final int mPortNumber;
|
protected final int mPortNumber;
|
||||||
|
|
||||||
// non-null when open()
|
// non-null when open()
|
||||||
protected UsbDeviceConnection mConnection;
|
protected UsbDeviceConnection mConnection = null;
|
||||||
protected UsbEndpoint mReadEndpoint;
|
protected UsbEndpoint mReadEndpoint;
|
||||||
protected UsbEndpoint mWriteEndpoint;
|
protected UsbEndpoint mWriteEndpoint;
|
||||||
protected UsbRequest mUsbRequest;
|
protected UsbRequest mUsbRequest;
|
||||||
|
|
||||||
/**
|
|
||||||
* Internal write buffer.
|
|
||||||
* Guarded by {@link #mWriteBufferLock}.
|
|
||||||
* Default length = mReadEndpoint.getMaxPacketSize()
|
|
||||||
**/
|
|
||||||
protected byte[] mWriteBuffer;
|
|
||||||
protected final Object mWriteBufferLock = new Object();
|
protected final Object mWriteBufferLock = new Object();
|
||||||
|
/** Internal write buffer. Guarded by {@link #mWriteBufferLock}. */
|
||||||
|
protected byte[] mWriteBuffer;
|
||||||
|
|
||||||
public CommonUsbSerialPort(UsbDevice device, int portNumber) {
|
public CommonUsbSerialPort(UsbDevice device, int portNumber) {
|
||||||
mDevice = device;
|
mDevice = device;
|
||||||
mPortNumber = portNumber;
|
mPortNumber = portNumber;
|
||||||
|
|
||||||
|
mWriteBuffer = new byte[DEFAULT_WRITE_BUFFER_SIZE];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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
|
* 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.
|
* 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) {
|
public final void setWriteBufferSize(int bufferSize) {
|
||||||
synchronized (mWriteBufferLock) {
|
synchronized (mWriteBufferLock) {
|
||||||
if (bufferSize <= 0) {
|
if (bufferSize == mWriteBuffer.length) {
|
||||||
if (mWriteEndpoint != null) {
|
|
||||||
bufferSize = mWriteEndpoint.getMaxPacketSize();
|
|
||||||
} else {
|
|
||||||
mWriteBuffer = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (mWriteBuffer != null && bufferSize == mWriteBuffer.length) {
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
mWriteBuffer = new byte[bufferSize];
|
mWriteBuffer = new byte[bufferSize];
|
||||||
|
@ -118,7 +106,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
}
|
}
|
||||||
mConnection = connection;
|
mConnection = connection;
|
||||||
try {
|
try {
|
||||||
openInt();
|
openInt(connection);
|
||||||
if (mReadEndpoint == null || mWriteEndpoint == null) {
|
if (mReadEndpoint == null || mWriteEndpoint == null) {
|
||||||
throw new IOException("Could not get read & write endpoints");
|
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
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
if (mConnection == null) {
|
if (mConnection == null) {
|
||||||
throw new IOException("Already closed");
|
throw new IOException("Already closed");
|
||||||
}
|
}
|
||||||
UsbRequest usbRequest = mUsbRequest;
|
|
||||||
mUsbRequest = null;
|
|
||||||
try {
|
try {
|
||||||
usbRequest.cancel();
|
mUsbRequest.cancel();
|
||||||
} catch(Exception ignored) {}
|
} catch(Exception ignored) {}
|
||||||
|
mUsbRequest = null;
|
||||||
try {
|
try {
|
||||||
closeInt();
|
closeInt();
|
||||||
} catch(Exception ignored) {}
|
} 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
|
* use simple USB request supported by all devices to test if connection is still valid
|
||||||
*/
|
*/
|
||||||
protected void testConnection(boolean full) throws IOException {
|
protected void testConnection() 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;
|
|
||||||
}
|
|
||||||
byte[] buf = new byte[2];
|
byte[] buf = new byte[2];
|
||||||
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
int len = mConnection.controlTransfer(0x80 /*DEVICE*/, 0 /*GET_STATUS*/, 0, 0, buf, buf.length, 200);
|
||||||
if(len < 0)
|
if(len < 0)
|
||||||
throw new IOException(msg);
|
throw new IOException("USB get_status request failed");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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 == 0) {
|
return read(dest, timeout, true);
|
||||||
throw new IllegalArgumentException("Read buffer too small");
|
|
||||||
}
|
|
||||||
return read(dest, dest.length, timeout);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
protected int read(final byte[] dest, final int timeout, boolean testConnection) throws IOException {
|
||||||
public int read(final byte[] dest, final int length, final int timeout) throws IOException {return read(dest, length, timeout, true);}
|
if(mConnection == null) {
|
||||||
|
throw new IOException("Connection closed");
|
||||||
protected int read(final byte[] dest, int length, final int timeout, boolean testConnection) throws IOException {
|
}
|
||||||
testConnection(false);
|
if(dest.length <= 0) {
|
||||||
if(length <= 0) {
|
throw new IllegalArgumentException("Read buffer to small");
|
||||||
throw new IllegalArgumentException("Read length too small");
|
|
||||||
}
|
}
|
||||||
length = Math.min(length, dest.length);
|
|
||||||
final int nread;
|
final int nread;
|
||||||
if (timeout != 0) {
|
if (timeout != 0) {
|
||||||
// bulkTransfer will cause data loss with short timeout + high baud rates + continuous transfer
|
// 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)
|
// /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
|
// data loss / crashes were observed with timeout up to 200 msec
|
||||||
long endTime = testConnection ? MonotonicClock.millis() + timeout : 0;
|
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);
|
nread = mConnection.bulkTransfer(mReadEndpoint, dest, readMax, timeout);
|
||||||
// Android error propagation is improvable:
|
// Android error propagation is improvable:
|
||||||
// nread == -1 can be: timeout, connection lost, buffer to small, ???
|
// nread == -1 can be: timeout, connection lost, buffer to small, ???
|
||||||
if(nread == -1 && testConnection)
|
if(nread == -1 && testConnection && MonotonicClock.millis() < endTime)
|
||||||
testConnection(MonotonicClock.millis() < endTime);
|
testConnection();
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
final ByteBuffer buf = ByteBuffer.wrap(dest, 0, length);
|
final ByteBuffer buf = ByteBuffer.wrap(dest);
|
||||||
if (!mUsbRequest.queue(buf, length)) {
|
if (!mUsbRequest.queue(buf, dest.length)) {
|
||||||
throw new IOException("Queueing USB request failed");
|
throw new IOException("Queueing USB request failed");
|
||||||
}
|
}
|
||||||
final UsbRequest response = mConnection.requestWait();
|
final UsbRequest response = mConnection.requestWait();
|
||||||
|
@ -223,23 +195,21 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
// Android error propagation is improvable:
|
// Android error propagation is improvable:
|
||||||
// response != null & nread == 0 can be: connection lost, buffer to small, ???
|
// response != null & nread == 0 can be: connection lost, buffer to small, ???
|
||||||
if(nread == 0) {
|
if(nread == 0) {
|
||||||
testConnection(true);
|
testConnection();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return Math.max(nread, 0);
|
return Math.max(nread, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void write(byte[] src, int timeout) throws IOException {write(src, src.length, timeout);}
|
public void write(final byte[] src, final int timeout) throws IOException {
|
||||||
|
|
||||||
@Override
|
|
||||||
public void write(final byte[] src, int length, final int timeout) throws IOException {
|
|
||||||
int offset = 0;
|
int offset = 0;
|
||||||
long startTime = MonotonicClock.millis();
|
final long endTime = (timeout == 0) ? 0 : (MonotonicClock.millis() + timeout);
|
||||||
length = Math.min(length, src.length);
|
|
||||||
|
|
||||||
testConnection(false);
|
if(mConnection == null) {
|
||||||
while (offset < length) {
|
throw new IOException("Connection closed");
|
||||||
|
}
|
||||||
|
while (offset < src.length) {
|
||||||
int requestTimeout;
|
int requestTimeout;
|
||||||
final int requestLength;
|
final int requestLength;
|
||||||
final int actualLength;
|
final int actualLength;
|
||||||
|
@ -247,10 +217,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
synchronized (mWriteBufferLock) {
|
synchronized (mWriteBufferLock) {
|
||||||
final byte[] writeBuffer;
|
final byte[] writeBuffer;
|
||||||
|
|
||||||
if (mWriteBuffer == null) {
|
requestLength = Math.min(src.length - offset, mWriteBuffer.length);
|
||||||
mWriteBuffer = new byte[mWriteEndpoint.getMaxPacketSize()];
|
|
||||||
}
|
|
||||||
requestLength = Math.min(length - offset, mWriteBuffer.length);
|
|
||||||
if (offset == 0) {
|
if (offset == 0) {
|
||||||
writeBuffer = src;
|
writeBuffer = src;
|
||||||
} else {
|
} else {
|
||||||
|
@ -261,7 +228,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
if (timeout == 0 || offset == 0) {
|
if (timeout == 0 || offset == 0) {
|
||||||
requestTimeout = timeout;
|
requestTimeout = timeout;
|
||||||
} else {
|
} else {
|
||||||
requestTimeout = (int)(startTime + timeout - MonotonicClock.millis());
|
requestTimeout = (int)(endTime - MonotonicClock.millis());
|
||||||
if(requestTimeout == 0)
|
if(requestTimeout == 0)
|
||||||
requestTimeout = -1;
|
requestTimeout = -1;
|
||||||
}
|
}
|
||||||
|
@ -271,18 +238,14 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
actualLength = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, requestLength, requestTimeout);
|
actualLength = mConnection.bulkTransfer(mWriteEndpoint, writeBuffer, requestLength, requestTimeout);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
long elapsed = MonotonicClock.millis() - startTime;
|
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + src.length + " timeout " + requestTimeout);
|
||||||
if (DEBUG) {
|
|
||||||
Log.d(TAG, "Wrote " + actualLength + "/" + requestLength + " offset " + offset + "/" + length + " time " + elapsed + "/" + requestTimeout);
|
|
||||||
}
|
|
||||||
if (actualLength <= 0) {
|
if (actualLength <= 0) {
|
||||||
String msg = "Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length + " after " + elapsed + "msec, rc=" + actualLength;
|
if (timeout != 0 && MonotonicClock.millis() >= endTime) {
|
||||||
if (timeout != 0) {
|
SerialTimeoutException ex = new SerialTimeoutException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length + ", rc=" + actualLength);
|
||||||
testConnection(elapsed < timeout, msg);
|
ex.bytesTransferred = offset;
|
||||||
throw new SerialTimeoutException(msg, offset);
|
throw ex;
|
||||||
} else {
|
} else {
|
||||||
throw new IOException(msg);
|
throw new IOException("Error writing " + requestLength + " bytes at offset " + offset + " of total " + src.length);
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
offset += actualLength;
|
offset += actualLength;
|
||||||
|
@ -291,7 +254,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isOpen() {
|
public boolean isOpen() {
|
||||||
return mUsbRequest != null;
|
return mConnection != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -322,7 +285,7 @@ public abstract class CommonUsbSerialPort implements UsbSerialPort {
|
||||||
public void setRTS(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
public void setRTS(boolean value) throws IOException { throw new UnsupportedOperationException(); }
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public EnumSet<ControlLine> getControlLines() throws IOException { throw new UnsupportedOperationException(); }
|
public abstract EnumSet<ControlLine> getControlLines() throws IOException;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public abstract EnumSet<ControlLine> getSupportedControlLines() throws IOException;
|
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.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
|
|
||||||
|
@ -118,14 +119,14 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
||||||
byte[] buffer = new byte[1];
|
byte[] buffer = new byte[1];
|
||||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, SILABSER_GET_MDMSTS_REQUEST_CODE, 0,
|
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, SILABSER_GET_MDMSTS_REQUEST_CODE, 0,
|
||||||
mPortNumber, buffer, buffer.length, USB_WRITE_TIMEOUT_MILLIS);
|
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);
|
throw new IOException("Control transfer failed: " + SILABSER_GET_MDMSTS_REQUEST_CODE + " / " + 0 + " -> " + result);
|
||||||
}
|
}
|
||||||
return buffer[0];
|
return buffer[0];
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void openInt() throws IOException {
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
|
mIsRestrictedPort = mDevice.getInterfaceCount() == 2 && mPortNumber == 1;
|
||||||
if(mPortNumber >= mDevice.getInterfaceCount()) {
|
if(mPortNumber >= mDevice.getInterfaceCount()) {
|
||||||
throw new IOException("Unknown port number");
|
throw new IOException("Unknown port number");
|
||||||
|
@ -320,7 +321,6 @@ public class Cp21xxSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
supportedDevices.put(UsbId.VENDOR_SILABS,
|
supportedDevices.put(UsbId.VENDOR_SILABS,
|
||||||
|
|
|
@ -9,6 +9,7 @@ package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbConstants;
|
import android.hardware.usb.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.emulator.calculator.usbserial.util.MonotonicClock;
|
import org.emulator.calculator.usbserial.util.MonotonicClock;
|
||||||
|
@ -98,8 +99,8 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void openInt() throws IOException {
|
protected void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
if (!mConnection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
if (!connection.claimInterface(mDevice.getInterface(mPortNumber), true)) {
|
||||||
throw new IOException("Could not claim interface " + mPortNumber);
|
throw new IOException("Could not claim interface " + mPortNumber);
|
||||||
}
|
}
|
||||||
if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) {
|
if (mDevice.getInterface(mPortNumber).getEndpointCount() < 2) {
|
||||||
|
@ -122,13 +123,12 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
// mDevice.getVersion() would require API 23
|
// mDevice.getVersion() would require API 23
|
||||||
byte[] rawDescriptors = mConnection.getRawDescriptors();
|
byte[] rawDescriptors = connection.getRawDescriptors();
|
||||||
if(rawDescriptors == null || rawDescriptors.length < 14) {
|
if(rawDescriptors == null || rawDescriptors.length < 14) {
|
||||||
throw new IOException("Could not get device descriptors");
|
throw new IOException("Could not get device descriptors");
|
||||||
}
|
}
|
||||||
int deviceType = rawDescriptors[13];
|
int deviceType = rawDescriptors[13];
|
||||||
baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9 // ...H devices
|
baudRateWithPort = deviceType == 7 || deviceType == 8 || deviceType == 9; // ...H devices
|
||||||
|| mDevice.getInterfaceCount() > 1; // FT2232C
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -139,37 +139,24 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@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) {
|
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
|
// 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
|
// 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.
|
// 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;
|
int nread;
|
||||||
if (timeout != 0) {
|
if (timeout != 0) {
|
||||||
long endTime = MonotonicClock.millis() + timeout;
|
long endTime = MonotonicClock.millis() + timeout;
|
||||||
do {
|
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);
|
} while (nread == READ_HEADER_LENGTH && MonotonicClock.millis() < endTime);
|
||||||
if(nread <= 0)
|
if(nread <= 0 && MonotonicClock.millis() < endTime)
|
||||||
testConnection(MonotonicClock.millis() < endTime);
|
testConnection();
|
||||||
} else {
|
} else {
|
||||||
do {
|
do {
|
||||||
nread = super.read(dest, length, timeout);
|
nread = super.read(dest, timeout, false);
|
||||||
} while (nread == READ_HEADER_LENGTH);
|
} while (nread == READ_HEADER_LENGTH);
|
||||||
}
|
}
|
||||||
return readFilter(dest, nread);
|
return readFilter(dest, nread);
|
||||||
|
@ -303,7 +290,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
byte[] data = new byte[2];
|
byte[] data = new byte[2];
|
||||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_MODEM_STATUS_REQUEST,
|
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_MODEM_STATUS_REQUEST,
|
||||||
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
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);
|
throw new IOException("Get modem status failed: result=" + result);
|
||||||
}
|
}
|
||||||
return data[0];
|
return data[0];
|
||||||
|
@ -419,7 +406,7 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
byte[] data = new byte[1];
|
byte[] data = new byte[1];
|
||||||
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_LATENCY_TIMER_REQUEST,
|
int result = mConnection.controlTransfer(REQTYPE_DEVICE_TO_HOST, GET_LATENCY_TIMER_REQUEST,
|
||||||
0, mPortNumber+1, data, data.length, USB_WRITE_TIMEOUT_MILLIS);
|
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);
|
throw new IOException("Get latency timer failed: result=" + result);
|
||||||
}
|
}
|
||||||
return data[0];
|
return data[0];
|
||||||
|
@ -427,7 +414,6 @@ public class FtdiSerialDriver implements UsbSerialDriver {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
supportedDevices.put(UsbId.VENDOR_FTDI,
|
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;
|
package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbDevice;
|
|
||||||
import android.util.Pair;
|
import android.util.Pair;
|
||||||
|
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
|
@ -15,14 +14,14 @@ import java.util.LinkedHashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps (vendor id, product id) pairs to the corresponding serial driver,
|
* Maps (vendor id, product id) pairs to the corresponding serial driver.
|
||||||
* or invoke 'probe' method to check actual USB devices for matching interfaces.
|
*
|
||||||
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
*/
|
*/
|
||||||
public class ProbeTable {
|
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<>();
|
new LinkedHashMap<>();
|
||||||
private final Map<Method, Class<? extends UsbSerialDriver>> mMethodProbeTable = new LinkedHashMap<>();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adds or updates a (vendor, product) pair in the table.
|
* Adds or updates a (vendor, product) pair in the table.
|
||||||
|
@ -34,7 +33,7 @@ public class ProbeTable {
|
||||||
*/
|
*/
|
||||||
public ProbeTable addProduct(int vendorId, int productId,
|
public ProbeTable addProduct(int vendorId, int productId,
|
||||||
Class<? extends UsbSerialDriver> driverClass) {
|
Class<? extends UsbSerialDriver> driverClass) {
|
||||||
mVidPidProbeTable.put(Pair.create(vendorId, productId), driverClass);
|
mProbeTable.put(Pair.create(vendorId, productId), driverClass);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,11 +41,12 @@ public class ProbeTable {
|
||||||
* Internal method to add all supported products from
|
* Internal method to add all supported products from
|
||||||
* {@code getSupportedProducts} static method.
|
* {@code getSupportedProducts} static method.
|
||||||
*
|
*
|
||||||
* @param driverClass to be added
|
* @param driverClass
|
||||||
|
* @return
|
||||||
*/
|
*/
|
||||||
@SuppressWarnings("unchecked")
|
@SuppressWarnings("unchecked")
|
||||||
void addDriver(Class<? extends UsbSerialDriver> driverClass) {
|
ProbeTable addDriver(Class<? extends UsbSerialDriver> driverClass) {
|
||||||
Method method;
|
final Method method;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
method = driverClass.getMethod("getSupportedDevices");
|
method = driverClass.getMethod("getSupportedDevices");
|
||||||
|
@ -68,35 +68,20 @@ public class ProbeTable {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
return this;
|
||||||
method = driverClass.getMethod("probe", UsbDevice.class);
|
|
||||||
mMethodProbeTable.put(method, driverClass);
|
|
||||||
} catch (SecurityException | NoSuchMethodException ignored) {
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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}
|
* @return the driver class matching this pair, or {@code null}
|
||||||
*/
|
*/
|
||||||
public Class<? extends UsbSerialDriver> findDriver(final UsbDevice usbDevice) {
|
public Class<? extends UsbSerialDriver> findDriver(int vendorId, int productId) {
|
||||||
final Pair<Integer, Integer> pair = Pair.create(usbDevice.getVendorId(), usbDevice.getProductId());
|
final Pair<Integer, Integer> pair = Pair.create(vendorId, productId);
|
||||||
Class<? extends UsbSerialDriver> driverClass = mVidPidProbeTable.get(pair);
|
return mProbeTable.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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,6 +11,7 @@ package org.emulator.calculator.usbserial.driver;
|
||||||
|
|
||||||
import android.hardware.usb.UsbConstants;
|
import android.hardware.usb.UsbConstants;
|
||||||
import android.hardware.usb.UsbDevice;
|
import android.hardware.usb.UsbDevice;
|
||||||
|
import android.hardware.usb.UsbDeviceConnection;
|
||||||
import android.hardware.usb.UsbEndpoint;
|
import android.hardware.usb.UsbEndpoint;
|
||||||
import android.hardware.usb.UsbInterface;
|
import android.hardware.usb.UsbInterface;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
@ -34,7 +35,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
|
28800, 38400, 57600, 115200, 128000, 134400, 161280, 201600, 230400, 268800,
|
||||||
403200, 460800, 614400, 806400, 921600, 1228800, 2457600, 3000000, 6000000
|
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 UsbDevice mDevice;
|
||||||
private final UsbSerialPort mPort;
|
private final UsbSerialPort mPort;
|
||||||
|
@ -122,7 +123,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
private volatile Thread mReadStatusThread = null;
|
private volatile Thread mReadStatusThread = null;
|
||||||
private final Object mReadStatusThreadLock = new Object();
|
private final Object mReadStatusThreadLock = new Object();
|
||||||
private boolean mStopReadStatusThread = false;
|
private boolean mStopReadStatusThread = false;
|
||||||
private Exception mReadStatusException = null;
|
private IOException mReadStatusException = null;
|
||||||
|
|
||||||
|
|
||||||
public ProlificSerialPort(UsbDevice device, int portNumber) {
|
public ProlificSerialPort(UsbDevice device, int portNumber) {
|
||||||
|
@ -138,7 +139,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
byte[] buffer = new byte[length];
|
byte[] buffer = new byte[length];
|
||||||
int result = mConnection.controlTransfer(requestType, request, value, index, buffer, length, USB_READ_TIMEOUT_MILLIS);
|
int result = mConnection.controlTransfer(requestType, request, value, index, buffer, length, USB_READ_TIMEOUT_MILLIS);
|
||||||
if (result != length) {
|
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;
|
return buffer;
|
||||||
}
|
}
|
||||||
|
@ -147,7 +148,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
int length = (data == null) ? 0 : data.length;
|
int length = (data == null) ? 0 : data.length;
|
||||||
int result = mConnection.controlTransfer(requestType, request, value, index, data, length, USB_WRITE_TIMEOUT_MILLIS);
|
int result = mConnection.controlTransfer(requestType, request, value, index, data, length, USB_WRITE_TIMEOUT_MILLIS);
|
||||||
if (result != length) {
|
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() {
|
private void readStatusThreadFunction() {
|
||||||
try {
|
try {
|
||||||
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
|
|
||||||
while (!mStopReadStatusThread) {
|
while (!mStopReadStatusThread) {
|
||||||
|
byte[] buffer = new byte[STATUS_BUFFER_SIZE];
|
||||||
long endTime = MonotonicClock.millis() + 500;
|
long endTime = MonotonicClock.millis() + 500;
|
||||||
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
|
int readBytesCount = mConnection.bulkTransfer(mInterruptEndpoint, buffer, STATUS_BUFFER_SIZE, 500);
|
||||||
if(readBytesCount == -1)
|
if(readBytesCount == -1 && MonotonicClock.millis() < endTime)
|
||||||
testConnection(MonotonicClock.millis() < endTime);
|
testConnection();
|
||||||
if (readBytesCount > 0) {
|
if (readBytesCount > 0) {
|
||||||
if (readBytesCount != STATUS_BUFFER_SIZE) {
|
if (readBytesCount != STATUS_BUFFER_SIZE) {
|
||||||
throw new IOException("Invalid status notification, expected " + STATUS_BUFFER_SIZE + " bytes, got " + readBytesCount);
|
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) {
|
} catch (IOException e) {
|
||||||
if (isOpen())
|
mReadStatusException = e;
|
||||||
mReadStatusException = e;
|
|
||||||
}
|
}
|
||||||
//Log.d(TAG, "end control line status thread " + mStopReadStatusThread + " " + (mReadStatusException == null ? "-" : mReadStatusException.getMessage()));
|
//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 */
|
/* throw and clear an exception which occured in the status read thread */
|
||||||
Exception readStatusException = mReadStatusException;
|
IOException readStatusException = mReadStatusException;
|
||||||
if (mReadStatusException != null) {
|
if (mReadStatusException != null) {
|
||||||
mReadStatusException = null;
|
mReadStatusException = null;
|
||||||
throw new IOException(readStatusException);
|
throw new IOException(readStatusException);
|
||||||
|
@ -265,10 +265,10 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void openInt() throws IOException {
|
public void openInt(UsbDeviceConnection connection) throws IOException {
|
||||||
UsbInterface usbInterface = mDevice.getInterface(0);
|
UsbInterface usbInterface = mDevice.getInterface(0);
|
||||||
|
|
||||||
if (!mConnection.claimInterface(usbInterface, true)) {
|
if (!connection.claimInterface(usbInterface, true)) {
|
||||||
throw new IOException("Error claiming Prolific interface 0");
|
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) {
|
if(rawDescriptors == null || rawDescriptors.length < 14) {
|
||||||
throw new IOException("Could not get device descriptors");
|
throw new IOException("Could not get device descriptors");
|
||||||
}
|
}
|
||||||
|
@ -299,19 +299,15 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
byte maxPacketSize0 = rawDescriptors[7];
|
byte maxPacketSize0 = rawDescriptors[7];
|
||||||
if (mDevice.getDeviceClass() == 0x02 || maxPacketSize0 != 64) {
|
if (mDevice.getDeviceClass() == 0x02 || maxPacketSize0 != 64) {
|
||||||
mDeviceType = DeviceType.DEVICE_TYPE_01;
|
mDeviceType = DeviceType.DEVICE_TYPE_01;
|
||||||
} else if(usbVersion == 0x200) {
|
} else if(deviceVersion == 0x300 && usbVersion == 0x200) {
|
||||||
if(deviceVersion == 0x300 && testHxStatus()) {
|
mDeviceType = DeviceType.DEVICE_TYPE_T; // TA
|
||||||
mDeviceType = DeviceType.DEVICE_TYPE_T; // TA
|
} else if(deviceVersion == 0x500) {
|
||||||
} else if(deviceVersion == 0x500 && testHxStatus()) {
|
mDeviceType = DeviceType.DEVICE_TYPE_T; // TB
|
||||||
mDeviceType = DeviceType.DEVICE_TYPE_T; // TB
|
} else if(usbVersion == 0x200 && !testHxStatus()) {
|
||||||
} else {
|
mDeviceType = DeviceType.DEVICE_TYPE_HXN;
|
||||||
mDeviceType = DeviceType.DEVICE_TYPE_HXN;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
mDeviceType = DeviceType.DEVICE_TYPE_HX;
|
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();
|
resetDevice();
|
||||||
doBlackMagic();
|
doBlackMagic();
|
||||||
setControlLines(mControlLinesValue);
|
setControlLines(mControlLinesValue);
|
||||||
|
@ -567,7 +563,6 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings({"unused"})
|
|
||||||
public static Map<Integer, int[]> getSupportedDevices() {
|
public static Map<Integer, int[]> getSupportedDevices() {
|
||||||
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
final Map<Integer, int[]> supportedDevices = new LinkedHashMap<>();
|
||||||
supportedDevices.put(UsbId.VENDOR_PROLIFIC,
|
supportedDevices.put(UsbId.VENDOR_PROLIFIC,
|
||||||
|
@ -576,6 +571,7 @@ public class ProlificSerialDriver implements UsbSerialDriver {
|
||||||
UsbId.PROLIFIC_PL2303GC,
|
UsbId.PROLIFIC_PL2303GC,
|
||||||
UsbId.PROLIFIC_PL2303GB,
|
UsbId.PROLIFIC_PL2303GB,
|
||||||
UsbId.PROLIFIC_PL2303GT,
|
UsbId.PROLIFIC_PL2303GT,
|
||||||
|
UsbId.PROLIFIC_PL2303GT3,
|
||||||
UsbId.PROLIFIC_PL2303GL,
|
UsbId.PROLIFIC_PL2303GL,
|
||||||
UsbId.PROLIFIC_PL2303GE,
|
UsbId.PROLIFIC_PL2303GE,
|
||||||
UsbId.PROLIFIC_PL2303GS,
|
UsbId.PROLIFIC_PL2303GS,
|
||||||
|
|
|
@ -9,8 +9,7 @@ import java.io.InterruptedIOException;
|
||||||
* {@see InterruptedIOException#bytesTransferred} may contain bytes transferred
|
* {@see InterruptedIOException#bytesTransferred} may contain bytes transferred
|
||||||
*/
|
*/
|
||||||
public class SerialTimeoutException extends InterruptedIOException {
|
public class SerialTimeoutException extends InterruptedIOException {
|
||||||
public SerialTimeoutException(String s, int bytesTransferred) {
|
public SerialTimeoutException(String s) {
|
||||||
super(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_FT232H = 0x6014;
|
||||||
public static final int FTDI_FT231X = 0x6015; // same ID for FT230X, FT231X, FT234XD
|
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 VENDOR_SILABS = 0x10c4;
|
||||||
public static final int SILABS_CP2102 = 0xea60; // same ID for CP2101, CP2103, CP2104, CP2109
|
public static final int SILABS_CP2102 = 0xea60; // same ID for CP2101, CP2103, CP2104, CP2109
|
||||||
public static final int SILABS_CP2105 = 0xea70;
|
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_PL2303 = 0x2303; // device type 01, T, HX
|
||||||
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
|
public static final int PROLIFIC_PL2303GC = 0x23a3; // device type HXN
|
||||||
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
|
public static final int PROLIFIC_PL2303GB = 0x23b3; // "
|
||||||
public static final int PROLIFIC_PL2303GT = 0x23c3; // "
|
public static final int PROLIFIC_PL2303GT = 0x23cd; // "
|
||||||
public static final int PROLIFIC_PL2303GL = 0x23d3; // "
|
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_PL2303GE = 0x23e3; // "
|
||||||
public static final int PROLIFIC_PL2303GS = 0x23f3; // "
|
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 VENDOR_QINHENG = 0x1a86;
|
||||||
public static final int QINHENG_CH340 = 0x7523;
|
public static final int QINHENG_CH340 = 0x7523;
|
||||||
public static final int QINHENG_CH341A = 0x5523;
|
public static final int QINHENG_CH341A = 0x5523;
|
||||||
|
|
||||||
public static final int VENDOR_UNISOC = 0x1782;
|
// 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 FIBOCOM_L610 = 0x4D10;
|
public static final int VENDOR_ARM = 0x0d28;
|
||||||
public static final int FIBOCOM_L612 = 0x4D12;
|
public static final int ARM_MBED = 0x0204;
|
||||||
|
|
||||||
|
public static final int VENDOR_ST = 0x0483;
|
||||||
|
public static final int ST_CDC = 0x5740;
|
||||||
|
|
||||||
private UsbId() {
|
private UsbId() {
|
||||||
throw new IllegalAccessError("Non-instantiable class");
|
throw new IllegalAccessError("Non-instantiable class");
|
||||||
|
|
|
@ -10,17 +10,12 @@ import android.hardware.usb.UsbDevice;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author mike wakerly (opensource@hoho.com)
|
||||||
|
*/
|
||||||
public interface UsbSerialDriver {
|
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.
|
* Returns the raw {@link UsbDevice} backing this port.
|
||||||
*
|
*
|
||||||
|
|
|
@ -58,7 +58,7 @@ public interface UsbSerialPort extends Closeable {
|
||||||
int STOPBITS_2 = 2;
|
int STOPBITS_2 = 2;
|
||||||
|
|
||||||
/** Values for get[Supported]ControlLines() */
|
/** 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.
|
* 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;
|
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.
|
* 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;
|
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.
|
* Sets various serial port parameters.
|
||||||
*
|
*
|
||||||
|
|
|
@ -37,8 +37,6 @@ public class UsbSerialProber {
|
||||||
probeTable.addDriver(FtdiSerialDriver.class);
|
probeTable.addDriver(FtdiSerialDriver.class);
|
||||||
probeTable.addDriver(ProlificSerialDriver.class);
|
probeTable.addDriver(ProlificSerialDriver.class);
|
||||||
probeTable.addDriver(Ch34xSerialDriver.class);
|
probeTable.addDriver(Ch34xSerialDriver.class);
|
||||||
probeTable.addDriver(GsmModemSerialDriver.class);
|
|
||||||
probeTable.addDriver(ChromeCcdSerialDriver.class);
|
|
||||||
return probeTable;
|
return probeTable;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,7 +69,11 @@ public class UsbSerialProber {
|
||||||
* {@code null} if none available.
|
* {@code null} if none available.
|
||||||
*/
|
*/
|
||||||
public UsbSerialDriver probeDevice(final UsbDevice usbDevice) {
|
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) {
|
if (driverClass != null) {
|
||||||
final UsbSerialDriver driver;
|
final UsbSerialDriver driver;
|
||||||
try {
|
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.os.Process;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
import org.emulator.calculator.usbserial.driver.SerialTimeoutException;
|
|
||||||
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
import org.emulator.calculator.usbserial.driver.UsbSerialPort;
|
||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
@ -22,15 +21,8 @@ import java.nio.ByteBuffer;
|
||||||
*/
|
*/
|
||||||
public class SerialInputOutputManager implements Runnable {
|
public class SerialInputOutputManager implements Runnable {
|
||||||
|
|
||||||
public enum State {
|
|
||||||
STOPPED,
|
|
||||||
RUNNING,
|
|
||||||
STOPPING
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean DEBUG = false;
|
|
||||||
|
|
||||||
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
|
private static final String TAG = SerialInputOutputManager.class.getSimpleName();
|
||||||
|
public static boolean DEBUG = false;
|
||||||
private static final int BUFSIZ = 4096;
|
private static final int BUFSIZ = 4096;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -45,6 +37,12 @@ public class SerialInputOutputManager implements Runnable {
|
||||||
private ByteBuffer mReadBuffer; // default size = getReadEndpoint().getMaxPacketSize()
|
private ByteBuffer mReadBuffer; // default size = getReadEndpoint().getMaxPacketSize()
|
||||||
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
private ByteBuffer mWriteBuffer = ByteBuffer.allocate(BUFSIZ);
|
||||||
|
|
||||||
|
public enum State {
|
||||||
|
STOPPED,
|
||||||
|
RUNNING,
|
||||||
|
STOPPING
|
||||||
|
}
|
||||||
|
|
||||||
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
|
private int mThreadPriority = Process.THREAD_PRIORITY_URGENT_AUDIO;
|
||||||
private State mState = State.STOPPED; // Synchronized by 'this'
|
private State mState = State.STOPPED; // Synchronized by 'this'
|
||||||
private Listener mListener; // Synchronized by 'this'
|
private Listener mListener; // Synchronized by 'this'
|
||||||
|
@ -204,11 +202,7 @@ public class SerialInputOutputManager implements Runnable {
|
||||||
step();
|
step();
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
if(mSerialPort.isOpen()) {
|
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
||||||
Log.w(TAG, "Run ending due to exception: " + e.getMessage(), e);
|
|
||||||
} else {
|
|
||||||
Log.i(TAG, "Socket closed");
|
|
||||||
}
|
|
||||||
final Listener listener = getListener();
|
final Listener listener = getListener();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
listener.onRunError(e);
|
listener.onRunError(e);
|
||||||
|
@ -229,9 +223,7 @@ public class SerialInputOutputManager implements Runnable {
|
||||||
}
|
}
|
||||||
int len = mSerialPort.read(buffer, mReadTimeout);
|
int len = mSerialPort.read(buffer, mReadTimeout);
|
||||||
if (len > 0) {
|
if (len > 0) {
|
||||||
if (DEBUG) {
|
if (DEBUG) Log.d(TAG, "Read data len=" + len);
|
||||||
Log.d(TAG, "Read data len=" + len);
|
|
||||||
}
|
|
||||||
final Listener listener = getListener();
|
final Listener listener = getListener();
|
||||||
if (listener != null) {
|
if (listener != null) {
|
||||||
final byte[] data = new byte[len];
|
final byte[] data = new byte[len];
|
||||||
|
@ -255,23 +247,7 @@ public class SerialInputOutputManager implements Runnable {
|
||||||
if (DEBUG) {
|
if (DEBUG) {
|
||||||
Log.d(TAG, "Writing data len=" + len);
|
Log.d(TAG, "Writing data len=" + len);
|
||||||
}
|
}
|
||||||
try {
|
mSerialPort.write(buffer, mWriteTimeout);
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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
|
// Most Recently Used state files
|
||||||
private final int MRU_ID_START = 10000;
|
private final int MRU_ID_START = 10000;
|
||||||
private final int MAX_MRU = 5;
|
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
|
@Override
|
||||||
protected boolean removeEldestEntry(Map.Entry eldest) {
|
protected boolean removeEldestEntry(Map.Entry eldest) {
|
||||||
return size() > MAX_MRU;
|
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 PrinterSimulator printerSimulator = new PrinterSimulator();
|
||||||
private final PrinterSimulatorFragment fragmentPrinterSimulator = new PrinterSimulatorFragment();
|
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 {
|
try {
|
||||||
// FileOpen auto-open.
|
// FileOpen auto-open.
|
||||||
onFileOpen(documentToOpenUrl, intent, null);
|
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--) {
|
for (int i = mrus.length - 1; i >= 0; i--) {
|
||||||
String mostRecentlyUsedFile = mrus[i];
|
String mostRecentlyUsedFile = mrus[i];
|
||||||
String displayName = getFilenameFromURL(mostRecentlyUsedFile);
|
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.
|
// 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.
|
// It might be deleted or the permissions does not allow to reach it anymore.
|
||||||
mruLinkedHashMap.remove(mostRecentlyUsedFile);
|
mruLinkedHashMap.remove(mostRecentlyUsedFile);
|
||||||
|
@ -301,7 +301,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
|
|
||||||
if (NativeLib.isDocumentAvailable() && settings.getBoolean("settings_autosave", true)) {
|
if (NativeLib.isDocumentAvailable() && settings.getBoolean("settings_autosave", true)) {
|
||||||
String currentFilename = NativeLib.getCurrentFilename();
|
String currentFilename = NativeLib.getCurrentFilename();
|
||||||
if (currentFilename != null && currentFilename.length() > 0)
|
if (currentFilename != null && !currentFilename.isEmpty())
|
||||||
onFileSave();
|
onFileSave();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1140,7 +1140,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
saveWhenLaunchingActivity = false;
|
saveWhenLaunchingActivity = false;
|
||||||
startActivityForResult(intent, INTENT_LOAD_FLASH_ROM);
|
startActivityForResult(intent, INTENT_LOAD_FLASH_ROM);
|
||||||
};
|
};
|
||||||
if(currentFlashPort2Url != null && currentFlashPort2Url.length() > 0)
|
if(currentFlashPort2Url != null && !currentFlashPort2Url.isEmpty())
|
||||||
new AlertDialog.Builder(this)
|
new AlertDialog.Builder(this)
|
||||||
.setTitle(getString(R.string.alert_losing_flash_rom_title))
|
.setTitle(getString(R.string.alert_losing_flash_rom_title))
|
||||||
.setMessage(getString(R.string.alert_losing_flash_rom_message))
|
.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
|
// Reset to default Flash ROM from the KML file
|
||||||
settings.putString("settings_flash_port2", null);
|
settings.putString("settings_flash_port2", null);
|
||||||
String kmlFilename = NativeLib.getCurrentKml();
|
String kmlFilename = NativeLib.getCurrentKml();
|
||||||
if(kmlFilename.length() > 0) {
|
if(!kmlFilename.isEmpty()) {
|
||||||
String kmlFolder = kmlFolderURL == null || kmlFolderURL.length() == 0 ? null : kmlFolderURL;
|
String kmlFolder = kmlFolderURL == null || kmlFolderURL.isEmpty() ? null : kmlFolderURL;
|
||||||
// Reset the flashROM
|
// Reset the flashROM
|
||||||
NativeLib.onLoadFlashROM("");
|
NativeLib.onLoadFlashROM("");
|
||||||
// Load the KML file again. TODO If it goes wrong, we are lost.
|
// 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);
|
updateFromPreferences("settings_flash_port2", true);
|
||||||
displayFilename(url);
|
displayFilename(url);
|
||||||
String settingsFlashPort2Url = settings.getString("settings_flash_port2", null);
|
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)));
|
showAlert(String.format(Locale.US, getString(R.string.message_state_and_flash_saved), getFilenameFromURL(url), getFilenameFromURL(settingsFlashPort2Url)));
|
||||||
else
|
else
|
||||||
showAlert(String.format(Locale.US, getString(R.string.message_state_saved), getFilenameFromURL(url)));
|
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);]
|
// 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!
|
// So, we are going to create a new one from the ROM loaded by the current KML script!
|
||||||
String kmlFilename = NativeLib.getCurrentKml();
|
String kmlFilename = NativeLib.getCurrentKml();
|
||||||
if(kmlFilename != null && kmlFilename.length() > 0) {
|
if(kmlFilename != null && !kmlFilename.isEmpty()) {
|
||||||
if(kmlFolderURL != null && kmlFolderURL.length() > 0)
|
if(kmlFolderURL != null && !kmlFolderURL.isEmpty())
|
||||||
copyROMFromFolder(kmlFilename, uri);
|
copyROMFromFolder(kmlFilename, uri);
|
||||||
else
|
else
|
||||||
copyROMFromAsset(kmlFilename, uri);
|
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);
|
ParcelFileDescriptor pfdROM = openFileInFolderFromContentResolverPFD(romFilename, kmlFolderURL, GENERIC_READ);
|
||||||
if(pfdROM != null) {
|
if(pfdROM != null) {
|
||||||
try {
|
try {
|
||||||
|
@ -1479,7 +1479,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
try {
|
try {
|
||||||
kmlInputStream = assetManager.open("calculators/" + kmlFilename);
|
kmlInputStream = assetManager.open("calculators/" + kmlFilename);
|
||||||
String romFilename = extractROMFilename(kmlInputStream);
|
String romFilename = extractROMFilename(kmlInputStream);
|
||||||
if(romFilename != null && romFilename.length() > 0) {
|
if(romFilename != null && !romFilename.isEmpty()) {
|
||||||
InputStream romInputStream = assetManager.open("calculators/" + romFilename);
|
InputStream romInputStream = assetManager.open("calculators/" + romFilename);
|
||||||
copyROMtoFlashROM(romInputStream, uri);
|
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)) {
|
if(getPackageName().contains("org.emulator.forty.eight") && settings.getBoolean("settings_port2en", false)) {
|
||||||
// Check if the access to the port2 shared file is still possible.
|
// Check if the access to the port2 shared file is still possible.
|
||||||
String port2Url = settings.getString("settings_port2load", "");
|
String port2Url = settings.getString("settings_port2load", "");
|
||||||
if(port2Url != null && port2Url.length() > 0) {
|
if(port2Url != null && !port2Url.isEmpty()) {
|
||||||
Uri port2Uri = Uri.parse(port2Url);
|
Uri port2Uri = Uri.parse(port2Url);
|
||||||
DocumentFile port2DocumentFile = DocumentFile.fromSingleUri(this, port2Uri);
|
DocumentFile port2DocumentFile = DocumentFile.fromSingleUri(this, port2Uri);
|
||||||
if (port2DocumentFile == null || !port2DocumentFile.exists()) {
|
if (port2DocumentFile == null || !port2DocumentFile.exists()) {
|
||||||
|
@ -1706,7 +1706,7 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
updateFromPreferences("settings_flash_port2", true);
|
updateFromPreferences("settings_flash_port2", true);
|
||||||
|
|
||||||
String settingsFlashPort2Url = settings.getString("settings_flash_port2", null);
|
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)));
|
showAlert(String.format(Locale.US, getString(R.string.message_state_and_flash_saved), getFilenameFromURL(currentFilenameUrl), getFilenameFromURL(settingsFlashPort2Url)));
|
||||||
else
|
else
|
||||||
showAlert(String.format(Locale.US, getString(R.string.message_state_saved), getFilenameFromURL(currentFilenameUrl)));
|
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) {
|
private void displayFilename(String stateFileURL) {
|
||||||
String displayName = getFilenameFromURL(stateFileURL == null ? "" : stateFileURL);
|
String displayName = getFilenameFromURL(stateFileURL == null ? "" : stateFileURL);
|
||||||
String port2FileURL = settings.getString("settings_flash_port2", null);
|
String port2FileURL = settings.getString("settings_flash_port2", null);
|
||||||
if(port2FileURL != null && port2FileURL.length() > 0)
|
if(port2FileURL != null && !port2FileURL.isEmpty())
|
||||||
displayName += " " + getFilenameFromURL(port2FileURL);
|
displayName += " " + getFilenameFromURL(port2FileURL);
|
||||||
View headerView = displayKMLTitle();
|
View headerView = displayKMLTitle();
|
||||||
if(headerView != null) {
|
if(headerView != null) {
|
||||||
|
@ -2082,14 +2082,14 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
}
|
}
|
||||||
|
|
||||||
private int serialIndex = 1;
|
private int serialIndex = 1;
|
||||||
private HashMap<Integer, Serial> serialsById = new HashMap<>();
|
private final HashMap<Integer, Serial> serialsById = new HashMap<>();
|
||||||
|
|
||||||
@SuppressWarnings("UnusedDeclaration")
|
@SuppressWarnings("UnusedDeclaration")
|
||||||
int openSerialPort(String serialPort) {
|
int openSerialPort(String serialPort) {
|
||||||
// Search if this same serial port is not already opened
|
// Search if this same serial port is not already opened
|
||||||
|
|
||||||
|
|
||||||
Integer serialPortId = serialIndex;
|
int serialPortId = serialIndex;
|
||||||
Serial serial = new Serial(this, serialPortId);
|
Serial serial = new Serial(this, serialPortId);
|
||||||
if(serial.connect(serialPort)) {
|
if(serial.connect(serialPort)) {
|
||||||
serialsById.put(serialPortId, serial);
|
serialsById.put(serialPortId, serial);
|
||||||
|
@ -2104,10 +2104,10 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
String connectionStatus = serial.getConnectionStatus();
|
String connectionStatus = serial.getConnectionStatus();
|
||||||
try {
|
try {
|
||||||
int resId = Utils.resId(MainActivity.this, "string", connectionStatus);
|
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) {
|
} catch (Exception ex) {
|
||||||
Log.e(TAG, ex.getMessage());
|
Log.e(TAG, "Unknown error, connectionStatus: " + connectionStatus + ", " + ex.getMessage());
|
||||||
Toast.makeText(MainActivity.this, "Unknown error, connectionStatus: " + connectionStatus, Toast.LENGTH_LONG).show();
|
Toast.makeText(MainActivity.this, "Unknown error, connectionStatus: " + connectionStatus, Toast.LENGTH_SHORT).show();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2200,7 +2200,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setPort1Settings(boolean port1Plugged, boolean port1Writable) {
|
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_port1en", port1Plugged);
|
||||||
settings.putBoolean("settings_port1wr", port1Writable);
|
settings.putBoolean("settings_port1wr", port1Writable);
|
||||||
updateFromPreferences("settings_port1", true);
|
updateFromPreferences("settings_port1", true);
|
||||||
|
@ -2224,7 +2225,8 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
switch (key) {
|
switch (key) {
|
||||||
case "settings_realspeed":
|
case "settings_realspeed":
|
||||||
case "settings_grayscale":
|
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;
|
break;
|
||||||
|
|
||||||
case "settings_rotation":
|
case "settings_rotation":
|
||||||
|
@ -2347,9 +2349,6 @@ public class MainActivity extends AppCompatActivity implements NavigationView.On
|
||||||
NativeLib.setConfiguration("settings_serial_ports_ir", isDynamicValue, 0, 0,
|
NativeLib.setConfiguration("settings_serial_ports_ir", isDynamicValue, 0, 0,
|
||||||
DevicesFragment.SerialConnectParameters.fromSettingsString(settings.getString("settings_serial_ports_ir", "")).toWin32String());
|
DevicesFragment.SerialConnectParameters.fromSettingsString(settings.getString("settings_serial_ports_ir", "")).toWin32String());
|
||||||
break;
|
break;
|
||||||
case "settings_serial_slowdown":
|
|
||||||
NativeLib.setConfiguration(key, isDynamicValue, settings.getBoolean(key, false) ? 1 : 0, 0, null);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,7 +7,7 @@ buildscript {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
}
|
}
|
||||||
dependencies {
|
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
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
# http://www.gradle.org/docs/current/userguide/build_environment.html
|
||||||
# Specifies the JVM arguments used for the daemon process.
|
# Specifies the JVM arguments used for the daemon process.
|
||||||
# The setting is particularly useful for tweaking memory settings.
|
# The setting is particularly useful for tweaking memory settings.
|
||||||
android.defaults.buildfeatures.buildconfig=true
|
#android.defaults.buildfeatures.buildconfig=true
|
||||||
android.enableJetifier=true
|
android.enableJetifier=true
|
||||||
android.nonFinalResIds=true
|
android.nonFinalResIds=true
|
||||||
android.nonTransitiveRClass=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
|
#Sat Jan 28 21:16:38 CET 2023
|
||||||
distributionBase=GRADLE_USER_HOME
|
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
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|
Loading…
Reference in a new issue