diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java
index 39964bdcd..ad1aa2c91 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/devicesettings/DeviceSettingsPreferenceConst.java
@@ -184,6 +184,9 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_UM25_SHOW_THRESHOLD_NOTIFICATION = "um25_current_threshold_notify";
public static final String PREF_UM25_SHOW_THRESHOLD = "um25_current_threshold";
+ public static final String PREF_VESC_MINIMUM_VOLTAGE = "vesc_minimum_battery_voltage";
+ public static final String PREF_VESC_MAXIMUM_VOLTAGE = "vesc_maximum_battery_voltage";
+
public static final String PREF_SOUNDS = "sounds";
public static final String PREF_AUTH_KEY = "authkey";
public static final String PREF_USER_FITNESS_GOAL = "fitness_goal";
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescControlActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescControlActivity.java
index 8c745f975..18f904a9d 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescControlActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescControlActivity.java
@@ -73,7 +73,7 @@ public class VescControlActivity extends AbstractGBActivity {
private void restoreValues(){
rpmEditText.setText(String.valueOf(preferences.getInt(PREFS_KEY_LAST_RPM, 0)));
- breakCurrentEditText.setText(String.valueOf(preferences.getInt(PREFS_KEY_LAST_BREAK_CURRENT, 0)));
+ breakCurrentEditText.setText(String.valueOf(preferences.getInt(PREFS_KEY_LAST_BREAK_CURRENT, 0) / 1000));
}
@Override
@@ -184,7 +184,11 @@ public class VescControlActivity extends AbstractGBActivity {
currentBreakCurrentMa = 0;
return;
}
- VescControlActivity.this.currentBreakCurrentMa = Integer.parseInt(text) * 1000;
+ try {
+ VescControlActivity.this.currentBreakCurrentMa = Integer.parseInt(text) * 1000;
+ }catch (NumberFormatException e){
+ VescControlActivity.this.currentBreakCurrentMa = 0;
+ }
}
});
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java
index f34dc2083..773b7e6a1 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/devices/vesc/VescCoordinator.java
@@ -24,6 +24,7 @@ import android.os.ParcelUuid;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
@@ -38,9 +39,11 @@ import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
public class VescCoordinator extends AbstractDeviceCoordinator {
public final static String UUID_SERVICE_SERIAL_HM10 = "0000ffe0-0000-1000-8000-00805f9b34fb";
public final static String UUID_CHARACTERISTIC_SERIAL_TX_HM10 = "0000ffe1-0000-1000-8000-00805f9b34fb";
+ public final static String UUID_CHARACTERISTIC_SERIAL_RX_HM10 = "0000ffe1-0000-1000-8000-00805f9b34fb";
public final static String UUID_SERVICE_SERIAL_NRF = "0000ffe0-0000-1000-8000-00805f9b34fb";
public final static String UUID_CHARACTERISTIC_SERIAL_TX_NRF = "0000ffe0-0000-1000-8000-00805f9b34fb";
+ public final static String UUID_CHARACTERISTIC_SERIAL_RX_NRF = "0000ffe1-0000-1000-8000-00805f9b34fb";
@Override
@@ -48,6 +51,13 @@ public class VescCoordinator extends AbstractDeviceCoordinator {
}
+ @Override
+ public int[] getSupportedDeviceSpecificSettings(GBDevice device) {
+ return new int[]{
+ R.xml.devicesettings_vesc
+ };
+ }
+
@Override
public DeviceType getSupportedType(GBDeviceCandidate candidate) {
ParcelUuid[] uuids = candidate.getServiceUuids();
@@ -77,7 +87,7 @@ public class VescCoordinator extends AbstractDeviceCoordinator {
@Override
public boolean supportsActivityDataFetching() {
- return false;
+ return true;
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/CommandType.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/CommandType.java
index b1ce868b4..bd0ca8eae 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/CommandType.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/CommandType.java
@@ -17,17 +17,47 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.vesc;
public enum CommandType {
- SET_CURRENT((byte) 0x06),
- SET_CURRENT_BRAKE((byte) 0x07),
- SET_RPM((byte) 0x08),
+ COMM_FW_VERSION,
+ COMM_JUMP_TO_BOOTLOADER,
+ COMM_ERASE_NEW_APP,
+ COMM_WRITE_NEW_APP_DATA,
+ COMM_GET_VALUES,
+ COMM_SET_DUTY,
+ COMM_SET_CURRENT,
+ COMM_SET_CURRENT_BRAKE,
+ COMM_SET_RPM,
+ COMM_SET_POS,
+ COMM_SET_HANDBRAKE,
+ COMM_SET_DETECT,
+ COMM_SET_SERVO_POS,
+ COMM_SET_MCCONF,
+ COMM_GET_MCCONF,
+ COMM_GET_MCCONF_DEFAULT,
+ COMM_SET_APPCONF,
+ COMM_GET_APPCONF,
+ COMM_GET_APPCONF_DEFAULT,
+ COMM_SAMPLE_PRINT,
+ COMM_TERMINAL_CMD,
+ COMM_PRINT,
+ COMM_ROTOR_POSITION,
+ COMM_EXPERIMENT_SAMPLE,
+ COMM_DETECT_MOTOR_PARAM,
+ COMM_DETECT_MOTOR_R_L,
+ COMM_DETECT_MOTOR_FLUX_LINKAGE,
+ COMM_DETECT_ENCODER,
+ COMM_DETECT_HALL_FOC,
+ COMM_REBOOT,
+ COMM_ALIVE,
+ COMM_GET_DECODED_PPM,
+ COMM_GET_DECODED_ADC,
+ COMM_GET_DECODED_CHUK,
+ COMM_FORWARD_CAN,
+ COMM_SET_CHUCK_DATA,
+ COMM_CUSTOM_APP_DATA,
+ COMM_NRF_START_PAIRING
;
- byte commandByte;
-
- CommandType(byte commandByte){
- this.commandByte = commandByte;
- }
public byte getCommandByte(){
- return this.commandByte;
+ return (byte) this.ordinal();
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/VescDeviceSupport.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/VescDeviceSupport.java
index ca10ef14a..2007b6f1d 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/VescDeviceSupport.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/service/devices/vesc/VescDeviceSupport.java
@@ -16,11 +16,14 @@
along with this program. If not, see . */
package nodomain.freeyourgadget.gadgetbridge.service.devices.vesc;
+import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
+import android.bluetooth.BluetoothGattDescriptor;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.SharedPreferences;
import androidx.localbroadcastmanager.content.LocalBroadcastManager;
@@ -28,8 +31,11 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
import java.util.UUID;
+import nodomain.freeyourgadget.gadgetbridge.GBApplication;
+import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.devices.vesc.VescCoordinator;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
@@ -37,32 +43,44 @@ import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.util.CheckSums;
-public class VescDeviceSupport extends VescBaseDeviceSupport{
- BluetoothGattCharacteristic serialWriteCharacteristic;
+public class VescDeviceSupport extends VescBaseDeviceSupport {
+ BluetoothGattCharacteristic serialWriteCharacteristic, serialReadCharacteristic;
public static final String COMMAND_SET_RPM = "nodomain.freeyourgadget.gadgetbridge.vesc.command.SET_RPM";
public static final String COMMAND_SET_CURRENT = "nodomain.freeyourgadget.gadgetbridge.vesc.command.SET_CURRENT";
public static final String COMMAND_SET_BREAK_CURRENT = "nodomain.freeyourgadget.gadgetbridge.vesc.command.SET_BREAK_CURRENT";
+ public static final String COMMAND_GET_VALUES = "nodomain.freeyourgadget.gadgetbridge.vesc.command.GET_VALUES";
public static final String EXTRA_RPM = "EXTRA_RPM";
public static final String EXTRA_CURRENT = "EXTRA_CURRENT";
+ public static final String EXTRA_VOLTAGE = "EXTRA_VOLTAGE";
+
+ public static final String ACTION_GOT_VALUES = "nodomain.freeyourgadget.gadgetbridge.vesc.action.GOT_VALUES";
private Logger logger = LoggerFactory.getLogger(getClass());
private DeviceType deviceType;
- public VescDeviceSupport(DeviceType type){
+ private ByteBuffer responseBuffer = ByteBuffer.allocate(100);
+
+ public VescDeviceSupport(DeviceType type) {
super();
- logger.debug("VescDeviceSupport() {}", type);
+ responseBuffer.order(ByteOrder.BIG_ENDIAN);
deviceType = type;
- if(type == DeviceType.VESC_NRF){
+ if (type == DeviceType.VESC_NRF) {
addSupportedService(UUID.fromString(VescCoordinator.UUID_SERVICE_SERIAL_NRF));
- }else if(type == DeviceType.VESC_HM10){
+ } else if (type == DeviceType.VESC_HM10) {
addSupportedService(UUID.fromString(VescCoordinator.UUID_SERVICE_SERIAL_HM10));
}
}
+ @Override
+ public void onFetchRecordedData(int dataTypes) {
+ super.onFetchRecordedData(dataTypes);
+ getValues();
+ }
+
@Override
protected TransactionBuilder initializeDevice(TransactionBuilder builder) {
logger.debug("initializing device");
@@ -71,15 +89,148 @@ public class VescDeviceSupport extends VescBaseDeviceSupport{
initBroadcast();
- if(deviceType == DeviceType.VESC_NRF){
+ if (deviceType == DeviceType.VESC_NRF) {
this.serialWriteCharacteristic = getCharacteristic(UUID.fromString(VescCoordinator.UUID_CHARACTERISTIC_SERIAL_TX_NRF));
- }else if(deviceType == DeviceType.VESC_HM10){
+ this.serialReadCharacteristic = getCharacteristic(UUID.fromString(VescCoordinator.UUID_CHARACTERISTIC_SERIAL_RX_NRF));
+ } else if (deviceType == DeviceType.VESC_HM10) {
this.serialWriteCharacteristic = getCharacteristic(UUID.fromString(VescCoordinator.UUID_CHARACTERISTIC_SERIAL_TX_HM10));
+ this.serialReadCharacteristic = getCharacteristic(UUID.fromString(VescCoordinator.UUID_CHARACTERISTIC_SERIAL_RX_HM10));
}
+ builder.notify(this.serialReadCharacteristic, true);
+
return builder.add(new SetDeviceStateAction(getDevice(), GBDevice.State.INITIALIZED, getContext()));
}
+ @Override
+ public boolean onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) {
+ super.onDescriptorWrite(gatt, descriptor, status);
+ getValues();
+
+ return true;
+ }
+
+ @Override
+ public boolean onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
+ handleRxCharacteristic(characteristic);
+
+ return true;
+ }
+
+ private void handleRxCharacteristic(BluetoothGattCharacteristic characteristic) {
+ if (characteristic != serialReadCharacteristic) return;
+
+ responseBuffer.put(characteristic.getValue());
+ short length = 0;
+ int oldPosition = responseBuffer.position();
+ responseBuffer.position(0);
+ byte lengthType = responseBuffer.get();
+ if (lengthType == 2) {
+ length = responseBuffer.get();
+ } else if (lengthType == 3) {
+ length = responseBuffer.getShort();
+ } else {
+ return;
+ }
+ if (length == oldPosition - 5) {
+ // whole message transmitted
+ responseBuffer.position(oldPosition);
+ handleResponseBuffer(responseBuffer);
+
+ oldPosition = 0;
+ }
+ responseBuffer.position(oldPosition);
+ }
+
+ private void handleResponseBuffer(ByteBuffer responseBuffer) {
+ int bufferLength = responseBuffer.position();
+ int payloadStartPosition = responseBuffer.get(0);
+
+ byte[] payload = new byte[bufferLength - 3 - payloadStartPosition];
+ System.arraycopy(responseBuffer.array(), payloadStartPosition, payload, 0, payload.length);
+
+ int actualCrc = CheckSums.getCRC16(payload, 0);
+ int expectedCrc = responseBuffer.getShort(bufferLength - 3);
+
+ byte responseType = payload[0];
+ if (responseType == 0x04) {
+ handleResponseValues(responseBuffer);
+ }
+ }
+
+ private void handleResponseValues(ByteBuffer valueBuffer) {
+ valueBuffer.position(3);
+ float temp_mos = buffer_get_float16(valueBuffer, 1e1);
+ float temp_motor = buffer_get_float16(valueBuffer, 1e1);
+ float current_motor = buffer_get_float32(valueBuffer, 1e2);
+ float current_in = buffer_get_float32(valueBuffer, 1e2);
+ float id = buffer_get_float32(valueBuffer, 1e2);
+ float iq = buffer_get_float32(valueBuffer, 1e2);
+ float duty_now = buffer_get_float16(valueBuffer, 1e3);
+ float rpm = buffer_get_float32(valueBuffer, 1e0);
+ float v_in = buffer_get_float16(valueBuffer, 1e1);
+ float amp_hours = buffer_get_float32(valueBuffer, 1e4);
+ float amp_hours_charged = buffer_get_float32(valueBuffer, 1e4);
+ float watt_hours = buffer_get_float32(valueBuffer, 1e4);
+ float watt_hours_charged = buffer_get_float32(valueBuffer, 1e4);
+ float tachometer = buffer_get_int32(valueBuffer);
+ float tachometer_abs = buffer_get_int32(valueBuffer);
+
+ handleBatteryVoltage(v_in);
+
+ Intent intent = new Intent(ACTION_GOT_VALUES);
+ intent.putExtra(EXTRA_VOLTAGE, v_in);
+ }
+
+
+
+ void handleBatteryVoltage(float voltage){
+ SharedPreferences prefs = GBApplication.getDeviceSpecificSharedPrefs(getDevice().getAddress());
+ float minimalVoltage = Float.parseFloat(prefs.getString(DeviceSettingsPreferenceConst.PREF_VESC_MINIMUM_VOLTAGE, "-1"));
+ float maximalVoltage = Float.parseFloat(prefs.getString(DeviceSettingsPreferenceConst.PREF_VESC_MAXIMUM_VOLTAGE, "-1"));
+
+ if(minimalVoltage == -1){
+ return;
+ }
+ if(maximalVoltage == -1){
+ return;
+ }
+
+ float voltageAboveMinimum = voltage - minimalVoltage;
+ float voltageRange = maximalVoltage - minimalVoltage;
+ float fullness = voltageAboveMinimum / voltageRange;
+
+ int fullnessPercent = (int)(fullness * 100);
+ fullnessPercent = Math.max(fullnessPercent, 0);
+ fullnessPercent = Math.min(fullnessPercent, 100);
+
+ getDevice().setBatteryLevel(fullnessPercent);
+ getDevice().setBatteryVoltage(voltage);
+ getDevice().sendDeviceUpdateIntent(getContext());
+ }
+
+ float buffer_get_float16(ByteBuffer buffer, double scale){
+ return (float) (buffer.getShort() / scale);
+ }
+
+ float buffer_get_float32(ByteBuffer buffer, double scale){
+ return (float) (buffer.getInt() / scale);
+ }
+
+ int buffer_get_int32(ByteBuffer buffer){
+ return buffer.getInt();
+ }
+
+ @Override
+ public void onTestNewFunction() {
+ getValues();
+ // getDecodedADC();
+ }
+
+ private void getDecodedADC() {
+ buildAndQueryPacket(CommandType.COMM_GET_DECODED_ADC);
+ }
+
private void initBroadcast() {
LocalBroadcastManager broadcastManager = LocalBroadcastManager.getInstance(getContext());
@@ -87,86 +238,99 @@ public class VescDeviceSupport extends VescBaseDeviceSupport{
filter.addAction(COMMAND_SET_RPM);
filter.addAction(COMMAND_SET_CURRENT);
filter.addAction(COMMAND_SET_BREAK_CURRENT);
+ filter.addAction(COMMAND_GET_VALUES);
broadcastManager.registerReceiver(commandReceiver, filter);
}
+ @Override
+ public void dispose() {
+ super.dispose();
+ LocalBroadcastManager.getInstance(getContext()).unregisterReceiver(commandReceiver);
+ }
+
BroadcastReceiver commandReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
- if(intent.getAction().equals(COMMAND_SET_RPM)){
+ if (intent.getAction().equals(COMMAND_SET_RPM)) {
VescDeviceSupport.this.setRPM(
intent.getIntExtra(EXTRA_RPM, 0)
);
- }else if(intent.getAction().equals(COMMAND_SET_BREAK_CURRENT)){
+ } else if (intent.getAction().equals(COMMAND_SET_BREAK_CURRENT)) {
VescDeviceSupport.this.setBreakCurrent(
intent.getIntExtra(EXTRA_CURRENT, 0)
);
- }else if(intent.getAction().equals(COMMAND_SET_CURRENT)){
+ } else if (intent.getAction().equals(COMMAND_SET_CURRENT)) {
VescDeviceSupport.this.setCurrent(
intent.getIntExtra(EXTRA_CURRENT, 0)
);
+ } else if (intent.getAction().equals(COMMAND_GET_VALUES)) {
+ VescDeviceSupport.this.getValues();
}
}
};
- public void setCurrent(int currentMillisAmperes){
- buildAndQueryPacket(CommandType.SET_CURRENT, currentMillisAmperes);
+ public void setCurrent(int currentMillisAmperes) {
+ buildAndQueryPacket(CommandType.COMM_SET_CURRENT, currentMillisAmperes);
}
- public void setBreakCurrent(int breakCurrentMillisAmperes){
- buildAndQueryPacket(CommandType.SET_CURRENT_BRAKE, breakCurrentMillisAmperes);
+ public void setBreakCurrent(int breakCurrentMillisAmperes) {
+ buildAndQueryPacket(CommandType.COMM_SET_CURRENT_BRAKE, breakCurrentMillisAmperes);
}
- public void setRPM(int rpm){
- buildAndQueryPacket(CommandType.SET_RPM, rpm);
+ public void getValues() {
+ buildAndQueryPacket(CommandType.COMM_GET_VALUES);
}
- public void buildAndQueryPacket(CommandType commandType, Object ... args){
+ public void setRPM(int rpm) {
+ buildAndQueryPacket(CommandType.COMM_SET_RPM, rpm);
+ }
+
+ public void buildAndQueryPacket(CommandType commandType, Object... args) {
byte[] data = buildPacket(commandType, args);
queryPacket(data);
}
- public void queryPacket(byte[] data){
+ public void queryPacket(byte[] data) {
new TransactionBuilder("write serial packet")
.write(this.serialWriteCharacteristic, data)
.queue(getQueue());
}
- public byte[] buildPacket(CommandType commandType, Object ... args){
+ public byte[] buildPacket(CommandType commandType, Object... args) {
int dataLength = 0;
- for(Object arg : args){
- if(arg instanceof Integer) dataLength += 4;
- else if(arg instanceof Short) dataLength += 2;
+ for (Object arg : args) {
+ if (arg instanceof Integer) dataLength += 4;
+ else if (arg instanceof Short) dataLength += 2;
}
ByteBuffer buffer = ByteBuffer.allocate(dataLength);
- for(Object arg : args){
- if(arg instanceof Integer) buffer.putInt((Integer) arg);
- if(arg instanceof Short) buffer.putShort((Short) arg);
+ for (Object arg : args) {
+ if (arg instanceof Integer) buffer.putInt((Integer) arg);
+ if (arg instanceof Short) buffer.putShort((Short) arg);
}
return buildPacket(commandType, buffer.array());
}
- public byte[] buildPacket(CommandType commandType, byte[] data){
+ public byte[] buildPacket(CommandType commandType, byte[] data) {
return buildPacket(commandType.getCommandByte(), data);
}
- private byte[] buildPacket(byte commandByte, byte[] data){
+ private byte[] buildPacket(byte commandByte, byte[] data) {
byte[] contents = new byte[data.length + 1];
contents[0] = commandByte;
System.arraycopy(data, 0, contents, 1, data.length);
return buildPacket(contents);
}
- private byte[] buildPacket(byte[] contents){
+ private byte[] buildPacket(byte[] contents) {
int dataLength = contents.length;
ByteBuffer buffer = ByteBuffer.allocate(dataLength + (dataLength < 256 ? 5 : 6));
- if(dataLength < 256){
- buffer.put((byte)0x02);
- buffer.put((byte)dataLength);
- }else{
+ if (dataLength < 256) {
+ buffer.put((byte) 0x02);
+ buffer.put((byte) dataLength);
+ } else {
buffer.put((byte) 0x03);
buffer.putShort((short) dataLength);
}
diff --git a/app/src/main/res/xml/devicesettings_vesc.xml b/app/src/main/res/xml/devicesettings_vesc.xml
new file mode 100644
index 000000000..d4906ee06
--- /dev/null
+++ b/app/src/main/res/xml/devicesettings_vesc.xml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
\ No newline at end of file