Skip to content

Commit

Permalink
initial version
Browse files Browse the repository at this point in the history
  • Loading branch information
kai-morich committed Feb 2, 2019
0 parents commit 8841bde
Show file tree
Hide file tree
Showing 48 changed files with 1,517 additions and 0 deletions.
7 changes: 7 additions & 0 deletions .gitignore
@@ -0,0 +1,7 @@
*.iml
/.gradle/
/.idea/
/local.properties
/app/build/
/build/
/usbSerialForAndroid/
21 changes: 21 additions & 0 deletions LICENSE.txt
@@ -0,0 +1,21 @@
MIT License

Copyright (c) 2019 Kai Morich

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
26 changes: 26 additions & 0 deletions README.md
@@ -0,0 +1,26 @@
# SimpleUsbTerminal

This Android app provides a line-oriented terminal / console for devices with a serial / UART interface connected with a USB-to-serial-converter.

It supports USB to serial converters based on
- FTDI FT232, FT2232, ...
- Prolific PL2303
- Silabs CP2102, CP2105, ...
- Qinheng CH340

and devices implementing the USB CDC protocol like
- Arduino using ATmega32U4
- Digispark using V-USB software USB
- BBC micro:bit using ARM mbed DAPLink firmware

## How to start

The app uses the [usb-serial-for-android](https://github.com/kai-morich/usb-serial-for-android) library,
which is unfortunately not available in jcenter or maven-central repositories, so you have to add it manually.
Copy usbSerialForAndroid folder from usb-serial-for-android project into folder containing this README.md

## Motivation

I got various requests asking for help with Android development or source code for my
[Serial USB Terminal](https://play.google.com/store/apps/details?id=de.kai_morich.serial_usb_terminal) app.
Here you find a simplified version of my app.
30 changes: 30 additions & 0 deletions app/build.gradle
@@ -0,0 +1,30 @@
apply plugin: 'com.android.application'

android {
compileSdkVersion 28
defaultConfig {
targetSdkVersion 28
minSdkVersion 18
vectorDrawables.useSupportLibrary true

applicationId "de.kai_morich.simple_usb_terminal"
versionCode 1
versionName "1.0"
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}

dependencies {
implementation project(':usbSerialForAndroid')
implementation 'com.android.support:appcompat-v7:28.0.0'
implementation 'com.android.support:design:28.0.0'
}
21 changes: 21 additions & 0 deletions app/proguard-rules.pro
@@ -0,0 +1,21 @@
# Add project specific ProGuard rules here.
# You can control the set of applied configuration files using the
# proguardFiles setting in build.gradle.
#
# For more details, see
# http://developer.android.com/guide/developing/tools/proguard.html

# If your project uses WebView with JS, uncomment the following
# and specify the fully qualified class name to the JavaScript interface
# class:
#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
# public *;
#}

# Uncomment this to preserve the line number information for
# debugging stack traces.
#-keepattributes SourceFile,LineNumberTable

# If you keep the line number information, uncomment this to
# hide the original source file name.
#-renamesourcefileattribute SourceFile
32 changes: 32 additions & 0 deletions app/src/main/AndroidManifest.xml
@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="de.kai_morich.simple_usb_terminal">

<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />

<!-- mipmap/ic_launcher created with Android Studio -> New -> Image Asset using @color/colorPrimaryDark as background color -->
<application
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme"
tools:ignore="AllowBackup,GoogleAppIndexingWarning">
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:windowSoftInputMode="stateHidden|adjustResize">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED" />
</intent-filter>
<meta-data
android:name="android.hardware.usb.action.USB_DEVICE_ATTACHED"
android:resource="@xml/usb_device_filter" />
</activity>
<service android:name=".SerialService" />
</application>

</manifest>
14 changes: 14 additions & 0 deletions app/src/main/java/de/kai_morich/simple_usb_terminal/Constants.java
@@ -0,0 +1,14 @@
package de.kai_morich.simple_usb_terminal;

class Constants {

// values have to be globally unique
static final String INTENT_ACTION_DISCONNECT = BuildConfig.APPLICATION_ID + ".Disconnect";
static final String NOTIFICATION_CHANNEL = BuildConfig.APPLICATION_ID + ".Channel";
static final String INTENT_CLASS_MAIN_ACTIVITY = BuildConfig.APPLICATION_ID + ".MainActivity";

// values have to be unique within each app
static final int NOTIFY_MANAGER_START_FOREGROUND_SERVICE = 1001;

private Constants() {}
}
@@ -0,0 +1,151 @@
package de.kai_morich.simple_usb_terminal;

import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.hardware.usb.UsbDevice;
import android.hardware.usb.UsbManager;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v4.app.ListFragment;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

import com.hoho.android.usbserial.driver.UsbSerialDriver;
import com.hoho.android.usbserial.driver.UsbSerialProber;

import java.util.ArrayList;
import java.util.Locale;

public class DevicesFragment extends ListFragment {

class ListItem {
UsbDevice device;
int port;
UsbSerialDriver driver;

ListItem(UsbDevice device, int port, UsbSerialDriver driver) {
this.device = device;
this.port = port;
this.driver = driver;
}
}

private ArrayList<ListItem> listItems = new ArrayList<>();
private ArrayAdapter<ListItem> listAdapter;

private int baudRate = 19200;

public DevicesFragment() {
}

@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true);
listAdapter = new ArrayAdapter<ListItem>(getActivity(), 0, listItems) {
@Override
public View getView(int position, View view, ViewGroup parent) {
ListItem item = listItems.get(position);
if (view == null)
view = getActivity().getLayoutInflater().inflate(R.layout.device_list_item, parent, false);
TextView text1 = view.findViewById(R.id.text1);
TextView text2 = view.findViewById(R.id.text2);
if(item.driver == null)
text1.setText("<no driver>");
else if(item.driver.getPorts().size() == 1)
text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver",""));
else
text1.setText(item.driver.getClass().getSimpleName().replace("SerialDriver","")+", Port "+item.port);
text2.setText(String.format(Locale.US, "Vendor %04X, Product %04X", item.device.getVendorId(), item.device.getProductId()));
return view;
}
};
}

@Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
setListAdapter(null);
View header = getActivity().getLayoutInflater().inflate(R.layout.device_list_header, null, false);
getListView().addHeaderView(header, null, false);
setEmptyText("<no USB devices found>");
((TextView) getListView().getEmptyView()).setTextSize(18);
setListAdapter(listAdapter);
}

@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
inflater.inflate(R.menu.menu_devices, menu);
}

