Improve app reliability
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
All checks were successful
ci/woodpecker/push/woodpecker Pipeline was successful
Signed-off-by: Severin Kaderli <severin@kaderli.dev>
This commit is contained in:
parent
5fb08ef5b4
commit
efd8e63e4e
3 changed files with 82 additions and 33 deletions
|
@ -5,7 +5,7 @@ class Constants {
|
||||||
* @type {Number}
|
* @type {Number}
|
||||||
*/
|
*/
|
||||||
static get CLOCK_TIME() {
|
static get CLOCK_TIME() {
|
||||||
return 1000;
|
return 500;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -16,7 +16,7 @@ abstract class BaseSensorActivity : BaseActivity(), SensorEventListener {
|
||||||
super.onResume()
|
super.onResume()
|
||||||
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
sensorManager = getSystemService(Context.SENSOR_SERVICE) as SensorManager
|
||||||
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
|
sensor = sensorManager.getDefaultSensor(Sensor.TYPE_MAGNETIC_FIELD);
|
||||||
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_UI);
|
sensorManager.registerListener(this, sensor, SensorManager.SENSOR_DELAY_GAME);
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onStop() {
|
override fun onStop() {
|
||||||
|
|
|
@ -25,6 +25,9 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
*/
|
*/
|
||||||
private var signal = ArrayList<Sample<Signal>>()
|
private var signal = ArrayList<Sample<Signal>>()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Flag that determines if the preamble was already received.
|
||||||
|
*/
|
||||||
private var preambleReceived = false
|
private var preambleReceived = false
|
||||||
|
|
||||||
override fun onCreate(savedInstanceState: Bundle?) {
|
override fun onCreate(savedInstanceState: Bundle?) {
|
||||||
|
@ -50,19 +53,51 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
return getMidRangeOfData() + 3
|
return getMidRangeOfData() + 3
|
||||||
}
|
}
|
||||||
|
|
||||||
return getMidRangeOfData();
|
return getMidRangeOfData() + 2
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getThresholdForLowSignals(): Float {
|
||||||
|
if (getRangeOfData() < 3) {
|
||||||
|
return getMidRangeOfData() + 3
|
||||||
|
}
|
||||||
|
|
||||||
|
return getMidRangeOfData() - 2
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getMidRangeOfData(): Float {
|
private fun getMidRangeOfData(): Float {
|
||||||
val maxValue = samples.maxByOrNull { it.value } ?: Sample(0f)
|
val maxValue = samples.maxByOrNull { it.value } ?: Sample(0f)
|
||||||
val minValue = samples.minByOrNull { it.value } ?: Sample(0f)
|
val minValue = samples.minByOrNull { it.value } ?: Sample(0f)
|
||||||
return (maxValue.value + minValue.value) / 2;
|
return (maxValue.value + minValue.value) / 2
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun isHigh(value: Float): Boolean {
|
private fun isHigh(value: Float): Boolean {
|
||||||
return value > getThresholdForHighSignals()
|
return value > getThresholdForHighSignals()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun isLow(value: Float): Boolean {
|
||||||
|
return value < getThresholdForLowSignals()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Check if the given sample should count as a high or low signal. If the sample is inside
|
||||||
|
* the threshold area it is not counted.
|
||||||
|
*/
|
||||||
|
private fun getSignalForSample(sample: Sample<Float>): Sample<Signal>? {
|
||||||
|
if (isHigh(sample.value)) {
|
||||||
|
return Sample(Signal.High)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isLow(sample.value)) {
|
||||||
|
return Sample(Signal.Low)
|
||||||
|
}
|
||||||
|
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to detect the preamble in the already received signal. If it can find the preamble it returns true and
|
||||||
|
* false otherwise.
|
||||||
|
*/
|
||||||
private fun detectPreamble(): Boolean {
|
private fun detectPreamble(): Boolean {
|
||||||
val cleanedSignal = cleanSignal(signal)
|
val cleanedSignal = cleanSignal(signal)
|
||||||
val compressedSignal = compressSignal(cleanedSignal)
|
val compressedSignal = compressSignal(cleanedSignal)
|
||||||
|
@ -89,9 +124,11 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This functions takes the signal and filters out samples that are only in a cluster of 3 or less of the same signal.
|
||||||
|
* This way we can remove single jumps that occur in the signal.
|
||||||
|
*/
|
||||||
private fun cleanSignal(signal: List<Sample<Signal>>): List<Sample<Signal>> {
|
private fun cleanSignal(signal: List<Sample<Signal>>): List<Sample<Signal>> {
|
||||||
// TODO: Improve this method
|
|
||||||
// Remove outliers from the signal (single signal spikes or drops)
|
|
||||||
val cleanSignal = signal.filterIndexed { index, sample ->
|
val cleanSignal = signal.filterIndexed { index, sample ->
|
||||||
var elementCount = 1
|
var elementCount = 1
|
||||||
|
|
||||||
|
@ -127,40 +164,51 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
|
|
||||||
private fun analyzePacketSignal(): List<Int> {
|
private fun analyzePacketSignal(): List<Int> {
|
||||||
val cleanedSignal = cleanSignal(signal)
|
val cleanedSignal = cleanSignal(signal)
|
||||||
val compressedSignal = compressSignal(cleanedSignal)
|
|
||||||
|
|
||||||
if (compressedSignal.size < 2) {
|
var maxSamplesInARow = 0
|
||||||
return listOf()
|
var count = 0
|
||||||
}
|
cleanedSignal.forEachIndexed { index, sample ->
|
||||||
|
if(index == 0) {
|
||||||
val timeDifferences = ArrayList<Long>()
|
|
||||||
compressedSignal.forEachIndexed { index, sample ->
|
|
||||||
if (index == 0) {
|
|
||||||
return@forEachIndexed
|
return@forEachIndexed
|
||||||
}
|
}
|
||||||
|
|
||||||
timeDifferences.add(sample.timestamp - compressedSignal[index - 1].timestamp)
|
if(sample.value == cleanedSignal[index - 1].value) {
|
||||||
|
count ++
|
||||||
|
if(count > maxSamplesInARow) {
|
||||||
|
maxSamplesInARow = count
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
count = 0
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val clockTimeThreshold = 900//timeDifferences.max() * 0.75
|
|
||||||
|
|
||||||
val packetData = ArrayList<Int>()
|
val packetData = ArrayList<Int>()
|
||||||
compressedSignal.forEachIndexed { index, sample ->
|
var lastSignal: Sample<Signal>? = null
|
||||||
if (index == 0) {
|
var isFirstSignal = true
|
||||||
return@forEachIndexed
|
var samplesSinceLastSignal = 0
|
||||||
|
cleanedSignal.forEach { sample ->
|
||||||
|
if (lastSignal == null) {
|
||||||
|
lastSignal = sample
|
||||||
}
|
}
|
||||||
|
|
||||||
val timeDifference = sample.timestamp - compressedSignal[index - 1].timestamp
|
if (sample.value != lastSignal!!.value) {
|
||||||
if (timeDifference > clockTimeThreshold && timeDifference < 2500) {
|
if(samplesSinceLastSignal > (maxSamplesInARow * 0.75) || isFirstSignal) {
|
||||||
if (sample.value == Signal.High) {
|
//Log.i(TAG, "$samplesSinceLastSignal")
|
||||||
packetData.add(0)
|
if (sample.value == Signal.High) {
|
||||||
} else {
|
packetData.add(0)
|
||||||
packetData.add(1)
|
} else {
|
||||||
|
packetData.add(1)
|
||||||
|
}
|
||||||
|
isFirstSignal = false
|
||||||
|
samplesSinceLastSignal=0
|
||||||
}
|
}
|
||||||
|
lastSignal = sample
|
||||||
}
|
}
|
||||||
|
samplesSinceLastSignal++
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.i(TAG, "$timeDifferences")
|
|
||||||
//Log.i(TAG, "$cleanSignal")
|
//Log.i(TAG, "$cleanSignal")
|
||||||
|
|
||||||
return packetData
|
return packetData
|
||||||
|
@ -171,15 +219,12 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
samples.add(Sample(magneticFieldStrength))
|
samples.add(Sample(magneticFieldStrength))
|
||||||
|
|
||||||
// Determine whether the sample is a high or low signal
|
// Determine whether the sample is a high or low signal
|
||||||
val currentSignal: Sample<Signal> = if (isHigh(magneticFieldStrength)) {
|
val currentSignal = getSignalForSample(samples.last()) ?: return
|
||||||
Sample(Signal.High)
|
|
||||||
} else {
|
|
||||||
Sample(Signal.Low)
|
|
||||||
}
|
|
||||||
signal.add(currentSignal)
|
signal.add(currentSignal)
|
||||||
|
|
||||||
// Try to detect the preamble in the signal
|
// Try to detect the preamble in the signal
|
||||||
if (!preambleReceived) {
|
if (!preambleReceived) {
|
||||||
|
// If we detect the preamble we change the status on the screen and clear the existing signal data.
|
||||||
if (detectPreamble()) {
|
if (detectPreamble()) {
|
||||||
preambleReceived = true
|
preambleReceived = true
|
||||||
preambleStatus.setText(R.string.preamble_status_detected)
|
preambleStatus.setText(R.string.preamble_status_detected)
|
||||||
|
@ -189,9 +234,12 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// After the preamble is detected we attempt to decode the packet.
|
||||||
if (preambleReceived) {
|
if (preambleReceived) {
|
||||||
val packet = analyzePacketSignal();
|
// Get the decoded packet data
|
||||||
|
val packet = analyzePacketSignal()
|
||||||
|
|
||||||
|
// Get the payload length of in the data
|
||||||
var payloadLength = 0
|
var payloadLength = 0
|
||||||
if (packet.size >= 4) {
|
if (packet.size >= 4) {
|
||||||
payloadLength = listToInteger(packet.take(4))
|
payloadLength = listToInteger(packet.take(4))
|
||||||
|
@ -207,6 +255,7 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
|
|
||||||
receiveValue.text = payload
|
receiveValue.text = payload
|
||||||
|
|
||||||
|
// TODO: CRC show and calculate if it's correct
|
||||||
if (packet.size >= 4 + (8 * payloadLength) + 8) {
|
if (packet.size >= 4 + (8 * payloadLength) + 8) {
|
||||||
// CRC Check
|
// CRC Check
|
||||||
val crc = listToInteger(packet.take(4 + (8 * payloadLength) + 8).takeLast(8))
|
val crc = listToInteger(packet.take(4 + (8 * payloadLength) + 8).takeLast(8))
|
||||||
|
@ -217,7 +266,7 @@ class ReceiveActivity : BaseSensorActivity() {
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun listToInteger(values: List<Int>): Int {
|
private fun listToInteger(values: List<Int>): Int {
|
||||||
var value: Int = 0
|
var value = 0
|
||||||
|
|
||||||
for (bit in values) {
|
for (bit in values) {
|
||||||
value = (value shl 1) + bit
|
value = (value shl 1) + bit
|
||||||
|
|
Reference in a new issue