The R1 CAN Simulator can transmit simulated CAN signal values using a java panel or scripted input in a CSV format to an emulated Android device running on the same computer.
Page contents:
Your Android app can get the CAN values or listen for changes using the FCA Car Service CAN API.
The values for each CAN signal can be set using:
Additional information relating to the CAN Simulator.
| Download | Version | Description |
|---|---|---|
|
|
1.4 | Updated to support CAE API v1.3. |
|
|
1.3 | Updated to allow CAN values to be input via a CSV and support R12.5 permissions. |
|
|
1.2 | Updated to support CAE API v1.2. |
In order to connect to the simulator from your app you will need to import several modules and assets to your project. Follow the steps below:
Note: If your app is already configured to use the LoaderManager then it likely already has the LoaderManagerInterfaces and LoaderManagerStub modules, so you may not need to import them. You will need to import the LoaderManagerImpl module because it contains implementations of the managers that function with the simulator.
Note: During the module import process you might be warned that the module is missing dependencies. This is fine and will be resolved once all modules are imported.
Note: It is recommended that you refer to the included “LoaderManagerSimulatorTestApp” to help understand the code for steps 5 – 8. The TestLoader.java Activity in the test app contains code that is cleanly broken into several button presses and onChange callbacks.
/**
* Connect the emulated app to the simulator on the PC.
*
* @param view
*/
public void connectToSimulator(View view) {
Properties propertiesKona = new Properties();
AssetManager assetManager = this.getAssets();
InputStream inputStream = null;
try {
inputStream = assetManager.open("KonaEmulator.properties");
} catch (IOException e) {
e.printStackTrace();
}
try {
propertiesKona.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
Properties propertiesSensor = new Properties();
assetManager = this.getAssets();
inputStream = null;
try {
inputStream = assetManager.open("SensorContainer.properties");
} catch (IOException e) {
e.printStackTrace();
}
try {
propertiesSensor.load(inputStream);
} catch (IOException e) {
e.printStackTrace();
}
Properties merged = new Properties();
merged.putAll(propertiesKona);
merged.putAll(propertiesSensor);
String sensorPropertyJson = null;
try {
InputStream is = getAssets().open("sensor_properties_global_20170127.json");
int size = is.available();
byte[] buffer = new byte[size];
is.read(buffer);
is.close();
sensorPropertyJson = new String(buffer, "UTF-8");
} catch (IOException ex) {
ex.printStackTrace();
}
char[] charArray;
charArray = sensorPropertyJson.toCharArray();
EmulatorProperties.getInstance().setPropertiesFile(propertiesKona);
ContainerProperties.getInstance().setPropertiesFile(propertiesSensor);
SensorsObjectFactory.getInstance().setCharBuffer(charArray);
}
public class TestLoader extends AppCompatActivity implements ILoader.ILoaderCallback, IVehicleHVACManager.FcaIVehicleHVACManagerCallback,
IVehicleStatusManager.FcaIVehicleStatusManagerCallback {
/**
* Load the managers containing the required LIDs.
*
* @param view
*/
public void loadManagers(View view) {
final ManagerLoader managerLoader = new ManagerLoader();
managerLoader.getManager(IVehicleHVACManager.class.getName(), this, getApplicationContext());
managerLoader.getManager(IVehicleStatusManager.class.getName(), this, getApplicationContext());
}
/**
* Refresh values via get methods.
*
* @param view
*/
public void getValues(View view) {
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
try {
textViewBattery.setText("Battery: " + this.mVehicleStatusManager.getBattery());
textViewSpeed.setText("Speedometer: " + this.mVehicleStatusManager.getSpeedometer());
textViewTemp.setText("FT_DRV_ATC_TEMP: " + this.mVehicleHVACManager.getFT_DRV_ATC_TEMP());
} catch (final PropertyNotSupported e) {
System.out.println("Property not supported");
}
});
}
/**
* Register the listeners.
*
* @param view
*/
public void registerListeners(View view) {
//Register VehicleHVACManager listeners
if (IVehicleHVACManager.version.equalsIgnoreCase(this.mVehicleHVACManager.getManagerVersion())) {
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
try {
this.mVehicleHVACManager.registerFT_DRV_ATC_TEMPChange(this);
} catch (final PropertyNotSupported e) {
System.out.println("Failed to register listener for VehicleHVACManager. Property not supported.");
}
});
} else {
System.out.println("Manager version " + this.mVehicleHVACManager.getManagerVersion()
+ " and interface version " + IVehicleHVACManager.version + " are not the same");
}
//Register VehicleStatusManager listeners
if (IVehicleStatusManager.version.equalsIgnoreCase(this.mVehicleStatusManager.getManagerVersion())) {
final ExecutorService executor = Executors.newSingleThreadExecutor();
executor.submit(() -> {
try {
this.mVehicleStatusManager.registerBatteryChange(this);
this.mVehicleStatusManager.registerSpeedometerChange(this);
} catch (final PropertyNotSupported e) {
System.out.println("Failed to register listener for VehicleStatusManager. Property not supported.");
}
});
} else {
System.out.println("Manager version " + this.mVehicleStatusManager.getManagerVersion()
+ " and interface version " + IVehicleHVACManager.version + " are not the same");
}
}
/**
* Unregisters the listeners.
*
* @param view
*/
public void unregisterListeners(View view) {
this.mVehicleStatusManager.unregisterBatteryChange(this);
this.mVehicleStatusManager.unregisterSpeedometerChange(this);
this.mVehicleHVACManager.unregisterFT_DRV_ATC_TEMPChange(this);
}
@Override
public void onManagerReady(final String managerName, final Object o) {
if (managerName.equals(IVehicleHVACManager.class.getName())) {
this.mVehicleHVACManager = (IVehicleHVACManager) o;
} else if (managerName.equals(IVehicleStatusManager.class.getName())) {
this.mVehicleStatusManager = (IVehicleStatusManager) o;
}
}
@Override
public void onManagerFailure(final String managerName) {
System.out.println("Manager failure: " + managerName);
}
@Override
public void onFT_DRV_ATC_TEMPChange(final int value) {
textViewTemp.setText("FT_DRV_ATC_TEMP: " + value);
}
@Override
public void onSpeedometerChange(final float value) {
textViewSpeed.setText("Speedometer: " + value);
}
@Override
public void onBatteryChange(final float value) {
textViewBattery.setText("Battery: " + value);
}
The signals displayed on the CAN panel are based on the sensor_properties_global_20170127.json file found in “\CANSimulator\simulator\properties” of the CAN_Simulator package. You can remove signals you don’t need from the file so it’s easier to find the signals you need on the panel. To remove a signal, remove its entry from the “sensor” array. The signal name is the same as the “componentname” for each sensor. For example, if you did not want to see the “A_EV_Miles” and “A_Hybrid_Miles” signals on the panel, you would delete the following code from the sensor_properties file.
{
"type": "range",
"componentname": "A_EV_Miles",
"ppsSource": "can/xlet",
"channelNos": "1",
"ppsattributes": "A_EV_Miles",
"dataTypes": "TYPE_DOUBLE",
"minabsranges": "0",
"maxabsranges": "9999.9",
"resoluions": "0.1",
"unit": "Mile"
},
{
"type": "range",
"componentname": "A_Hybrid_Miles",
"ppsSource": "can/xlet",
"channelNos": "1",
"ppsattributes": "A_Hybrid_Miles",
"dataTypes": "TYPE_DOUBLE",
"minabsranges": "0",
"maxabsranges": "9999.9",
"resoluions": "0.1",
"unit": "Mile"
},
Once the file has been updated, save it and relaunch the simulator to see the changes take effect.
Updated: 1/31/2020, Android is a trademark of Google LLC