@Override
public void onResume() {
super.onResume();
refresh();
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if(id == R.id.refresh) {
refresh();
return true;
} else if (id ==R.id.baud_rate) {
final String[] baudRates = getResources().getStringArray(R.array.baud_rates);
int pos = java.util.Arrays.asList(baudRates).indexOf(String.valueOf(baudRate));
AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
builder.setTitle("Baud rate");
builder.setSingleChoiceItems(baudRates, pos, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int item) {
baudRate = Integer.valueOf(baudRates[item]);
dialog.dismiss();
}
});
builder.create().show();
return true;
} else {
return super.onOptionsItemSelected(item);
}
}

void refresh() {
UsbManager usbManager = (UsbManager) getActivity().getSystemService(Context.USB_SERVICE);
UsbSerialProber usbSerialProber = UsbSerialProber.getDefaultProber();
listItems.clear();
for(UsbDevice device : usbManager.getDeviceList().values()) {
UsbSerialDriver driver = usbSerialProber.probeDevice(device);
if(driver != null) {
for(int port = 0; port < driver.getPorts().size(); port++)
listItems.add(new ListItem(device, port, driver));
} else {
listItems.add(new ListItem(device, 0, null));
}
}
listAdapter.notifyDataSetChanged();
}

@Override
public void onListItemClick(ListView l, View v, int position, long id) {
ListItem item = listItems.get(position-1);
if(item.driver == null) {
Toast.makeText(getActivity(), "no driver", Toast.LENGTH_SHORT).show();
} else {
Bundle args = new Bundle();
args.putInt("device", item.device.getDeviceId());
args.putInt("port", item.port);
args.putInt("baud", baudRate);
Fragment fragment = new TerminalFragment();
fragment.setArguments(args);
getFragmentManager().beginTransaction().replace(R.id.fragment, fragment, "terminal").addToBackStack(null).commit();
}
}

}
@@ -0,0 +1,33 @@
package de.kai_morich.simple_usb_terminal;

import android.os.Bundle;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;

public class MainActivity extends AppCompatActivity implements FragmentManager.OnBackStackChangedListener {

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
Toolbar toolbar = findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
getSupportFragmentManager().addOnBackStackChangedListener(this);
if (savedInstanceState == null)
getSupportFragmentManager().beginTransaction().add(R.id.fragment, new DevicesFragment(), "devices").commit();
else
onBackStackChanged();
}

@Override
public void onBackStackChanged() {
getSupportActionBar().setDisplayHomeAsUpEnabled(getSupportFragmentManager().getBackStackEntryCount()>0);
}

@Override
public boolean onSupportNavigateUp() {
onBackPressed();
return true;
}
}
@@ -0,0 +1,8 @@
package de.kai_morich.simple_usb_terminal;

interface SerialListener {
void onSerialConnect ();
void onSerialConnectError (Exception e);
void onSerialRead (byte[] data);
void onSerialIoError (Exception e);
}

2 comments on commit 8841bde

@CristianoIlmo
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am facing problems to connect arduino Due.
With device attached appears vendor2341, Product003D in USB Devices screen.
Could someone help me?
Thanks!
,

@kai-morich
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some Arduino devices use rarely used VID/PID, typically created while the Arduino project was split.
You can add these IDs to your https://github.com/kai-morich/SimpleUsbTerminal/blob/master/app/src/main/java/de/kai_morich/simple_usb_terminal/CustomProber.java class

Please sign in to comment.