Skip to content

Commit

Permalink
v.1.9.0
Browse files Browse the repository at this point in the history
[*] completely rewritten initialization code to support hardware late hardware initialization if it fails during startup
[*] pretty all status messages have been changed
[+] added logging of initialization steps to syslog
  • Loading branch information
7floor committed Jun 22, 2016
1 parent 8097f7d commit 64310b2
Show file tree
Hide file tree
Showing 11 changed files with 343 additions and 207 deletions.
18 changes: 18 additions & 0 deletions library/src/main/java/com/sevenfloor/mtcsound/CLib.java
@@ -0,0 +1,18 @@
package com.sevenfloor.mtcsound;

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public interface CLib extends Library {
CLib instance = (CLib) Native.loadLibrary(Platform.C_LIBRARY_NAME, CLib.class);

int O_RDWR = 0x0002;
int I2C_RETRIES = 0x0701;
int I2C_SLAVE = 0x0703;

int open(String path, int flags);
int close(int fd);
int ioctl(int fd, int request, Object... args);
int write(int fd, byte[] buffer, int count);
}
50 changes: 30 additions & 20 deletions library/src/main/java/com/sevenfloor/mtcsound/Device.java
Expand Up @@ -25,25 +25,15 @@ public class Device {
private final Object lock = new Object();
public final DeviceState state = new DeviceState();
private final Map<String, ParameterHandler> handlers = new HashMap<>();
private final HwInterface hardware = new HwInterface();
private final Persister persister = new Persister();
private HwInterface hardware = null;
private boolean stateLoaded = false;
private boolean i2cMode = false;

public Device(Context context) {
this.context = context;

addHandler(new ControlModeHandler(this));

for(int attempts = 3; attempts > 0; attempts--) {
i2cMode = checkHardware();
if (i2cMode) break;
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
}
}

addHandler(new PowerHandler(this));

// inputs
Expand Down Expand Up @@ -85,6 +75,8 @@ public Device(Context context) {
addHandler(new GpsAltMixHandler(this));
addHandler(new GsmAltInputHandler(this));
addHandler(new RecMuteHandler(this));

init();
}

public String getParameters(String keyValue, String defaultValue) {
Expand Down Expand Up @@ -170,32 +162,50 @@ public void onRecording(boolean active) {
applyState();
}

public void checkHardware() {
if (hardware == null) return;
hardware.check();
setModeAndStatus(hardware.isOnline(), hardware.getStateDescription());
}

public void applyState() {
applyState(false);
}

public void applyState(boolean forced) {
if (i2cMode)
hardware.applyState(state, forced);
persister.writeState(context, state);
if (hardware == null) return;
hardware.applyState(state, forced);
setModeAndStatus(hardware.isOnline(), hardware.getStateDescription());
}

public void notifyInputChange(){
context.sendBroadcast(new Intent("com.microntek.inputchange"));
}

private void checkStateLoaded() {
if (stateLoaded)
private void init() {
String message = SoftwareChecker.check();
if (message != null) {
setModeAndStatus(false, message);
return;
}

hardware = new HwInterface(SoftwareChecker.getFileNames());
setModeAndStatus(hardware.isOnline(), hardware.getStateDescription());
}

private void checkStateLoaded() {
if (stateLoaded) return;
persister.readState(context, state);
if (i2cMode)
hardware.applyState(state, true);
stateLoaded = true;
if (hardware == null) return;
hardware.applyState(state, true);
setModeAndStatus(hardware.isOnline(), hardware.getStateDescription());
}

private boolean checkHardware() {
state.HardwareStatus = hardware.CheckHardware();
return state.HardwareStatus.startsWith("i2c");
private void setModeAndStatus(boolean i2cMode, String status)
{
state.ModeAndStatus = String.format("%s, %s", i2cMode ? "i2c" : "mcu", status);
}

private void addHandler(ParameterHandler handler){
Expand Down
111 changes: 60 additions & 51 deletions library/src/main/java/com/sevenfloor/mtcsound/HwInterface.java
@@ -1,13 +1,14 @@
package com.sevenfloor.mtcsound;

import android.util.Log;

import com.sevenfloor.mtcsound.state.DeviceState;
import com.sevenfloor.mtcsound.state.EqualizerBand;
import com.sevenfloor.mtcsound.state.Input;
import com.sevenfloor.mtcsound.state.PhoneState;
import com.sevenfloor.mtcsound.state.SoundProfile;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

public class HwInterface {

Expand Down Expand Up @@ -53,34 +54,52 @@ public class HwInterface {

private final Register[] AllRegisters = new Register[] { R01, R02, R03, R05, R06, R20, R28, R29, R2A, R2B, R2C, R30, R41, R44, R47, R51, R54, R57, R75 };

public String CheckHardware() {
if (!checkDevI2cFile(0)) {
tryLoadDriver();
}
if (!checkDevI2cFile(0)) {
return "mcu,No device driver i2c-dev";
}
private List<String> fileNames;
private String fileName = null;
private String stateMessage;

String lastError = "";
for(int i = 0; i < 10; i++)
{
if (!checkDevI2cFile(i)) continue; // don't check files that don't exist
public HwInterface(List<String> fileNames) {
this.fileNames = fileNames;
check();
}

if (I2cBus.getDevFileAccess(i) != 0) {
lastError = "No access to /dev/i2c-?; " + I2cBus.lastError;
continue;
}
public boolean isOnline() {
return fileName != null;
}

int errno = I2cBus.write(0x40,new byte[][]{{0x01}});
if (errno == 0) return "i2c,Channel " + i;
lastError = I2cBus.lastError;
if ((errno == 11 || errno == 110) && lastError.contains("write")) // EAGAIN (3188) || ETIMEOUT (3066)
lastError = lastError + " (no response from i2c slave)";
public String getStateDescription() {
if (fileName != null)
return "Controlling via " + fileName;
return stateMessage;
}

public void check() {
if (fileName != null) return;
Log.i(Utils.logTag, "Checking hardware");
stateMessage = "No accessible device files";
fileName = null;
for (String fn: fileNames) {
stateMessage = I2cBus.write(fn, 0x40,new byte[][]{{0x01}});
if (stateMessage == null) {
Log.i(Utils.logTag, String.format("Checking %s - Success", fn));
fileName = fn;
Log.i(Utils.logTag, getStateDescription());
return;
} else {
Log.e(Utils.logTag, String.format("Checking %s - %s", fn, stateMessage));
}
}
return "mcu," + lastError;
stateMessage = "Error checking hardware: " + stateMessage;
Log.i(Utils.logTag, getStateDescription());
}

public void applyState(DeviceState state, boolean forced) {
if (fileName == null) {
check();
if (fileName == null) return;
forced = true; // if connected for the first time
}

applySettings(state);

applyMixingGain(state);
Expand Down Expand Up @@ -279,7 +298,7 @@ private void writeRegistersToI2C(boolean forced) {
r.flush();
}
}
I2cBus.write(0x40, buffer.toArray(new byte[][]{}));
I2cBus.write(fileName, 0x40, buffer.toArray(new byte[][]{}));
}

private void writeAllRegistersToI2C() {
Expand All @@ -292,38 +311,28 @@ private void writeAllRegistersToI2C() {
buffer[i + 1] = (byte) r.value;
r.flush();
}
I2cBus.write(0x40, new byte[][]{buffer});
I2cBus.write(fileName, 0x40, new byte[][]{buffer});
}

private static boolean checkDevI2cFile(int channel) {
File f = new File("/dev/i2c-" + channel);
return f.exists();
}
private class Register {
int index;
int lastValue;
int value;

private static void tryLoadDriver() {
try {
Process process = Runtime.getRuntime().exec(new String[]{"su", "-c", "insmod /system/lib/modules/i2c-dev.ko"});
process.waitFor();
} catch (Throwable ignored) {}
}}

class Register {
int index;
int lastValue;
int value;

public Register(int index, int defaultValue){
this.index = index;
this.value = defaultValue;
this.lastValue = -1; // so that first time it will be written forcibly
}
public Register(int index, int defaultValue){
this.index = index;
this.value = defaultValue;
this.lastValue = -1; // so that first time it will be written forcibly
}

public boolean isChanged() {
return lastValue != value;
}
public boolean isChanged() {
return lastValue != value;
}

public void flush(){
lastValue = value;
public void flush(){
lastValue = value;
}
}

}

56 changes: 12 additions & 44 deletions library/src/main/java/com/sevenfloor/mtcsound/I2cBus.java
Expand Up @@ -6,80 +6,48 @@

public class I2cBus {

private interface CLib extends Library {
CLib instance = (CLib) Native.loadLibrary(Platform.C_LIBRARY_NAME, CLib.class);

int O_RDWR = 0x0002;
int I2C_RETRIES = 0x0701;
int I2C_SLAVE = 0x0703;

int open(String path, int flags);
int close(int fd);
int ioctl(int fd, int request, Object... args);
int write(int fd, byte[] buffer, int count);
}

public static int currentBusNumber = 4;
public static String lastError = "";

public static int getDevFileAccess(int busNumber) {
lastError = "";
currentBusNumber = busNumber;
try {
Process process = Runtime.getRuntime().exec(new String[]{"su", "-c", String.format("chmod 666 /dev/i2c-%d", currentBusNumber)});
process.waitFor();
int ev = process.exitValue();
if (ev != 0)
lastError = String.format("su exit code %s", ev);
return ev;
} catch (Throwable e) {
lastError = String.format("Exception %s", e.getMessage());
return -1;
}
}

public static int write(int address, byte[][] data) {
public static String write(String fileName, int address, byte[][] data) {
int errno;
lastError = "";
try {
int file = CLib.instance.open(String.format("/dev/i2c-%d", currentBusNumber), CLib.O_RDWR);
int file = CLib.instance.open(fileName, CLib.O_RDWR);
if (file < 0) {
errno = Native.getLastError();
lastError = String.format("Error in open() %d", errno);
return errno;
return String.format("Error in open() %d", errno);
}

if (CLib.instance.ioctl(file, CLib.I2C_RETRIES, (int) 2) < 0) {
errno = Native.getLastError();
lastError = String.format("Error in ioctl(retries) %d", errno);
CLib.instance.close(file);
return errno;
return String.format("Error in ioctl(retries) %d", errno);
}

if (CLib.instance.ioctl(file, CLib.I2C_SLAVE, address) < 0) {
errno = Native.getLastError();
lastError = String.format("Error in ioctl(slave) %d", errno);
CLib.instance.close(file);
return errno;
return String.format("Error in ioctl(slave) %d", errno);
}

for (byte[] chunk : data) {
int len = chunk.length;
if (CLib.instance.write(file, chunk, len) != len) {
errno = Native.getLastError();
lastError = String.format("Error in write() %d", errno);
CLib.instance.close(file);
return errno;
String errorMessage = String.format("Error in write() %d", errno);
if (errno == 11 || errno == 110) // EAGAIN (3188) || ETIMEOUT (3066)
errorMessage = errorMessage + " (no response from i2c slave)";
return errorMessage;
}
}

CLib.instance.close(file);

return 0;
return null;

} catch (Throwable e) {
lastError = String.format("Exception %s", e.getMessage());
return -1;
return String.format("Exception %s", e.getMessage());
}
}
}

0 comments on commit 64310b2

Please sign in to comment.