...
 
Commits (12)
*.iml
.gradle
/local.properties
/.idea/caches
/.idea/libraries
/.idea/modules.xml
/.idea/workspace.xml
/.idea/navEditor.xml
/.idea/assetWizardSettings.xml
.DS_Store
/build
/captures
.externalNativeBuild
fertilizeSorting
<component name="ProjectDictionaryState">
<dictionary name="peslerbe">
<words>
<w>wellplate</w>
</words>
</dictionary>
</component>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Encoding" addBOMForNewFiles="with NO BOM">
<file url="file://$PROJECT_DIR$/hardwarecontroller/src/main/java/ch/peslerbe/android/hardwarecontroller/serialUsb/UsbLayerInstance.java" charset="ISO-8859-1" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<compositeConfiguration>
<compositeBuild compositeDefinitionSource="SCRIPT" />
</compositeConfiguration>
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="resolveModulePerSourceSet" value="false" />
</GradleProjectSettings>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeSettings">
<configurations>
<configuration PROFILE_NAME="Debug" CONFIG_NAME="Debug" />
</configurations>
</component>
<component name="NullableNotNullManager">
<option name="myDefaultNullable" value="org.jetbrains.annotations.Nullable" />
<option name="myDefaultNotNull" value="android.support.annotation.NonNull" />
<option name="myNullables">
<value>
<list size="10">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.Nullable" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nullable" />
<item index="2" class="java.lang.String" itemvalue="javax.annotation.CheckForNull" />
<item index="3" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.Nullable" />
<item index="4" class="java.lang.String" itemvalue="android.support.annotation.Nullable" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.Nullable" />
<item index="6" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNullable" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.Nullable" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableDecl" />
<item index="9" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NullableType" />
</list>
</value>
</option>
<option name="myNotNulls">
<value>
<list size="9">
<item index="0" class="java.lang.String" itemvalue="org.jetbrains.annotations.NotNull" />
<item index="1" class="java.lang.String" itemvalue="javax.annotation.Nonnull" />
<item index="2" class="java.lang.String" itemvalue="edu.umd.cs.findbugs.annotations.NonNull" />
<item index="3" class="java.lang.String" itemvalue="android.support.annotation.NonNull" />
<item index="4" class="java.lang.String" itemvalue="androidx.annotation.NonNull" />
<item index="5" class="java.lang.String" itemvalue="androidx.annotation.RecentlyNonNull" />
<item index="6" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.qual.NonNull" />
<item index="7" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullDecl" />
<item index="8" class="java.lang.String" itemvalue="org.checkerframework.checker.nullness.compatqual.NonNullType" />
</list>
</value>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="RunConfigurationProducerService">
<option name="ignoredProducers">
<set>
<option value="org.jetbrains.plugins.gradle.execution.test.runner.AllInPackageGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestClassGradleConfigurationProducer" />
<option value="org.jetbrains.plugins.gradle.execution.test.runner.TestMethodGradleConfigurationProducer" />
</set>
</option>
</component>
</project>
\ No newline at end of file
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>
\ No newline at end of file
apply plugin: 'com.android.application'
ext {
play_services_version = "15.0.1"
support_version = "27.1.1"
}
android {
compileSdkVersion 27
defaultConfig {
applicationId "ch.bionomous.eggsorter.controller"
minSdkVersion 27
targetSdkVersion 27
versionCode 1
versionName "1.0"
dataBinding {
enabled = true
}
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
signingConfigs {
debug {
keyAlias 'android'
keyPassword 'eggSorter'
storeFile file('/Users/peslerbe/Bionomous/eggSorterSystemSignature/testkey.jks')
storePassword 'eggSorter'
}
release {
keyAlias 'android'
keyPassword 'eggSorter'
storeFile file('/Users/peslerbe/Bionomous/eggSorterSystemSignature/testkey.jks')
storePassword 'eggSorter'
}
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
buildToolsVersion = '29.0.1'
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
configurations.all {
resolutionStrategy.force "com.android.support:support-core-utils:27.0.0"
}
}
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar'])
implementation 'com.android.support:appcompat-v7:27.1.1'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.2'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.2'
implementation 'com.android.support.constraint:constraint-layout:1.1.3'
implementation 'com.android.support:support-v4:27.1.1'
implementation 'com.android.support:design:27.1.1'
implementation 'com.android.support:appcompat-v7:27.1.1'
implementation 'com.android.support:support-core-utils:27.1.1'
implementation 'jp.co.cyberagent.android:gpuimage:2.0.3'
implementation 'gov.nist.math:jama:1.0.3'
implementation "com.google.android.gms:play-services-auth:$play_services_version"
implementation "com.google.android.gms:play-services-drive:$play_services_version"
implementation 'com.squareup.okio:okio:1.14.0'
implementation 'com.android.support:support-compat:27.1.1'
implementation 'com.daimajia.easing:library:2.0@aar'
implementation 'com.daimajia.androidanimations:library:2.3@aar'
implementation project(':imageslinearpreview')
implementation project(':filesmanager')
implementation project(':generalutilities')
implementation project(':hardwarecontroller')
implementation project(':webservices')
implementation project(':camera')
implementation project(':homemenu')
implementation project(':parametersloader')
implementation project(':mlkit')
}
print("Generating the res file for dispenser...")
print(" <!-- Auto-generated interface start -->\n")
for i in range(0,12) :
print(" <LinearLayout\n" +
"android:layout_width=\"wrap_content\"\n" +
"android:layout_height=\"wrap_content\"\n" +
"android:orientation=\"horizontal\">\n")
print("<TextView\n" +
"android:layout_width=\"50dp\"\n" +
"android:layout_height=\"50dp\"\n" +
"android:textSize=\"25sp\"\n" +
"android:gravity=\"center\"\n" +
"android:text=\"" + str(12-i) + "\"" +
"/>")
for j in range(0,8) :
print("<ImageView\n" +
"android:layout_width=\"50dp\"\n"+
"android:layout_height=\"50dp\"\n" +
"android:padding=\"2dp\"\n" +
"android:background=\"@{wellplate.eggs[" + str((11-i)*8 + j) + "] == null ? @drawable/empty_well : wellplate.eggs[" + str((11-i)*8 + j) + "].category == `Fertilized` ? @drawable/fert_background_color : @drawable/unfert_background_color }\"\n" +
"android:onClick=\"@{(view) -> ImageEnlargeDialog.openNew(context, wellplate.eggs[" + str((11-i)*8 + j) + "].image, `" + chr(65+ j) + str(12-i) + "` + ` ` + wellplate.eggs[" + str((11-i)*8 + j) + "].category + ` `+ String.format(`%.2f`, wellplate.eggs[" + str((11-i)*8 + j) + "].certitudeFactor) + `%` )}\"\n"
"app:imageBitmap=\"@{wellplate.eggs[" + str((11-i)*8 + j) + "].image}\"\n/>")
print(" </LinearLayout>\n")
print(" <!-- Auto-generated interface end -->\n")
This diff is collapsed.
# 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
package ch.bionomous.eggsorter.controller;
import android.content.Context;
import android.support.test.InstrumentationRegistry;
import android.support.test.runner.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android state.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getTargetContext();
assertEquals("ch.bionomous.eggsorter.controller", appContext.getPackageName());
}
}
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="ch.bionomous.eggsorter.controller"
coreApp="true"
android:sharedUserId="android.uid.system">
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<uses-permission android:name="android.permission.CAMERA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-feature android:name="android.hardware.camera" />
<uses-feature android:name="android.hardware.usb.host" />
<application
android:allowBackup="true"
android:icon="@mipmap/controller_logo"
android:roundIcon="@mipmap/controller_logo_round"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/AppTheme" >
<meta-data
android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version" />
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.provider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths"/>
</provider>
<receiver
android:name="ch.bionomous.eggsorter.controller.StartStartupServiceAtBootReceiver"
android:enabled="true"
android:exported="false">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
</receiver>
<service
android:name="ch.peslerbe.android.hardwarecontroller.service.HardwareControllerService"
android:exported="false"/>
<service
android:name="ch.peslerbe.android.hardwarehandler.HardwareHandlerService"
android:exported="true" />
<activity android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden" android:name="ch.bionomous.eggsorter.controller.Launcher">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.MAIN_APP_1" />
</intent-filter>
</activity>
<activity android:screenOrientation="landscape" android:configChanges="orientation|keyboardHidden" android:name="ch.peslerbe.android.generalutilities.AppManagment$ErrorActivity">
</activity>
</application>
</manifest>
package ch.bionomous.eggsorter.controller;
public interface FragmentStateListener {
enum State{Valid, goBack};
void notify(State state);
}
/**
* Launcher class
*
* This class is the base of the Project and is the reference if app context / activity are required
*/
package ch.bionomous.eggsorter.controller;
import android.app.Activity;
import android.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.databinding.DataBindingUtil;
import android.os.Bundle;
import android.os.PersistableBundle;
import android.support.annotation.Nullable;
import android.support.v4.app.FragmentManager;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.widget.Toast;
import ch.bionomous.eggsorter.controller.automationalgorithms.Automation;
import ch.bionomous.eggsorter.controller.control.WaterLevel;
import ch.bionomous.eggsorter.controller.global.GlobalSettings;
import ch.bionomous.eggsorter.controller.hardware.Hw;
import ch.bionomous.eggsorter.controller.processing.AlgorithmsManager;
import ch.bionomous.eggsorter.controller.views.HomeMenuImpl;
import ch.peslerbe.android.hardwarecontroller.DistantHardwareManager;
public class Launcher extends AppCompatActivity {
public static final String TAG = Launcher.class.getSimpleName();
private static AppCompatActivity activity;
public static Context getContext() {
return activity;
}
public static AppCompatActivity getMainActivity() {
return activity;
}
boolean waterWasRunning = false;
@Override
protected void onStop() {
Automation.getInstance().stopRunning();
waterWasRunning = WaterLevel.getHandler().correctionIsRunning.get();
if(Hw.get().camera != null) Hw.get().camera.onPause();
DistantHardwareManager.getService().onRelease();
super.onStop();
}
boolean hwIsInitiated = false;
@Override
protected void onStart() {
super.onStart();
if(Hw.get() != null && hwIsInitiated && DistantHardwareManager.getService() != null) {
DistantHardwareManager.getService().onLock();
Hw.get().camera.onResume();
if(waterWasRunning) WaterLevel.getHandler().start();
}
}
@Override
public void onBackPressed() {
FragmentManager fm = getSupportFragmentManager();
if (fm.isStateSaved() || !fm.popBackStackImmediate()) {
}
}
AppCompatActivity splashScreen = new AppCompatActivity(){
@Override
public void onCreate(@Nullable Bundle savedInstanceState, @Nullable PersistableBundle persistentState) {
super.onCreate(savedInstanceState, persistentState);
DataBindingUtil.setContentView(activity, R.layout.splashscreen);
}
};
private boolean isMyServiceRunning(Class<?> serviceClass) {
ActivityManager manager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE);
for (ActivityManager.RunningServiceInfo service : manager.getRunningServices(Integer.MAX_VALUE)) {
if (serviceClass.getName().equals(service.service.getClassName())) {
Log.i ("isMyServiceRunning?", true+"");
return true;
}
}
Log.i ("isMyServiceRunning?", false+"");
return false;
}
@Override
protected void onDestroy() {
super.onDestroy();
}
/**
* This function is called when the app is loaded
* Please refer to the app lifecycle documentation for more information
*
* @param savedInstanceState
*/
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
activity = this;
Thread.setDefaultUncaughtExceptionHandler(new UnCaughtException(this));
Hw.init(getContext());
new Thread(AlgorithmsManager::getInstance).start();
Automation.init(getContext());
new Thread(() -> {
Hw.get().connect(this::onFinishLoading);
hwIsInitiated = true;
}).start();
}
void onFinishLoading(){
DataBindingUtil.setContentView(activity, R.layout.main_container);
if(GlobalSettings.debug.isEnabled()) Toast.makeText(getContext(), "Be carefull, some debug functionalities have been enabled", Toast.LENGTH_SHORT).show();
getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, new HomeMenuImpl()).commit();
}
}
package ch.bionomous.eggsorter.controller;
import ch.peslerbe.android.generalutilities.Egg;
import ch.peslerbe.android.Parameters;
import ch.peslerbe.android.generalutilities.callbacks.SimpleCallback;
public interface OutputEndpoint{
enum CleaningMode_e{Full, Rapid}
Parameters getParameters();
void outputEgg(Egg egg, SimpleCallback continueProcess);
default void onAutomationStart(){};
void clean(CleaningMode_e mode);
}
/*******
* File : StartStartupServiceAtBootReceiver.java
* Project : LSRO EggSorter
*
* Description :
*
* Version :
* Validation :
* Comments :
*
* Written by Nicolas Peslerbe <development@peslerbe.com>, August 2018
*
* Unauthorized copying and/or distribution of this file, via any medium is strictly prohibited
* Proprietary and confidential
*/
package ch.bionomous.eggsorter.controller;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
public class StartStartupServiceAtBootReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
Intent startIntent = new Intent(context, Launcher.class);
startIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(startIntent);
}
}
}
\ No newline at end of file
package ch.bionomous.eggsorter.controller;
import java.io.File;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.io.Writer;
import java.lang.Thread.UncaughtExceptionHandler;
import java.util.Date;
import java.util.Locale;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.hardware.handler.HardwareManager;
import android.os.Environment;
import android.os.Looper;
import android.os.StatFs;
import android.util.Log;
import ch.peslerbe.android.generalutilities.AppManagment;
import ch.peslerbe.android.hardwarecontroller.DistantHardwareManager;
public class UnCaughtException implements UncaughtExceptionHandler {
private Context context;
private static Context context1;
public UnCaughtException(Context ctx) {
context = ctx;
context1 = ctx;
}
private StatFs getStatFs() {
File path = Environment.getDataDirectory();
return new StatFs(path.getPath());
}
private long getAvailableInternalMemorySize(StatFs stat) {
long blockSize = stat.getBlockSize();
long availableBlocks = stat.getAvailableBlocks();
return availableBlocks * blockSize;
}
private long getTotalInternalMemorySize(StatFs stat) {
long blockSize = stat.getBlockSize();
long totalBlocks = stat.getBlockCount();
return totalBlocks * blockSize;
}
private void addInformation(StringBuilder message) {
message.append("Locale: ").append(Locale.getDefault()).append('\n');
try {
PackageManager pm = context.getPackageManager();
PackageInfo pi;
pi = pm.getPackageInfo(context.getPackageName(), 0);
message.append("Version: ").append(pi.versionName).append('\n');
message.append("Package: ").append(pi.packageName).append('\n');
} catch (Exception e) {
Log.e("CustomExceptionHandler", "Error", e);
message.append("Could not get Version information for ").append(
context.getPackageName());
}
message.append("Phone Model ").append(android.os.Build.MODEL)
.append('\n');
message.append("Android Version : ")
.append(android.os.Build.VERSION.RELEASE).append('\n');
message.append("Board: ").append(android.os.Build.BOARD).append('\n');
message.append("Brand: ").append(android.os.Build.BRAND).append('\n');
message.append("State: ").append(android.os.Build.DEVICE).append('\n');
message.append("Host: ").append(android.os.Build.HOST).append('\n');
message.append("ID: ").append(android.os.Build.ID).append('\n');
message.append("Model: ").append(android.os.Build.MODEL).append('\n');
message.append("Product: ").append(android.os.Build.PRODUCT)
.append('\n');
message.append("Type: ").append(android.os.Build.TYPE).append('\n');
StatFs stat = getStatFs();
message.append("Total Internal memory: ")
.append(getTotalInternalMemorySize(stat)).append('\n');
message.append("Available Internal memory: ")
.append(getAvailableInternalMemorySize(stat)).append('\n');
}
public void uncaughtException(Thread t, Throwable e) {
try {
DistantHardwareManager.getService().onRelease();
StringBuilder report = new StringBuilder();
Date curDate = new Date();
report.append("Error Report collected on : ")
.append(curDate.toString()).append('\n').append('\n');
report.append("Informations :").append('\n');
addInformation(report);
report.append('\n').append('\n');
report.append("Stack:\n");
final Writer result = new StringWriter();
final PrintWriter printWriter = new PrintWriter(result);
e.printStackTrace(printWriter);
report.append(result.toString());
printWriter.close();
report.append('\n');
report.append("**** End of current Report ***");
Log.e(UnCaughtException.class.getName(),
"Error while sendErrorMail" + report);
sendErrorMail(report);
} catch (Throwable ignore) {
Log.e(UnCaughtException.class.getName(),
"Error while sending error e-mail", ignore);
}
}
public void sendErrorMail(final StringBuilder errorContent) {
final AlertDialog.Builder builder = new AlertDialog.Builder(context);
new Thread() {
@Override
public void run() {
Looper.prepare();
builder.setTitle("Sorry...!");
builder.create();
/*builder.setNegativeButton("Cancel",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
System.exit(0);
}
});*/
/*builder.setPositiveButton("Report",
new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog,
int which) {
/*Intent sendIntent = new Intent(
Intent.ACTION_SEND);
String subject = "Your App crashed! Fix it!";
StringBuilder body = new StringBuilder("Yoddle");
body.append('\n').append('\n');
body.append(errorContent).append('\n')
.append('\n');
// sendIntent.setType("text/plain");
sendIntent.setType("message/rfc822");
sendIntent.putExtra(Intent.EXTRA_EMAIL,
new String[] { "coderzheaven@gmail.com" });
sendIntent.putExtra(Intent.EXTRA_TEXT,
body.toString());
sendIntent.putExtra(Intent.EXTRA_SUBJECT,
subject);
sendIntent.setType("message/rfc822");
context1.startActivity(sendIntent);
System.exit(0);
}
});
*/
builder.setMessage("Oops,Your application has crashed");
builder.show();
AppManagment.closeApp(context);
Looper.loop();
}
}.start();
}
}
\ No newline at end of file
/*******
* File : Automation.java
* Project : LSRO EggSorter by Frank Bonnet
*
* Description :
*
* Version :
* Validation :
* Comments :
*
* Written by Nicolas Peslerbe <development@peslerbe.com>, August 2018
*
* Unauthorized copying and/or distribution of this file, via any medium is strictly prohibited
* Proprietary and confidential
*/
package ch.bionomous.eggsorter.controller.automationalgorithms;
import android.content.Context;
import android.content.res.Resources;
import android.databinding.Observable;
import android.databinding.ObservableBoolean;
import android.util.Log;
import java.util.ArrayList;
import java.util.List;
import ch.bionomous.eggsorter.controller.R;
import ch.bionomous.eggsorter.controller.hardware.Hw;
import ch.peslerbe.android.hardwarecontroller.interfaces.componentsimplementations.Pump;
import ch.peslerbe.android.hardwarecontroller.interfaces.topsystems.Sorter;
public class Automation{
final String TAG = Automation.class.getSimpleName();
public enum Processes{RegularCaptureUnique, RegularCaptureList, AutoSorting, EmptyingWheel, SingleSorting};
private boolean[] readyFor = new boolean[Processes.values().length];
private ObservableBoolean[] runningFor = new ObservableBoolean[Processes.values().length];
private static Automation automation;
public static Automation getInstance(){
return automation;
}
public static void init(Context ctx){
if(automation == null) automation = new Automation(ctx);
}
public ObservableBoolean isRunning = new ObservableBoolean(false);
List<AutomationAlgorithm> persistentAlgorithm = new ArrayList<>();
public synchronized void tryStart(AutomationAlgorithm algo){
persistentAlgorithm.add(algo);
if(isRunning.get()) return;
isRunning.set(true);
algo.isRunning.addOnPropertyChangedCallback(new Observable.OnPropertyChangedCallback() {
@Override
public void onPropertyChanged(Observable sender, int propertyId) {
isRunning.set(algo.isRunning.get());
}
});
algo.start();
}
public void stop(AutomationAlgorithm algo){
algo.stop();
}
public final EggSortingAutom sortingAlgo;
public final WheelEmptyingAutom wheelEmptyingAutom;
private Automation(Context context){
Resources res = context.getResources();
this.sortingAlgo = new EggSortingAutom(res.getStringArray(R.array.sorting_texts));
this.wheelEmptyingAutom = new WheelEmptyingAutom();
}
public void stopRunning(){
for(AutomationAlgorithm algorithmInterface : persistentAlgorithm){
algorithmInterface.stop();
}
}
public boolean isRunning(){
for(ObservableBoolean b : runningFor){
if(b.get()) return true;
}
return false;
}
}
package ch.bionomous.eggsorter.controller.automationalgorithms;
import android.databinding.ObservableBoolean;
import ch.peslerbe.android.generalutilities.callbacks.SimpleCallback;
public abstract class AutomationAlgorithm {
public ObservableBoolean isRunning = new ObservableBoolean(false);
abstract void start();
void stop(){stop(null);}
abstract void stop(SimpleCallback cb);
abstract void stop_sync();
}
package ch.bionomous.eggsorter.controller.automationalgorithms;
import ch.peslerbe.android.generalutilities.callbacks.SimpleCallback;
public class RegularEggCaptureAutom extends AutomationAlgorithm {
@Override
public void start() {
}
@Override
void stop(SimpleCallback cb) {
}
@Override
public void stop_sync() {
}
}
package ch.bionomous.eggsorter.controller.automationalgorithms;
import android.graphics.Bitmap;
import android.util.Log;
import java.util.concurrent.Semaphore;
import ch.bionomous.eggsorter.controller.control.RoutinesAutomation;
import ch.bionomous.eggsorter.controller.global.GlobalSettings;
import ch.bionomous.eggsorter.controller.hardware.Hw;
import ch.bionomous.eggsorter.controller.processing.utilities.EggSlot;
import ch.bionomous.eggsorter.filesmanager.FilesManager;
import ch.peslerbe.android.generalutilities.callbacks.SimpleCallback;
import ch.peslerbe.android.hardwarecontroller.interfaces.componentsimplementations.Pump;
import ch.peslerbe.android.hardwarecontroller.interfaces.topsystems.Sorter;
public class WheelEmptyingAutom extends AutomationAlgorithm {
public class Controller{
public void start(SimpleCallback cb){
if(cb != null) processTerminated = cb;
Automation.getInstance().tryStart(WheelEmptyingAutom.this);
}
public void stop(SimpleCallback cb){
if(cb != null) processTerminated = cb;
Automation.getInstance().stop(WheelEmptyingAutom.this);
}
}
public Controller controller = new Controller();
@Override
synchronized void start() {
isRunning.set(true);
new Thread(automation).start();
}
@Override
synchronized void stop(SimpleCallback cb) {
if(cb != null) processTerminated = cb;
isRunning.set(false);
}
@Override
void stop_sync() {
if(isRunning.get()){
Semaphore sem = new Semaphore(0);
isRunning.set(false);
stop(() -> {
synchronized (WheelEmptyingAutom.this){
sem.release();
}
});
try {
sem.acquire(1);
} catch (InterruptedException e){}
}
}
private SimpleCallback processTerminated;
Runnable automation = new Runnable() {
@Override
public void run() {
Sorter sorter = Hw.get().sorter;
Pump centralPump = sorter.pump.central;
int numberOfEmptySlots = 0;
while(isRunning.get() && numberOfEmptySlots<40){
centralPump.set(Pump.State.Reverse);
Bitmap image = RoutinesAutomation.goToNextEggAndGetSlotPicture();
EggSlot slot = new EggSlot(image, FilesManager.getIntValueInFile("Algos/SortAlgo0/default" + "/bestThresold.txt"));
if(slot.getType() == EggSlot.ContentType.EGG){
numberOfEmptySlots = 0;
}else{
numberOfEmptySlots++;
}
centralPump.set(Pump.State.Off);
Hw.get().state.outs.get(1).outputEgg(null, null);
}
isRunning.set(false);
if(processTerminated != null){
processTerminated.notifyOk();
processTerminated = null;
}
}
};
}
package ch.bionomous.eggsorter.controller.control;
import android.graphics.Bitmap;
import android.util.Log;
import java.util.concurrent.Semaphore;
import ch.bionomous.eggsorter.controller.OutputEndpoint;
import ch.bionomous.eggsorter.controller.devicestate.EggsOutputs;
import ch.bionomous.eggsorter.controller.functionalities.Sort;
import ch.bionomous.eggsorter.controller.global.AppFilesManager;
import ch.bionomous.eggsorter.controller.global.GlobalSettings;
import ch.bionomous.eggsorter.controller.hardware.Hw;
import ch.bionomous.eggsorter.controller.processing.utilities.EggSlot;
import ch.bionomous.eggsorter.filesmanager.FilesManager;
import ch.peslerbe.android.hardwarecontroller.interfaces.componentsimplementations.StepperMotor;
import ch.peslerbe.android.hardwarecontroller.interfaces.nativeinterfaces.SteppermotorNI;
import ch.peslerbe.android.hardwarecontroller.interfaces.topsystems.Sorter;
public class RoutinesAutomation {
private static final String TAG = RoutinesAutomation.class.getSimpleName();
/*
* Method to get recentering shift value or perform recentering if not critical
*/
private static int numberOfJumped = 0;
enum RecenterType{Critical, NotCritical}
static int recenter(Bitmap image, RecenterType recenterType){
if(numberOfJumped > 4 ){
Log.e(TAG, "Slot not found");
}
final int STEP_FOR_IMAGE = 190;
final int STEP_FOR_IMAGE_2 = 200;
int requiredStartingPoint = image.getWidth()*28/100;
int requiredEndingPoint = image.getWidth()*73/100;
int startingPoint = -1;
int endingPoint = 3000;
int j = image.getHeight()/2;
int endPointCount = 0;
for (int i = 0; i < image.getWidth(); i += 30) {
int color = image.getPixel(i, j);
int value = (((color >> 16) & 0xff) + ((color >> 8) & 0xff) + ((color) & 0xff))/3;
if(value > 30 && startingPoint == -1){
startingPoint = i;
}
if(value < 30 && startingPoint != -1){
endPointCount++;
if(endingPoint == 3000){
endingPoint = i;
}
if(endPointCount > 3){
break;
}
} else{
endingPoint = 3000;
endPointCount = 0;
}
}
if(startingPoint == -1 || startingPoint > image.getWidth()*9/10){
numberOfJumped+=1;
if(recenterType == RecenterType.Critical) return 0;
Hw.get().sorter.motor.sychronousMove( StepperMotor.Direction.Anticlockwise, STEP_FOR_IMAGE/2);
}
else if(endingPoint <= requiredEndingPoint-200){
if(recenterType == RecenterType.Critical && Math.abs(startingPoint - endingPoint) < 500 ){
numberOfJumped+=1;
return 0;
}
Hw.get().sorter.motor.sychronousMove(StepperMotor.Direction.Anticlockwise, (requiredEndingPoint-endingPoint)*STEP_FOR_IMAGE/image.getWidth());
numberOfJumped = 0;
}
else if(endingPoint > requiredEndingPoint-200 && endingPoint < requiredEndingPoint + 250) {
if(recenterType == RecenterType.Critical && Math.abs(startingPoint - endingPoint) < 500 ){
numberOfJumped+=1;
return 0;
}
numberOfJumped = 0;
return (requiredEndingPoint-endingPoint)*STEP_FOR_IMAGE/image.getWidth();
}
else if(endingPoint >= requiredEndingPoint + 250) {
numberOfJumped+=1;
if(recenterType == RecenterType.Critical) return 0;
Hw.get().sorter.motor.sychronousMove(StepperMotor.Direction.Anticlockwise, Sorter.NUMBER_OF_STEPS_FOR_NEXT-(startingPoint-requiredStartingPoint)*STEP_FOR_IMAGE_2/image.getWidth());
}
return 1000;
}
/*
* Method to go to next egg in sorter
*/
private static int adjustementSteps = 1000;
public static Bitmap goToNextEggAndGetSlotPicture(){
Hw.get().sorter.motor.sychronousMove( StepperMotor.Direction.Anticlockwise,
Sorter.NUMBER_OF_STEPS_FOR_NEXT +
(adjustementSteps != 1000 ? adjustementSteps : 0 ));
try {
Thread.sleep(100);
} catch(Exception e){
Log.e(TAG, "Unexpected sleep interruption :" + e.toString());
}
Bitmap image;
if(!GlobalSettings.debug.falseEggsImages){
int step = 0;
do {
image = Hw.get().camera.takePicture();
step++;
adjustementSteps = recenter(image, RecenterType.Critical);
} while(adjustementSteps == 1000 && step < 4);
} else{
image = AppFilesManager.loadFakeEggImage();
}
return image;
}
/*
* Method to suck egg for a small moment into the wheel
*/
private static final int ratioForEggSucking = 750;
private static final int timeForEggSucking = 500;
public static void suckEggs(){
Hw.get().sorter.pump.central.setRatio(ratioForEggSucking);
try {
Thread.sleep(timeForEggSucking);
}catch (Exception e){
Log.e(TAG, "Unexpected sleep interruption :" + e.toString());
}
Hw.get().sorter.pump.central.setRatio(Sorter.PUMP_CENTRAL_RATIO);
}
public static void cleanWell(final OutputEndpoint.CleaningMode_e mode){
int registered = 0;
Semaphore sem = new Semaphore(0);
Hw.get().sorter.state.isReady = false;
if(Hw.get().dispenser != null) Hw.get().dispenser.state.isReady = false;
for(EggsOutputs.Element el : EggsOutputs.get().getList()){
new Thread(() -> {
el.clean(mode);
sem.release();
}).start();
registered++;
}
Hw.get().sorter.motor.sychronousMove(SteppermotorNI.Direction.Anticlockwise, 40000);
// Turn the well here
try {
sem.acquire(registered);
} catch (InterruptedException ignored){}
}
public static void emptyWell(){
}
}
package ch.bionomous.eggsorter.controller.control;
import android.graphics.Bitmap;
import android.util.Log;
import ch.bionomous.eggsorter.controller.global.GlobalSettings;
import ch.bionomous.eggsorter.controller.hardware.Hw;
public class RoutinesTest {
private static final String TAG = RoutinesTest.class.getSimpleName();
public static Boolean ledOn(){
Bitmap image = Hw.get().camera.takePicture();
Log.d(TAG, "Returns from picture");
int numberOfValues = 0;
int totalValue = 0;
for(int i =0; i < image.getHeight(); i+=50){
for(int j = 0; j < image.getWidth(); j+=50){
int color = image.getPixel(j,i);
totalValue = ((color >> 16) & 0xff) + ((color >> 8) & 0xff) + ((color ) & 0xff);
if(totalValue > GlobalSettings.THRESHOLD_LED_ON){
numberOfValues++;
}
}
}
Log.d(TAG, "Returns from ledOn");
return (numberOfValues > 40) ;
}
public static Boolean lensInPlace(){
Bitmap image = Hw.get().camera.takePicture();
int numberOfValues = 0;
int totalValue = 0;
for(int i =0; i < 100; i+=20){
for(int j =0; j < image.getWidth(); j+=50){
numberOfValues+=1;
int color = image.getPixel(j,i);
totalValue += (((color >> 16) & 0xff) +
((color >> 8) & 0xff) +
((color ) & 0xff))/3;
}
}
if(totalValue / numberOfValues < GlobalSettings.THRESHOLD_WHEEL_OPACITY) return true;
else return false;
}
public static Boolean adjustmentWheelPosition(){
Bitmap image;
do {
image = Hw.get().camera.takePicture();
}while(RoutinesAutomation.recenter(image, RoutinesAutomation.RecenterType.NotCritical) == 1000);
return true;
}
// TODO - Routine for auto exposure adjustment, does not work
/*public static Integer getPerfectExposure(){
int numberOfValues = 0;
int totalValue = 0;
int exposureValue = 50;
do {
exposureValue += 6;
CamerasManager.getInstance().setExposure(exposureValue);
try {
Thread.sleep(200);
} catch (Exception e) {
}
CamerasManager.getInstance().livePictures();
Bitmap image = CamerasManager.getInstance().frontCameraLastImage.get();
int[] pixels = new int[image.getWidth() * image.getHeight()];
image.getPixels(pixels, 0, image.getWidth(), 0, 0, image.getWidth(), image.getHeight());
numberOfValues = 0;
totalValue = 0;
for (int i = 0; i < pixels.length; i += 1000) {
int color = pixels[i];
totalValue += (((color >> 16) & 0xff) + ((color >> 8) & 0xff) + ((color) & 0xff))/3;
numberOfValues++;
}
} while(totalValue / numberOfValues < GlobalSettings.thresholdCalibration );
return exposureValue;
}*/
}
\ No newline at end of file
package ch.bionomous.eggsorter.controller.control;
import android.databinding.ObservableBoolean;
import android.databinding.ObservableField;
import android.databinding.ObservableInt;
import android.util.Log;
import java.util.Timer;
import java.util.TimerTask;
import ch.bionomous.eggsorter.controller.OutputEndpoint;
import ch.bionomous.eggsorter.controller.devicestate.EggsOutputs;
import ch.bionomous.eggsorter.controller.global.GlobalSettings;
import ch.bionomous.eggsorter.controller.hardware.Adc;
import ch.bionomous.eggsorter.controller.hardware.Hw;
import ch.peslerbe.android.generalutilities.ActivityComponent;
import ch.peslerbe.android.generalutilities.callbacks.SimpleCallback;
import ch.peslerbe.android.hardwarecontroller.interfaces.componentsimplementations.CounterPump;
import ch.peslerbe.android.hardwarecontroller.interfaces.componentsimplementations.Pump;
public class WaterLevel implements ActivityComponent {
private static final String TAG = WaterLevel.class.getSimpleName();
private final ObservableInt waterCorrectLevel = GlobalSettings.variables.waterCorrectLevel;
private final ObservableInt waterCriticalMin = GlobalSettings.variables.waterCriticalMin;
private final ObservableInt waterCriticalMax = GlobalSettings.variables.waterCriticalMax;
private final ObservableInt waterPumpNormalRatio = GlobalSettings.variables.centralPumpNormalRatio;
private int waterProportionalCorCoef = GlobalSettings.WATER_PROPORTIONAL_COR_COEF;
private final int WATER_SHIFT_TOLERANCE = GlobalSettings.WATER_SHIFT_TOLERANCE;
CounterPump centralPump = Hw.get().sorter.pump.central;
Pump waterPump = Hw.get().sorter.pump.water;
/*
* Class handler stuff
*/
private WaterLevel(){
Timer levelMeasurementHandler = new Timer();
levelMeasurementHandler.scheduleAtFixedRate(sensorDataAcquisition, 0, 800);
}
private static WaterLevel handler = new WaterLevel();
public static WaterLevel getHandler(){
return handler;
}
/*
* Activity stop
*/
boolean wasRunning = false;
@Override
public void onPause() {
if(correctionIsRunning.get()){
wasRunning = true;
stop();
}
}
@Override
public void onResume() {
if(wasRunning)
start();
}
/*
* Loop water measurement thread
*/
public Integer getCurrentLevel(){
if(GlobalSettings.debug.correctWaterLevel) return waterCorrectLevel.get();
return Adc.getValue(GlobalSettings.WATER_LEVEL_SENSOR_PIN);
}
public ObservableInt actualLevel = new ObservableInt();
private int nbIncorrect = 0;
private void acquireAndCheckValue(){
int value = getCurrentLevel();
Log.d(TAG, "Actual: " + value);