/*
CanZE
Take a closer look at your ZE car
Copyright (C) 2015 - The CanZE Team
http://canze.fisch.lu
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or any
later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package lu.fisch.canze.activities;
import android.annotation.SuppressLint;
import android.app.AlertDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.EditText;
import android.widget.ProgressBar;
import android.widget.TextView;
import java.util.Locale;
import lu.fisch.canze.R;
import lu.fisch.canze.actors.Field;
import lu.fisch.canze.interfaces.DebugListener;
import lu.fisch.canze.interfaces.FieldListener;
import lu.fisch.canze.activities.MainActivity;
public class DrivingActivity extends CanzeActivity implements FieldListener, DebugListener {
// for ISO-TP optimization to work, group all identical CAN ID's together when calling addListener
// free data
public static final String SID_Consumption = "1fd.48"; //EVC
public static final String SID_Pedal = "186.40"; //EVC
public static final String SID_MeanEffectiveTorque = "186.16"; //EVC
public static final String SID_Coasting_Torque = "18a.27"; //10ms Friction torque means EMULATED friction, what we'd call coasting
public static final String SID_RealSpeed = "5d7.0"; //ESC-ABS
public static final String SID_SoC = "654.25"; //EVC
public static final String SID_RangeEstimate = "654.42"; //EVC
public static final String SID_DriverBrakeWheel_Torque_Request = "130.44"; //UBP braking wheel torque the driver wants
public static final String SID_ElecBrakeWheelsTorqueApplied = "1f8.28"; //UBP 10ms
public static final String SID_TotalPotentialResistiveWheelsTorque = "1f8.16"; //UBP 10ms
// ISO-TP data
public static final String SID_MaxCharge = "7bb.6101.336";
public static final String SID_EVC_Odometer = "7ec.622006.24"; // (EVC)
private int odo = 0;
private int destOdo = 0; // have to init from save file
private double realSpeed = 0;
private double driverBrakeWheel_Torque_Request = 0;
private double coasting_Torque = 0;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_driving);
final TextView distkmToDest = (TextView) findViewById(R.id.LabelDistToDest);
distkmToDest.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
setDistanceToDestination();
}
});
if (MainActivity.milesMode) {
TextView tv;
tv = (TextView) findViewById(R.id.textSpeedUnit);
tv.setText(MainActivity.getStringSingle(R.string.unit_SpeedMi));
tv = (TextView) findViewById(R.id.textConsumptionUnit);
tv.setText(MainActivity.getStringSingle(R.string.unit_ConsumptionMi));
}
}
protected void initListeners() {
getDestOdo();
// Make sure to add ISO-TP listeners grouped by ID
MainActivity.getInstance().setDebugListener(this);
addField(SID_Consumption, 0);
addField(SID_Pedal, 0);
addField(SID_MeanEffectiveTorque, 0);
addField(SID_DriverBrakeWheel_Torque_Request, 0);
addField(SID_ElecBrakeWheelsTorqueApplied, 0);
addField(SID_Coasting_Torque, 0);
addField(SID_TotalPotentialResistiveWheelsTorque, 7200);
addField(SID_RealSpeed, 0);
addField(SID_SoC, 7200);
addField(SID_RangeEstimate, 7200);
addField(SID_EVC_Odometer, 6000);
}
void setDistanceToDestination () {
// don't react if we do not have a live odo yet
if (odo == 0) return;
final Context context = DrivingActivity.this;
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
LayoutInflater inflater = getLayoutInflater();
// we allow this SuppressLint as this is a pop up Dialog
@SuppressLint("InflateParams")
final View distToDestView = inflater.inflate(R.layout.alert_dist_to_dest, null);
// set dialog message
alertDialogBuilder
.setView(distToDestView)
.setTitle(R.string.prompt_Distance)
.setMessage(MainActivity.getStringSingle(R.string.prompt_SetDistance))
.setCancelable(true)
.setPositiveButton(R.string.default_Ok, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT,0);
EditText dialogDistToDest = (EditText) distToDestView.findViewById(R.id.dialog_dist_to_dest);
if (dialogDistToDest != null) {
saveDestOdo(odo + Integer.parseInt(dialogDistToDest.getText().toString()));
}
dialog.cancel();
}
})
.setNeutralButton(R.string.button_Double, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT,0);
EditText dialogDistToDest = (EditText) distToDestView.findViewById(R.id.dialog_dist_to_dest);
if (dialogDistToDest != null) {
saveDestOdo(odo + 2 * Integer.parseInt(dialogDistToDest.getText().toString()));
}
dialog.cancel();
}
})
.setNegativeButton(R.string.default_Cancel, new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_IMPLICIT,0);
dialog.cancel();
}
});
// create alert dialog
AlertDialog alertDialog = alertDialogBuilder.create();
InputMethodManager imm = (InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE);
imm.toggleSoftInput(InputMethodManager.SHOW_FORCED,0);
// show it
alertDialog.show();
}
private void saveDestOdo (int d) {
SharedPreferences settings = getSharedPreferences(MainActivity.PREFERENCES_FILE, 0);
SharedPreferences.Editor editor = settings.edit();
editor.putInt("destOdo", d);
editor.apply();
destOdo = d;
Field field = MainActivity.fields.getBySID(SID_RangeEstimate);
int distInBat = (int) field.getValue();
if (destOdo > odo) {
setDestToDest("" + (destOdo - odo), "" + (distInBat - destOdo + odo));
} else {
setDestToDest("0", "0");
}
}
private void getDestOdo () {
SharedPreferences settings = getSharedPreferences(MainActivity.PREFERENCES_FILE, 0);
destOdo = settings.getInt("destOdo", 0);
// get last persistent odo to calc
Field field = MainActivity.fields.getBySID(SID_EVC_Odometer);
odo = (int)field.getValue();
field = MainActivity.fields.getBySID(SID_RangeEstimate);
int distInBat = (int) field.getValue();
if (destOdo > odo) {
setDestToDest("" + (destOdo - odo), "" + (distInBat - destOdo + odo));
} else {
setDestToDest("0", "0");
}
}
private void setDestToDest(String distance1, String distance2) {
TextView tv;
tv = (TextView) findViewById(R.id.textDistToDest);
tv.setText(distance1);
tv = (TextView) findViewById(R.id.textDistAVailAtDest);
tv.setText(distance2);
}
// This is the event fired as soon as this the registered fields are
// getting updated by the corresponding reader class.
@Override
public void onFieldUpdateEvent(final Field field) {
// the update has to be done in a separate thread
// otherwise the UI will not be repainted
runOnUiThread(new Runnable() {
@Override
public void run() {
String fieldId = field.getSID();
TextView tv = null;
ProgressBar pb;
// get the text field
switch (fieldId) {
case SID_SoC:
// case SID_EVC_SoC:
tv = (TextView) findViewById(R.id.textSOC);
break;
case SID_Pedal:
// case SID_EVC_Pedal:
pb = (ProgressBar) findViewById(R.id.pedalBar);
pb.setProgress((int) field.getValue());
break;
case SID_MeanEffectiveTorque:
pb = (ProgressBar) findViewById(R.id.MeanEffectiveAccTorque);
pb.setProgress((int) (field.getValue() * MainActivity.reduction)); // --> translate from motor torque to wheel torque
break;
case SID_EVC_Odometer:
odo = (int ) field.getValue();
//odo = (int) Utils.kmOrMiles(field.getValue());
tv = null;
break;
case SID_MaxCharge:
tv = (TextView) findViewById(R.id.text_max_charge);
break;
case SID_RealSpeed:
realSpeed = (Math.round(field.getValue() * 10.0) / 10.0);
tv = (TextView) findViewById(R.id.textRealSpeed);
break;
case SID_Consumption:
double dcPwr = field.getValue();
tv = (TextView) findViewById(R.id.textConsumption);
if (realSpeed > 5) {
tv.setText(String.format(Locale.getDefault(), "%.1f", 100.0 * dcPwr / realSpeed));
// tv.setText("" + (Math.round(1000.0 * dcPwr / realSpeed) / 10.0));
} else {
tv.setText("-");
}
tv = null;
break;
case SID_RangeEstimate:
//int rangeInBat = (int) Utils.kmOrMiles(field.getValue());
int rangeInBat = (int) field.getValue();
if (rangeInBat > 0 && odo > 0 && destOdo > 0) { // we update only if there are no weird values
try {
if (destOdo > odo) {
setDestToDest("" + (destOdo - odo), "" + (rangeInBat - destOdo + odo));
} else {
setDestToDest("0", "0");
}
} catch (Exception e) {
// empty
}
}
tv = null;
break;
case SID_Coasting_Torque:
coasting_Torque = field.getValue() * MainActivity.reduction; // this torque is given in motor torque, not in wheel torque
break;
case SID_TotalPotentialResistiveWheelsTorque:
int tprwt = - ((int) field.getValue());
pb = (ProgressBar) findViewById(R.id.MaxBreakTorque);
if (pb != null) pb.setProgress(tprwt < 2047 ? tprwt : 10);
tv = null; // (TextView) findViewById(R.id.textTPRWT);
break;
case SID_DriverBrakeWheel_Torque_Request:
driverBrakeWheel_Torque_Request = field.getValue() + coasting_Torque;
pb = (ProgressBar) findViewById(R.id.pb_driver_torque_request);
if (pb != null) pb.setProgress((int) driverBrakeWheel_Torque_Request);
tv = null;
break;
}
// set regular new content, all exeptions handled above
if (tv != null) {
tv.setText(String.format(Locale.getDefault(), "%.1f", field.getValue()));
}
}
});
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present. This menu
// is another way to set the distance
getMenuInflater().inflate(R.menu.menu_driving, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_setDistanceToDestination) {
setDistanceToDestination();
return true;
}
return super.onOptionsItemSelected(item);
}
}