From a01211ec8802e3e96ff811f665617a9bf9fada73 Mon Sep 17 00:00:00 2001 From: Ramandeep Date: Fri, 21 Jan 2022 20:55:06 +0530 Subject: [PATCH] Sickle Cell App With Usb Integration --- app/.gitignore | 1 + app/build.gradle | 40 ++ app/proguard-rules.pro | 21 + .../sickle_cell/ExampleInstrumentedTest.java | 26 + app/src/main/AndroidManifest.xml | 30 + .../shanmukha/in/sickle_cell/Serial_Com.java | 572 ++++++++++++++++++ .../in/sickle_cell/SplashScreen.java | 39 ++ .../shanmukha/in/sickle_cell/UsbService.java | 499 +++++++++++++++ .../shanmukha/in/sickle_cell/flag_pojo.java | 31 + .../java/shanmukha/in/sickle_cell/pojo.java | 94 +++ .../drawable-v24/ic_launcher_foreground.xml | 30 + app/src/main/res/drawable/buttonshape.xml | 20 + .../res/drawable/ic_launcher_background.xml | 170 ++++++ .../res/drawable/shanmukha_logo_small.png | Bin 0 -> 34428 bytes app/src/main/res/drawable/text_back.xml | 7 + app/src/main/res/layout/activity_serial.xml | 104 ++++ .../res/layout/activity_splash_screen.xml | 230 +++++++ .../res/mipmap-anydpi-v26/ic_launcher.xml | 5 + .../mipmap-anydpi-v26/ic_launcher_round.xml | 5 + app/src/main/res/mipmap-hdpi/ic_launcher.png | 0 .../res/mipmap-hdpi/ic_launcher_round.png | 0 app/src/main/res/mipmap-mdpi/ic_launcher.png | 0 .../res/mipmap-mdpi/ic_launcher_round.png | 0 app/src/main/res/mipmap-xhdpi/ic_launcher.png | 0 .../res/mipmap-xhdpi/ic_launcher_round.png | 0 .../main/res/mipmap-xxhdpi/ic_launcher.png | 0 .../res/mipmap-xxhdpi/ic_launcher_round.png | 0 .../main/res/mipmap-xxxhdpi/ic_launcher.png | 0 .../res/mipmap-xxxhdpi/ic_launcher_round.png | 0 app/src/main/res/values/colors.xml | 6 + app/src/main/res/values/strings.xml | 7 + app/src/main/res/values/styles.xml | 10 + .../in/sickle_cell/ExampleUnitTest.java | 17 + 33 files changed, 1964 insertions(+) create mode 100644 app/.gitignore create mode 100644 app/build.gradle create mode 100644 app/proguard-rules.pro create mode 100644 app/src/androidTest/java/shanmukha/in/sickle_cell/ExampleInstrumentedTest.java create mode 100644 app/src/main/AndroidManifest.xml create mode 100644 app/src/main/java/shanmukha/in/sickle_cell/Serial_Com.java create mode 100644 app/src/main/java/shanmukha/in/sickle_cell/SplashScreen.java create mode 100644 app/src/main/java/shanmukha/in/sickle_cell/UsbService.java create mode 100644 app/src/main/java/shanmukha/in/sickle_cell/flag_pojo.java create mode 100644 app/src/main/java/shanmukha/in/sickle_cell/pojo.java create mode 100644 app/src/main/res/drawable-v24/ic_launcher_foreground.xml create mode 100644 app/src/main/res/drawable/buttonshape.xml create mode 100644 app/src/main/res/drawable/ic_launcher_background.xml create mode 100644 app/src/main/res/drawable/shanmukha_logo_small.png create mode 100644 app/src/main/res/drawable/text_back.xml create mode 100644 app/src/main/res/layout/activity_serial.xml create mode 100644 app/src/main/res/layout/activity_splash_screen.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml create mode 100644 app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-hdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-mdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher.png create mode 100644 app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png create mode 100644 app/src/main/res/values/colors.xml create mode 100644 app/src/main/res/values/strings.xml create mode 100644 app/src/main/res/values/styles.xml create mode 100644 app/src/test/java/shanmukha/in/sickle_cell/ExampleUnitTest.java diff --git a/app/.gitignore b/app/.gitignore new file mode 100644 index 0000000..42afabf --- /dev/null +++ b/app/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/app/build.gradle b/app/build.gradle new file mode 100644 index 0000000..5706093 --- /dev/null +++ b/app/build.gradle @@ -0,0 +1,40 @@ +apply plugin: 'com.android.application' + +android { + compileSdkVersion 30 + buildToolsVersion "30.0.0" + + defaultConfig { + applicationId "shanmukha.in.sickle_cell" + minSdkVersion 16 + targetSdkVersion 30 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } + compileOptions { + sourceCompatibility JavaVersion.VERSION_1_8 + targetCompatibility JavaVersion.VERSION_1_8 + } +} + +dependencies { + implementation fileTree(dir: "libs", include: ["*.jar"]) + implementation 'androidx.appcompat:appcompat:1.1.0' + implementation 'androidx.constraintlayout:constraintlayout:1.1.3' + implementation 'com.google.android.material:material:1.0.0' + implementation 'com.github.felHR85:UsbSerial:6.1.0' + + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test.ext:junit:1.1.1' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + +} \ No newline at end of file diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro new file mode 100644 index 0000000..481bb43 --- /dev/null +++ b/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 \ No newline at end of file diff --git a/app/src/androidTest/java/shanmukha/in/sickle_cell/ExampleInstrumentedTest.java b/app/src/androidTest/java/shanmukha/in/sickle_cell/ExampleInstrumentedTest.java new file mode 100644 index 0000000..411553a --- /dev/null +++ b/app/src/androidTest/java/shanmukha/in/sickle_cell/ExampleInstrumentedTest.java @@ -0,0 +1,26 @@ +package shanmukha.in.sickle_cell; + +import android.content.Context; + +import androidx.test.platform.app.InstrumentationRegistry; +import androidx.test.ext.junit.runners.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) +public class ExampleInstrumentedTest { + @Test + public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext(); + assertEquals("com.xoco96.serialled", appContext.getPackageName()); + } +} \ No newline at end of file diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml new file mode 100644 index 0000000..4174495 --- /dev/null +++ b/app/src/main/AndroidManifest.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/java/shanmukha/in/sickle_cell/Serial_Com.java b/app/src/main/java/shanmukha/in/sickle_cell/Serial_Com.java new file mode 100644 index 0000000..02844c2 --- /dev/null +++ b/app/src/main/java/shanmukha/in/sickle_cell/Serial_Com.java @@ -0,0 +1,572 @@ +package shanmukha.in.sickle_cell; + +import androidx.appcompat.app.AppCompatActivity; + +import android.app.AlertDialog; +import android.app.PendingIntent; +import android.content.DialogInterface; +import android.hardware.usb.UsbDevice; +import android.os.Bundle; + +import android.content.BroadcastReceiver; +import android.content.ComponentName; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.content.ServiceConnection; +import android.os.Handler; +import android.os.IBinder; +import android.os.Message; +import android.util.Log; +import android.view.View; +import android.widget.Button; +import android.widget.TextView; +import android.widget.Toast; + +import java.lang.ref.WeakReference; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +import static shanmukha.in.sickle_cell.UsbService.obj; + +public class Serial_Com extends AppCompatActivity { + public static flag_pojo fobj = new flag_pojo(); +int flag=0; +int dev=0;int bas=0;int ru=0; + /* + * Notifications from UsbService will be received here. + */ + private final BroadcastReceiver mUsbReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context context, Intent intent) { + switch (intent.getAction()) { + case UsbService.ACTION_USB_PERMISSION_GRANTED: // USB PERMISSION GRANTED + flag=0; + + Toast.makeText(context, "USB Ready", Toast.LENGTH_SHORT).show(); + break; + case UsbService.ACTION_USB_PERMISSION_NOT_GRANTED: // USB PERMISSION NOT GRANTED + Toast.makeText(context, "USB Permission not granted", Toast.LENGTH_SHORT).show(); + flag=1; + + break; + case UsbService.ACTION_NO_USB: // NO USB CONNECTED + Toast.makeText(context, "No USB connected", Toast.LENGTH_SHORT).show(); + flag=1; + break; + case UsbService.ACTION_USB_DISCONNECTED: // USB DISCONNECTED + Toast.makeText(context, "USB disconnected", Toast.LENGTH_SHORT).show(); + break; + case UsbService.ACTION_USB_NOT_SUPPORTED: // USB NOT SUPPORTED + Toast.makeText(context, "USB device not supported", Toast.LENGTH_SHORT).show(); + break; + } + } + }; + private UsbService usbService; + + private MyHandler mHandler; + double ratio,ab_427,ab_555; + private static final String ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"; + private TextView textViewTitle ; + String result; + private final ServiceConnection usbConnection = new ServiceConnection() { + @Override + public void onServiceConnected(ComponentName arg0, IBinder arg1) { + usbService = ((UsbService.UsbBinder) arg1).getService(); + usbService.setHandler(mHandler); + } + + @Override + public void onServiceDisconnected(ComponentName arg0) { + usbService = null; + } + }; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_serial); + + mHandler = new MyHandler(this); + textViewTitle=findViewById(R.id.textViewTitle1); + + Button sendButton = (Button) findViewById(R.id.buttonSend); + Button baseli=(Button) findViewById(R.id.baseline_c); + Button runi=(Button) findViewById(R.id.run_c); + Button next=(Button) findViewById(R.id.next_c); + next.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + if (dev == 1 && bas == 1 && ru == 1) { + + + if (flag != 1) { + + + Log.e("x 427 pixel ", obj.getX_427()); + Log.e("x 555 pixel ", obj.getX_555()); + + + Log.e("i 427 pixel ", obj.getI_427()); + + Log.e("i 555 pixel ", obj.getI_555()); + + + Log.e("f 427 pixel ", obj.getF_427()); + + + Log.e("f 555 pixel ", obj.getF_555()); + + ab_427 = Math.log(Double.parseDouble(obj.getF_427()) / Double.parseDouble(obj.getI_427())); + Log.e("ab 427 ", String.valueOf(ab_427)); + + + ab_555 = Math.log(Double.parseDouble(obj.getF_555()) / Double.parseDouble(obj.getI_555())); + Log.e("ab 555 ", String.valueOf(ab_555)); + + ratio = ab_555 / ab_427; + + Log.e("ratio ", String.valueOf(ratio)); + + if (ratio < 0.32) { + result = "Healthy"; + Log.e("result ", String.valueOf(result)); + textViewTitle.setText(result); + } else if (ratio > 0.32 && ratio < 0.475) { + result = "SCT"; + Log.e("result ", String.valueOf(result)); + textViewTitle.setText(result); + + + } else if (ratio > 0.475) { + + result = "SCD"; + textViewTitle.setText(result); + + Log.e("result ", String.valueOf(result)); + + } else { + + textViewTitle.setText("No Result Try Again"); + + } + } else { + Toast.makeText(Serial_Com.this, "USB Not Connect", Toast.LENGTH_SHORT).show(); + + } + + + /* Intent intent=new Intent (Serial_Com.this,run23.class); + startActivity(intent);*/ + } + dev=0;ru=0;bas=0; + + } + + }); + + + runi.setOnClickListener(new View.OnClickListener() + + { + @Override + public void onClick (View v){ + fobj.setRun_flag(1); + ru=1; + if (bas == 1 && dev == 1) { + if (usbService != null) { + + try { + int number427 = Integer.valueOf(obj.getX_427()); + Thread.sleep(1000); + + int number555 = Integer.valueOf(obj.getX_555()); + Log.e("Final x value 555", String.valueOf(number555)); + + + Thread.sleep(1000); + String string44 = "print " + number427 + "\r"; + usbService.write(string44.getBytes()); + + + Thread.sleep(2000); + String string45 = "print " + number555 + "\r"; + usbService.write(string45.getBytes()); + + + Thread.sleep(2000); + + + } catch (InterruptedException e) { + e.printStackTrace(); + } + + } else { + Toast.makeText(Serial_Com.this, "USB Not Connect", Toast.LENGTH_SHORT).show(); + + } + + /* try { + Thread.sleep(1000); + int number427=Integer.valueOf(obj.getX_427()); + Thread.sleep(1000); + + int number555=Integer.valueOf(obj.getX_555()); +Log.e("Final x value 555", String.valueOf(number555)); + + + Thread.sleep(1000); + String string44 = "print "+number427+"\r"; + usbService.write(string44.getBytes()); + + + Thread.sleep(1000); + String string45 = "print "+number555+"\r"; + usbService.write(string45.getBytes()); + + + Thread.sleep(1000); + + + } catch (InterruptedException e) { + e.printStackTrace(); + } + + +*/ + + + } else { + Toast.makeText(Serial_Com.this, "Set Device and Baseline PAramter before ", Toast.LENGTH_SHORT).show(); + + } + + + } + + + + }); + + baseli.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + fobj.setBaseline_flag(1); + bas=1; + if(dev==1) { + if (flag == 0) { + + Log.e("X value 427 usb service", obj.getX_427()); + Log.e("X value 555 usb service", obj.getX_555()); + + String string22 = "led2 50\r"; + + usbService.write(string22.getBytes()); + String string1 = "autoset\r"; + + + usbService.write(string1.getBytes()); + + + try { + Thread.sleep(Long.parseLong("1000")); + String string4 = "run\r"; + + + Thread.sleep(2000); + + usbService.write(string4.getBytes()); + Thread.sleep(2000); + + int number427 = Integer.valueOf(obj.getX_427()); + Thread.sleep(1000); + + int number555 = Integer.valueOf(obj.getX_555()); + + + Thread.sleep(2000); + String string44 = "print " + number427 + "\r"; + usbService.write(string44.getBytes()); + + + Thread.sleep(2000); + String string45 = "print " + number555 + "\r"; + usbService.write(string45.getBytes()); + + + Thread.sleep(2000); + + + } catch (InterruptedException e) { + e.printStackTrace(); + } + + + + + /* String string22 = "led2 50\r"; + + usbService.write(string22.getBytes()); + String string1 = "autoset\r"; + + + usbService.write(string1.getBytes()); + + + try { + Thread.sleep(Long.parseLong("1000")); + String string4 = "run\r"; + + + Thread.sleep(2000); + + usbService.write(string4.getBytes()); + Thread.sleep(2000); + + int number1=45; + + Thread.sleep(2000); + + usbService.write(string4.getBytes()); + Thread.sleep(2000); + String string44 = "print "+number1+"\r"; + usbService.write(string44.getBytes()); + + + Thread.sleep(2000); + + + + + + + String string = data + "\r"; + + usbService.write(string.getBytes()); + + + + } catch (InterruptedException e) { + e.printStackTrace(); + }*/ + + +// if UsbService was correctly binded, Send data + } else { + Toast.makeText(Serial_Com.this, "USB Not Connect", Toast.LENGTH_SHORT).show(); + + } + } + else + { + Toast.makeText(Serial_Com.this, "Get Device Parameters First ", Toast.LENGTH_SHORT).show(); + + } + } + }); + + sendButton.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + fobj.setConnect_flag(1); +dev=1; + textViewTitle.setText(""); + if (flag==0) { + + + try { + + String string22 = "read\r"; + + usbService.write(string22.getBytes()); + + Thread.sleep(10000); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + /* String string22 = "led2 50\r"; + + usbService.write(string22.getBytes()); + String string1 = "autoset\r"; + + + usbService.write(string1.getBytes()); + + + try { + Thread.sleep(Long.parseLong("1000")); + String string4 = "run\r"; + + + Thread.sleep(2000); + + usbService.write(string4.getBytes()); + Thread.sleep(2000); + + int number1=45; + + Thread.sleep(2000); + + usbService.write(string4.getBytes()); + Thread.sleep(2000); + String string44 = "print "+number1+"\r"; + usbService.write(string44.getBytes()); + + + Thread.sleep(2000); + + + + + + + String string = data + "\r"; + + usbService.write(string.getBytes()); + + + + } catch (InterruptedException e) { + e.printStackTrace(); + }*/ + + + + + +// if UsbService was correctly binded, Send data + } + else + { + Toast.makeText(Serial_Com.this, "USB Not Connect", Toast.LENGTH_SHORT).show(); + + } + } + }); + + + } + + @Override + public void onResume() { + super.onResume(); + setFilters(); // Start listening notifications from UsbService + startService(UsbService.class, usbConnection, null); // Start UsbService(if it was not started before) and Bind it + } + + @Override + public void onPause() { + super.onPause(); + unregisterReceiver(mUsbReceiver); + unbindService(usbConnection); + } + + private void startService(Class service, ServiceConnection serviceConnection, Bundle extras) { + if (!UsbService.SERVICE_CONNECTED) { + Intent startService = new Intent(this, service); + if (extras != null && !extras.isEmpty()) { + Set keys = extras.keySet(); + for (String key : keys) { + String extra = extras.getString(key); + startService.putExtra(key, extra); + } + } + startService(startService); + } + Intent bindingIntent = new Intent(this, service); + bindService(bindingIntent, serviceConnection, Context.BIND_AUTO_CREATE); + } + + private void setFilters() { + IntentFilter filter = new IntentFilter(); + filter.addAction(UsbService.ACTION_USB_PERMISSION_GRANTED); + filter.addAction(UsbService.ACTION_NO_USB); + filter.addAction(UsbService.ACTION_USB_DISCONNECTED); + filter.addAction(UsbService.ACTION_USB_NOT_SUPPORTED); + filter.addAction(UsbService.ACTION_USB_PERMISSION_NOT_GRANTED); + registerReceiver(mUsbReceiver, filter); + } + + /* + * This handler will be passed to UsbService. Data received from serial port is displayed through this handler + */ + private static class MyHandler extends Handler { + private final WeakReference mActivity; + + public MyHandler(Serial_Com activity) { + mActivity = new WeakReference<>(activity); + } + + @Override + public void handleMessage(Message msg) { + switch (msg.what) { + case UsbService.MESSAGE_FROM_SERIAL_PORT: + String data = (String) msg.obj; + break; + + case UsbService.SYNC_READ: + String buffer = (String) msg.obj; + break; + } + } + } + public void onClickconectar(View view) { + UsbService sf=new UsbService(); + HashMap usbDevices = sf.usbManager.getDeviceList(); + if (!usbDevices.isEmpty()) { + boolean keep = true; + for (Map.Entry entry : usbDevices.entrySet()) { + flag=0; + + sf.device = entry.getValue(); + int deviceVID = sf.device.getVendorId(); + if (deviceVID == 0x0403 || deviceVID == 0x0403)// Arduino Vendor ID + //if(deviceVID == 0x2341)// Arduino Vendor ID + { + PendingIntent pi = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); + sf.usbManager.requestPermission(sf.device, pi); + keep = false; + } else { + sf.connection = null; + sf.device = null; + } + + if (!keep) + break; + flag=0; + } + } + } + @Override + public void onBackPressed() { + AlertDialog.Builder builder = new AlertDialog.Builder(this); + builder.setCancelable(false); + builder.setMessage("Do you want to Exit ?"); + + builder.setPositiveButton("Yes", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + finishAffinity(); + finish(); + + + + + } + }); + builder.setNegativeButton("No", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + + dialog.cancel(); + } + }); + AlertDialog alert = builder.create(); + alert.show(); + } + +} \ No newline at end of file diff --git a/app/src/main/java/shanmukha/in/sickle_cell/SplashScreen.java b/app/src/main/java/shanmukha/in/sickle_cell/SplashScreen.java new file mode 100644 index 0000000..ef82c00 --- /dev/null +++ b/app/src/main/java/shanmukha/in/sickle_cell/SplashScreen.java @@ -0,0 +1,39 @@ +package shanmukha.in.sickle_cell; + +import android.content.Intent; +import android.content.SharedPreferences; +import android.os.Bundle; +import android.os.Handler; + +import androidx.appcompat.app.AppCompatActivity; + + +public class SplashScreen extends AppCompatActivity { + + private static int SPLASH_TIME_OUT=3000; + String number; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_splash_screen); + SharedPreferences preferences6 = getSharedPreferences("PhoneBook_number", MODE_PRIVATE); + + number = preferences6.getString("Phone", null); + + new Handler().postDelayed(new Runnable() { + @Override + public void run() { + + + + Intent home = new Intent(SplashScreen.this, Serial_Com.class); + startActivity(home); + finish(); + + + + } + }, SPLASH_TIME_OUT); + } +} diff --git a/app/src/main/java/shanmukha/in/sickle_cell/UsbService.java b/app/src/main/java/shanmukha/in/sickle_cell/UsbService.java new file mode 100644 index 0000000..9f66a23 --- /dev/null +++ b/app/src/main/java/shanmukha/in/sickle_cell/UsbService.java @@ -0,0 +1,499 @@ +package shanmukha.in.sickle_cell; + +import android.app.PendingIntent; +import android.app.Service; +import android.content.BroadcastReceiver; +import android.content.Context; +import android.content.Intent; +import android.content.IntentFilter; +import android.hardware.usb.UsbDevice; +import android.hardware.usb.UsbDeviceConnection; +import android.hardware.usb.UsbManager; +import android.os.Binder; +import android.os.Handler; +import android.os.IBinder; +import android.util.Log; + +import com.felhr.usbserial.CDCSerialDevice; +import com.felhr.usbserial.UsbSerialDevice; +import com.felhr.usbserial.UsbSerialInterface; + +import java.io.UnsupportedEncodingException; +import java.math.BigDecimal; +import java.util.HashMap; +import java.util.Map; + +import static shanmukha.in.sickle_cell.Serial_Com.fobj; + +public class UsbService extends Service { + + public static final String TAG = "UsbService"; + + public static final String ACTION_USB_READY = "USB_READY"; + public static final String ACTION_USB_ATTACHED = "USB_DEVICE_ATTACHED"; + public static final String ACTION_USB_DETACHED = "USB_DEVICE_DETACHED"; + public static final String ACTION_USB_NOT_SUPPORTED = "USB_NOT_SUPPORTED"; + public static final String ACTION_NO_USB = "NO_USB"; + public static final String ACTION_USB_PERMISSION_GRANTED = "USB_PERMISSION_GRANTED"; + public static final String ACTION_USB_PERMISSION_NOT_GRANTED = "USB_PERMISSION_NOT_GRANTED"; + public static final String ACTION_USB_DISCONNECTED = "USB_DISCONNECTED"; + public static final String ACTION_CDC_DRIVER_NOT_WORKING = "ACTION_CDC_DRIVER_NOT_WORKING"; + public static final String ACTION_USB_DEVICE_NOT_WORKING = "ACTION_USB_DEVICE_NOT_WORKING"; + public static final int MESSAGE_FROM_SERIAL_PORT = 0; + public static final int CTS_CHANGE = 1; + public static final int DSR_CHANGE = 2; + public static final int SYNC_READ = 3; + private static final String ACTION_USB_PERMISSION = "shanmukha.in.sickle_cell.USB_PERMISSION"; + public static boolean SERVICE_CONNECTED = false; + + private IBinder binder = new UsbBinder(); + + private Context context; + private Handler mHandler; + public static UsbManager usbManager; + public static UsbDevice device; + public static UsbDeviceConnection connection; + + private UsbSerialDevice serialPort; + float a, b, c, d, ddash_427, ddash_555; + int wl_427, wl_555; + String i_427, i_555,f_427,f_555; + public static pojo obj = new pojo(); + private boolean serialPortConnected; + /* + * Data received from serial port will be received here. Just populate onReceivedData with your code + * In this particular example. byte stream is converted to String and send to UI thread to + * be treated there. + */ + private UsbSerialInterface.UsbReadCallback mCallback = new UsbSerialInterface.UsbReadCallback() { + @Override + public void onReceivedData(byte[] arg0) { + String data = null; + + try { + data = new String(arg0, "UTF-8"); + + data.concat("/n"); + + + if (data.contains(",")) { + + + String[] namesList = data.split(","); + + BigDecimal d5 = new BigDecimal(namesList[3]); + + ddash_427 = (float) (Float.parseFloat(String.valueOf((d5))) - 427.00); + ddash_555 = (float) (Float.parseFloat(String.valueOf((d5))) - 555.00); + + + BigDecimal d3 = new BigDecimal(namesList[2]); + BigDecimal d1 = new BigDecimal(namesList[1]); + + Double d8 = (Double) (-d3.doubleValue() + Math.sqrt(Math.pow(d3.doubleValue(), 2) - 4 * (d1).doubleValue() * ddash_427)); + d8 = d8 / (2 * d1.doubleValue()); + BigDecimal d11 = new BigDecimal(d8); + System.out.println(d11.toPlainString()); + wl_427 = (int) Math.round(d8); + obj.setX_427(String.valueOf(wl_427)); + Log.e("Value x 427 ", String.valueOf(wl_427)); + Log.e("Value x 427 obj ", String.valueOf(obj.getX_427())); + + + + Double d9 = (Double) (-d3.doubleValue() + Math.sqrt(Math.pow(d3.doubleValue(), 2) - 4 * (d1).doubleValue() * ddash_555)); + d9 = d9 / (2 * d1.doubleValue()); + BigDecimal d12 = new BigDecimal(d9); + System.out.println(d12.toPlainString()); + wl_555 = (int) Math.round(d9); + Log.e("Value x 555 ", String.valueOf(wl_555)); + obj.setX_555(String.valueOf(wl_555)); + Log.e("Value x 555 obj ", String.valueOf(obj.getX_555())); + + + } + } catch (UnsupportedEncodingException e){ + e.printStackTrace(); + } + + + + try { + String data1 = new String(arg0, "UTF-8"); + if (mHandler != null) + mHandler.obtainMessage(MESSAGE_FROM_SERIAL_PORT, data1).sendToTarget(); + } catch (UnsupportedEncodingException e) { + e.printStackTrace(); + } + + } + }; + + + private UsbSerialInterface.UsbCTSCallback ctsCallback = new UsbSerialInterface.UsbCTSCallback() { + @Override + public void onCTSChanged(boolean state) { + if(mHandler != null) + mHandler.obtainMessage(CTS_CHANGE).sendToTarget(); + } + }; + + /* + * State changes in the DSR line will be received here + */ + private UsbSerialInterface.UsbDSRCallback dsrCallback = new UsbSerialInterface.UsbDSRCallback() { + @Override + public void onDSRChanged(boolean state) { + if(mHandler != null) + mHandler.obtainMessage(DSR_CHANGE).sendToTarget(); + } + }; + + private final BroadcastReceiver usbReceiver = new BroadcastReceiver() { + @Override + public void onReceive(Context arg0, Intent arg1) { + if (arg1.getAction().equals(ACTION_USB_PERMISSION)) { + boolean granted = arg1.getExtras().getBoolean(UsbManager.EXTRA_PERMISSION_GRANTED); + if (granted) // User accepted our USB connection. Try to open the device as a serial port + { + Intent intent = new Intent(ACTION_USB_PERMISSION_GRANTED); + arg0.sendBroadcast(intent); + connection = usbManager.openDevice(device); + new ConnectionThread().start(); + } else // User not accepted our USB connection. Send an Intent to the Main Activity + { + Intent intent = new Intent(ACTION_USB_PERMISSION_NOT_GRANTED); + arg0.sendBroadcast(intent); + } + } else if (arg1.getAction().equals(ACTION_USB_ATTACHED)) { + if (!serialPortConnected) + findSerialPortDevice(); // A USB device has been attached. Try to open it as a Serial port + } else if (arg1.getAction().equals(ACTION_USB_DETACHED)) { + // Usb device was disconnected. send an intent to the Main Activity + Intent intent = new Intent(ACTION_USB_DISCONNECTED); + arg0.sendBroadcast(intent); + if (serialPortConnected) { + serialPort.syncClose(); + } + serialPortConnected = false; + } + } + }; + + /* + * onCreate will be executed when service is started. It configures an IntentFilter to listen for + * incoming Intents (USB ATTACHED, USB DETACHED...) and it tries to open a serial port. + */ + @Override + public void onCreate() { + this.context = this; + serialPortConnected = false; + UsbService.SERVICE_CONNECTED = true; + setFilter(); + usbManager = (UsbManager) getSystemService(Context.USB_SERVICE); + findSerialPortDevice(); + } + + /* MUST READ about services + * http://developer.android.com/guide/components/services.html + * http://developer.android.com/guide/components/bound-services.html + */ + @Override + public IBinder onBind(Intent intent) { + return binder; + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + return Service.START_NOT_STICKY; + } + + @Override + public void onDestroy() { + super.onDestroy(); + serialPort.close(); + unregisterReceiver(usbReceiver); + UsbService.SERVICE_CONNECTED = false; + } + + /* + * This function will be called from MainActivity to write data through Serial Port + */ + public void write(byte[] data) { + if (serialPort != null) + serialPort.syncWrite(data, 0); + } + + /* + * This function will be called from MainActivity to change baud rate + */ + + public void changeBaudRate(int baudRate){ + if(serialPort != null) + serialPort.setBaudRate(baudRate); + } + + public void setHandler(Handler mHandler) { + this.mHandler = mHandler; + } + + private void findSerialPortDevice() { + // This snippet will try to open the first encountered usb device connected, excluding usb root hubs + HashMap usbDevices = usbManager.getDeviceList(); + if (!usbDevices.isEmpty()) { + + // first, dump the map for diagnostic purposes + for (Map.Entry entry : usbDevices.entrySet()) { + device = entry.getValue(); + Log.d(TAG, String.format("USBDevice.HashMap (vid:pid) (%X:%X)-%b class:%X:%X name:%s", + device.getVendorId(), device.getProductId(), + UsbSerialDevice.isSupported(device), + device.getDeviceClass(), device.getDeviceSubclass(), + device.getDeviceName())); + } + + for (Map.Entry entry : usbDevices.entrySet()) { + device = entry.getValue(); + int deviceVID = device.getVendorId(); + int devicePID = device.getProductId(); + +// if (deviceVID != 0x1d6b && (devicePID != 0x0001 && devicePID != 0x0002 && devicePID != 0x0003)) { + if (UsbSerialDevice.isSupported(device)) { + // There is a device connected to our Android device. Try to open it as a Serial Port. + requestUserPermission(); + break; + } else { + connection = null; + device = null; + } + } + if (device==null) { + // There is no USB devices connected (but usb host were listed). Send an intent to MainActivity. + Intent intent = new Intent(ACTION_NO_USB); + sendBroadcast(intent); + } + } else { + Log.d(TAG, "findSerialPortDevice() usbManager returned empty device list." ); + // There is no USB devices connected. Send an intent to MainActivity + Intent intent = new Intent(ACTION_NO_USB); + sendBroadcast(intent); + } + } + + private void setFilter() { + IntentFilter filter = new IntentFilter(); + filter.addAction(ACTION_USB_PERMISSION); + filter.addAction(ACTION_USB_DETACHED); + filter.addAction(ACTION_USB_ATTACHED); + registerReceiver(usbReceiver, filter); + } + + /* + * Request user permission. The response will be received in the BroadcastReceiver + */ + private void requestUserPermission() { + Log.d(TAG, String.format("requestUserPermission(%X:%X)", device.getVendorId(), device.getProductId() ) ); + PendingIntent mPendingIntent = PendingIntent.getBroadcast(this, 0, new Intent(ACTION_USB_PERMISSION), 0); + usbManager.requestPermission(device, mPendingIntent); + } + + public class UsbBinder extends Binder { + public UsbService getService() { + return UsbService.this; + } + } + + /* + * A simple thread to open a serial port. + * Although it should be a fast operation. moving usb operations away from UI thread is a good thing. + */ + private class ConnectionThread extends Thread { + @Override + public void run() { + serialPort = UsbSerialDevice.createUsbSerialDevice(device, connection); + if (serialPort != null) { + if (serialPort.syncOpen()) { + serialPortConnected = true; + serialPort.setBaudRate(115200); + serialPort.setDataBits(UsbSerialInterface.DATA_BITS_8); + serialPort.setStopBits(UsbSerialInterface.STOP_BITS_1); + serialPort.setParity(UsbSerialInterface.PARITY_NONE); + + serialPort.setFlowControl(UsbSerialInterface.FLOW_CONTROL_OFF); + serialPort.read(mCallback); + serialPort.getCTS(ctsCallback); + serialPort.getDSR(dsrCallback); + + new ReadThread().start(); + + + Intent intent = new Intent(ACTION_USB_READY); + context.sendBroadcast(intent); + } else { + if (serialPort instanceof CDCSerialDevice) { + Intent intent = new Intent(ACTION_CDC_DRIVER_NOT_WORKING); + context.sendBroadcast(intent); + } else { + Intent intent = new Intent(ACTION_USB_DEVICE_NOT_WORKING); + context.sendBroadcast(intent); + } + } + } else { + Intent intent = new Intent(ACTION_USB_NOT_SUPPORTED); + context.sendBroadcast(intent); + } + } + } + + private class ReadThread extends Thread { + @Override + public void run() { + while (true) { + byte[] buffer = new byte[100]; + int n = serialPort.syncRead(buffer, 0); + if (n > 0) { + byte[] received = new byte[n]; + System.arraycopy(buffer, 0, received, 0, n); + String receivedStr = new String(received); + Log.e("Recived Data", receivedStr); + String data = null; + + data = new String(received); + + data.concat("/n"); + if (fobj.getConnect_flag() == 1) { + + + if (data.contains(",")) { + try { + Thread.sleep(Long.parseLong("4000")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + + String[] namesList = data.split(","); + try { + Thread.sleep(Long.parseLong("4000")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + + Double d5 = new Double(namesList[3]); + + ddash_427 = (float) (Float.parseFloat(String.valueOf((d5))) - 427.00); + ddash_555 = (float) (Float.parseFloat(String.valueOf((d5))) - 555.00); + + + BigDecimal d3 = new BigDecimal(namesList[2]); + BigDecimal d1 = new BigDecimal(namesList[1]); + + Double d8 = (Double) (-d3.doubleValue() + Math.sqrt(Math.pow(d3.doubleValue(), 2) - 4 * (d1).doubleValue() * ddash_427)); + d8 = d8 / (2 * d1.doubleValue()); + BigDecimal d11 = new BigDecimal(d8); + wl_427 = (int) Math.round(d8); + obj.setX_427(String.valueOf(wl_427)); + Log.e("Value x 427 ", String.valueOf(wl_427)); + Log.e("Value x 427 obj ", String.valueOf(obj.getX_427())); + + + Double d9 = (Double) (-d3.doubleValue() + Math.sqrt(Math.pow(d3.doubleValue(), 2) - 4 * (d1).doubleValue() * ddash_555)); + d9 = d9 / (2 * d1.doubleValue()); + BigDecimal d12 = new BigDecimal(d9); + wl_555 = (int) Math.round(d9); + Log.e("Value x 555 ", String.valueOf(wl_555)); + obj.setX_555(String.valueOf(wl_555)); + Log.e("Value x 555 obj ", String.valueOf(obj.getX_555())); + + + } + + } + + if (fobj.getRun_flag()==1) + { + fobj.setBaseline_flag(0); + if (data.contains(String.valueOf(obj.getX_427()))) { + Log.e("final 427 value yes", String.valueOf(data)); + String ds2 = data.substring(data.lastIndexOf(":") + 1).trim(); + f_427 = ds2; + + ds2=ds2.replace("OK [0]",""); + + + obj.setF_427(ds2); + Log.e("Value of initial 427", String.valueOf(f_427)); + + } + if (data.contains(String.valueOf(obj.getX_555()))) { + Log.e("i 555 value yes", String.valueOf(data)); + + String ds2 = data.substring(data.lastIndexOf(":") + 1).trim(); + f_555 = ds2; + ds2=ds2.replace("OK [0]",""); + obj.setF_555(ds2); + + Log.e("Value of final 555", String.valueOf(f_555)); + + } + + + + } + if (fobj.getBaseline_flag() == 1) { + fobj.setRun_flag(0); + if (data.contains(String.valueOf(obj.getX_427()))) { + Log.e("i 427 value yes", String.valueOf(data)); + + String ds1 = data.substring(data.lastIndexOf(":") + 1).trim(); + i_427 = ds1; + try { + Thread.sleep(Long.parseLong("1000")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + ds1=ds1.replace("OK [0]",""); + try { + Thread.sleep(Long.parseLong("1000")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + Log.e("this is i value",ds1); + obj.setI_427(ds1); + Log.e("Value of initial 427", String.valueOf(i_427)); + + + } + if (data.contains(String.valueOf(obj.getX_555()))) { + Log.e("i 555 value ", String.valueOf(data)); + + String ds2 = data.substring(data.lastIndexOf(":") + 1).trim(); + i_555 = ds2; + try { + Thread.sleep(Long.parseLong("1000")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + ds2=ds2.replace("OK [0]",""); + try { + Thread.sleep(Long.parseLong("1000")); + } catch (InterruptedException e) { + e.printStackTrace(); + } + obj.setI_555(ds2); + + Log.e("Value of initial 555", String.valueOf(i_555)); + Log.e("Value of obj in 427", obj.getI_427()); + Log.e("Value of obj in 555", obj.getI_555()); + + } + + + } + + } + + } + } + } +} \ No newline at end of file diff --git a/app/src/main/java/shanmukha/in/sickle_cell/flag_pojo.java b/app/src/main/java/shanmukha/in/sickle_cell/flag_pojo.java new file mode 100644 index 0000000..cd27914 --- /dev/null +++ b/app/src/main/java/shanmukha/in/sickle_cell/flag_pojo.java @@ -0,0 +1,31 @@ +package shanmukha.in.sickle_cell; + +public class flag_pojo { + private int connect_flag; + private int baseline_flag; + private int run_flag; + + public int getConnect_flag() { + return connect_flag; + } + + public void setConnect_flag(int connect_flag) { + this.connect_flag = connect_flag; + } + + public int getBaseline_flag() { + return baseline_flag; + } + + public void setBaseline_flag(int baseline_flag) { + this.baseline_flag = baseline_flag; + } + + public int getRun_flag() { + return run_flag; + } + + public void setRun_flag(int run_flag) { + this.run_flag = run_flag; + } +} \ No newline at end of file diff --git a/app/src/main/java/shanmukha/in/sickle_cell/pojo.java b/app/src/main/java/shanmukha/in/sickle_cell/pojo.java new file mode 100644 index 0000000..57b120b --- /dev/null +++ b/app/src/main/java/shanmukha/in/sickle_cell/pojo.java @@ -0,0 +1,94 @@ +package shanmukha.in.sickle_cell; + +public class pojo { + private String x_427; + private String x_555; + private String i_427; + private String i_555; + private String f_427; + private String f_555; + private String a_555; + private String a_427; + private String ratio; + private String result; + + public String getA_555() { + return a_555; + } + + public void setA_555(String a_555) { + this.a_555 = a_555; + } + + public String getA_427() { + return a_427; + } + + public void setA_427(String a_427) { + this.a_427 = a_427; + } + + public String getRatio() { + return ratio; + } + + public void setRatio(String ratio) { + this.ratio = ratio; + } + + public String getResult() { + return result; + } + + public void setResult(String result) { + this.result = result; + } + + public String getX_427() { + return x_427; + } + + public void setX_427(String x_427) { + this.x_427 = x_427; + } + + public String getX_555() { + return x_555; + } + + public void setX_555(String x_555) { + this.x_555 = x_555; + } + + public String getI_427() { + return i_427; + } + + public void setI_427(String i_427) { + this.i_427 = i_427; + } + + public String getI_555() { + return i_555; + } + + public void setI_555(String i_555) { + this.i_555 = i_555; + } + + public String getF_427() { + return f_427; + } + + public void setF_427(String f_427) { + this.f_427 = f_427; + } + + public String getF_555() { + return f_555; + } + + public void setF_555(String f_555) { + this.f_555 = f_555; + } +} \ No newline at end of file diff --git a/app/src/main/res/drawable-v24/ic_launcher_foreground.xml b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml new file mode 100644 index 0000000..2b068d1 --- /dev/null +++ b/app/src/main/res/drawable-v24/ic_launcher_foreground.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/buttonshape.xml b/app/src/main/res/drawable/buttonshape.xml new file mode 100644 index 0000000..85525c7 --- /dev/null +++ b/app/src/main/res/drawable/buttonshape.xml @@ -0,0 +1,20 @@ + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_launcher_background.xml b/app/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..07d5da9 --- /dev/null +++ b/app/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/app/src/main/res/drawable/shanmukha_logo_small.png b/app/src/main/res/drawable/shanmukha_logo_small.png new file mode 100644 index 0000000000000000000000000000000000000000..14955c7fb4ad8206758705951ac30211f8b9db98 GIT binary patch literal 34428 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 literal 0 HcmV?d00001 diff --git a/app/src/main/res/drawable/text_back.xml b/app/src/main/res/drawable/text_back.xml new file mode 100644 index 0000000..b155c77 --- /dev/null +++ b/app/src/main/res/drawable/text_back.xml @@ -0,0 +1,7 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/activity_serial.xml b/app/src/main/res/layout/activity_serial.xml new file mode 100644 index 0000000..1abf917 --- /dev/null +++ b/app/src/main/res/layout/activity_serial.xml @@ -0,0 +1,104 @@ + + + + + + + + +