Clean up some strings and show checksum check

Signed-off-by: Severin Kaderli <severin@kaderli.dev>
This commit is contained in:
Severin Kaderli 2023-01-04 22:41:05 +01:00
parent 308104f321
commit 1a221761b8
Signed by: severinkaderli
GPG key ID: F419F8835B72F0C4
7 changed files with 118 additions and 27 deletions

View file

@ -0,0 +1,51 @@
package dev.kaderli.magsend
class Utility {
companion object {
/**
* Calculates the CRC-8-AUTOSAR checksum of the given array of bytes.
*
* This code is based on the code examples from the following page:
* http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html
*
* The specifics of the algorithm is coming from the AUTOSAR CRC specification:
* https://www.autosar.org/fileadmin/user_upload/standards/classic/21-11/AUTOSAR_SWS_CRCLibrary.pdf
*
* > Utility.crc8Autosar(arrayListOf(0x0, 0x0, 0x0, 0x0)).toString(16)
* "12"
* > Utility.crc8Autosar(arrayListOf(0xF2, 0x01, 0x83)).toString(16)
* "c2"
* > Utility.crc8Autosar(arrayListOf(0x0F, 0xAA, 0x00, 0x55)).toString(16)
* "c6"
* > Utility.crc8Autosar(arrayListOf(0x00, 0xff, 0x55, 0x11)).toString(16)
* "77"
* > Utility.crc8Autosar(arrayListOf(0x33, 0x22, 0x55, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff)).toString(16)
* "11"
* > Utility.crc8Autosar(arrayListOf(0x92, 0x6b, 0x55)).toString(16)
* "33"
* > Utility.crc8Autosar(arrayListOf(0xff, 0xff, 0xff, 0xff)).toString(16)
* "6c"
*/
fun crc8Autosar(bytes: List<Int>): Int {
val polynomial = 0x2f;
val xorOut = 0xff;
var crc = 0xff;
for (byte in bytes) {
crc = crc xor byte;
for(i in 1..8) {
crc = if ((crc and 0x80) != 0) {
((crc shl 1) xor polynomial) and 0xff;
} else {
crc shl 1
}
}
}
return crc xor xorOut;
}
}
}

View file

@ -27,6 +27,7 @@ abstract class BaseSensorActivity : BaseActivity(), SensorEventListener {
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {} override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
override fun onSensorChanged(event: SensorEvent) { override fun onSensorChanged(event: SensorEvent) {
// Calculate the absolute magnetic field strength
val magneticFieldStrength = sqrt(event.values[0].pow(2) + event.values[1].pow(2) + event.values[2].pow(2)) val magneticFieldStrength = sqrt(event.values[0].pow(2) + event.values[1].pow(2) + event.values[2].pow(2))
sensorValueReceived(magneticFieldStrength) sensorValueReceived(magneticFieldStrength)
} }

View file

@ -1,17 +1,20 @@
package dev.kaderli.magsend.activity package dev.kaderli.magsend.activity
import android.os.Bundle import android.os.Bundle
import android.util.Log
import android.view.View import android.view.View
import android.widget.TextView import android.widget.TextView
import androidx.core.content.ContextCompat import androidx.core.content.ContextCompat
import dev.kaderli.magsend.R import dev.kaderli.magsend.R
import dev.kaderli.magsend.Utility
import dev.kaderli.magsend.model.Sample import dev.kaderli.magsend.model.Sample
import dev.kaderli.magsend.model.Signal import dev.kaderli.magsend.model.Signal
import java.lang.Integer.min import java.lang.Integer.min
import java.util.stream.Collectors
class ReceiveActivity : BaseSensorActivity() { class ReceiveActivity : BaseSensorActivity() {
private lateinit var receiveDescription: TextView
private lateinit var preambleStatus: TextView private lateinit var preambleStatus: TextView
private lateinit var crcStatus: TextView
private lateinit var headerStatus: TextView private lateinit var headerStatus: TextView
private lateinit var receiveValue: TextView private lateinit var receiveValue: TextView
@ -30,9 +33,13 @@ class ReceiveActivity : BaseSensorActivity() {
*/ */
private var preambleReceived = false private var preambleReceived = false
private var receivingComplete = false
override fun onCreate(savedInstanceState: Bundle?) { override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState) super.onCreate(savedInstanceState)
receiveDescription = findViewById(R.id.receiveDescription)
preambleStatus = findViewById(R.id.preambleStatus) preambleStatus = findViewById(R.id.preambleStatus)
crcStatus = findViewById(R.id.crcStatus)
headerStatus = findViewById(R.id.headerStatus) headerStatus = findViewById(R.id.headerStatus)
receiveValue = findViewById(R.id.receiveValue) receiveValue = findViewById(R.id.receiveValue)
} }
@ -168,13 +175,13 @@ class ReceiveActivity : BaseSensorActivity() {
var maxSamplesInARow = 0 var maxSamplesInARow = 0
var count = 0 var count = 0
cleanedSignal.forEachIndexed { index, sample -> cleanedSignal.forEachIndexed { index, sample ->
if(index == 0) { if (index == 0) {
return@forEachIndexed return@forEachIndexed
} }
if(sample.value == cleanedSignal[index - 1].value) { if (sample.value == cleanedSignal[index - 1].value) {
count ++ count++
if(count > maxSamplesInARow) { if (count > maxSamplesInARow) {
maxSamplesInARow = count maxSamplesInARow = count
} }
} else { } else {
@ -182,7 +189,6 @@ class ReceiveActivity : BaseSensorActivity() {
} }
} }
val packetData = ArrayList<Int>() val packetData = ArrayList<Int>()
var lastSignal: Sample<Signal>? = null var lastSignal: Sample<Signal>? = null
var isFirstSignal = true var isFirstSignal = true
@ -193,28 +199,28 @@ class ReceiveActivity : BaseSensorActivity() {
} }
if (sample.value != lastSignal!!.value) { if (sample.value != lastSignal!!.value) {
if(samplesSinceLastSignal > (maxSamplesInARow * 0.75) || isFirstSignal) { if (samplesSinceLastSignal > (maxSamplesInARow * 0.75) || isFirstSignal) {
//Log.i(TAG, "$samplesSinceLastSignal")
if (sample.value == Signal.High) { if (sample.value == Signal.High) {
packetData.add(0) packetData.add(0)
} else { } else {
packetData.add(1) packetData.add(1)
} }
isFirstSignal = false isFirstSignal = false
samplesSinceLastSignal=0 samplesSinceLastSignal = 0
} }
lastSignal = sample lastSignal = sample
} }
samplesSinceLastSignal++ samplesSinceLastSignal++
} }
//Log.i(TAG, "$cleanSignal")
return packetData return packetData
} }
override fun sensorValueReceived(magneticFieldStrength: Float) { override fun sensorValueReceived(magneticFieldStrength: Float) {
if (receivingComplete) {
return;
}
// Add the current received sensor value to the samples // Add the current received sensor value to the samples
samples.add(Sample(magneticFieldStrength)) samples.add(Sample(magneticFieldStrength))
@ -252,14 +258,26 @@ class ReceiveActivity : BaseSensorActivity() {
for (i in 1..numberOfAvailablePayloadBytes) { for (i in 1..numberOfAvailablePayloadBytes) {
payload += listToInteger(packet.take(4 + (8 * i)).takeLast(8)).toChar().toString() payload += listToInteger(packet.take(4 + (8 * i)).takeLast(8)).toChar().toString()
} }
receiveValue.text = payload receiveValue.text = payload
// TODO: CRC show and calculate if it's correct // 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 receivedCrc = listToInteger(packet.take(4 + (8 * payloadLength) + 8).takeLast(8))
Log.i(TAG, "CRC: $crc") val calculatedCrc =
Utility.crc8Autosar(receiveValue.text.codePoints().boxed().collect(Collectors.toList()))
if (receivedCrc == calculatedCrc) {
crcStatus.setText(R.string.crc_status_valid)
crcStatus.setTextColor(ContextCompat.getColor(this, R.color.success))
} else {
crcStatus.setText(R.string.crc_status_invalid)
crcStatus.setTextColor(ContextCompat.getColor(this, R.color.error))
}
// Mark receiving as complete
receiveDescription.setText(R.string.receive_description_complete)
receivingComplete = true
} }
} }
} }
@ -278,8 +296,15 @@ class ReceiveActivity : BaseSensorActivity() {
fun restartReceiveProcess(view: View) { fun restartReceiveProcess(view: View) {
preambleReceived = false preambleReceived = false
receivingComplete = false
receiveDescription.setText(R.string.receive_description)
preambleStatus.setText(R.string.preamble_status_not_detected) preambleStatus.setText(R.string.preamble_status_not_detected)
preambleStatus.setTextColor(ContextCompat.getColor(this, R.color.error)) preambleStatus.setTextColor(ContextCompat.getColor(this, R.color.error))
headerStatus.text = ""
crcStatus.text = ""
receiveValue.text = ""
samples.clear() samples.clear()
signal.clear() signal.clear()
} }

View file

@ -8,7 +8,7 @@
<TextView <TextView
android:id="@+id/receiveDescription" android:id="@+id/receiveDescription"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/layout_margins" android:layout_marginTop="@dimen/layout_margins"
android:paddingHorizontal="@dimen/layout_margins" android:paddingHorizontal="@dimen/layout_margins"
@ -21,10 +21,10 @@
android:id="@+id/preambleStatus" android:id="@+id/preambleStatus"
android:layout_width="0dp" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/component_spacing_small" android:layout_marginTop="@dimen/component_spacing"
android:paddingHorizontal="@dimen/layout_margins" android:paddingHorizontal="@dimen/layout_margins"
android:text="@string/preamble_status_not_detected" android:text="@string/preamble_status_not_detected"
android:textColor="#FF0000" android:textColor="@color/error"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/receiveDescription" /> app:layout_constraintTop_toBottomOf="@+id/receiveDescription" />
@ -40,21 +40,31 @@
app:layout_constraintTop_toBottomOf="@+id/preambleStatus" /> app:layout_constraintTop_toBottomOf="@+id/preambleStatus" />
<TextView <TextView
android:id="@+id/receiveValue" android:id="@+id/crcStatus"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/component_spacing" android:layout_marginTop="@dimen/component_spacing_small"
android:text="___" android:paddingHorizontal="@dimen/layout_margins"
android:textSize="48sp" android:textColor="@color/success"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/headerStatus" /> app:layout_constraintTop_toBottomOf="@+id/headerStatus" />
<TextView <TextView
android:id="@+id/restartDescription" android:id="@+id/receiveValue"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginTop="@dimen/component_spacing" android:layout_marginTop="@dimen/component_spacing"
android:textSize="48sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/crcStatus" />
<TextView
android:id="@+id/restartDescription"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="@dimen/component_spacing_large"
android:paddingHorizontal="@dimen/layout_margins" android:paddingHorizontal="@dimen/layout_margins"
android:text="@string/restart_description" android:text="@string/restart_description"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"

View file

@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="error">#FFFF0000</color> <color name="error">#FFFF5454</color>
<color name="success">#FF00FF00</color> <color name="success">#FF4BB543</color>
</resources> </resources>

View file

@ -4,4 +4,5 @@
<dimen name="component_spacing">24dp</dimen> <dimen name="component_spacing">24dp</dimen>
<dimen name="title_text_size">48sp</dimen> <dimen name="title_text_size">48sp</dimen>
<dimen name="component_spacing_small">8dp</dimen> <dimen name="component_spacing_small">8dp</dimen>
<dimen name="component_spacing_large">48dp</dimen>
</resources> </resources>

View file

@ -5,7 +5,7 @@
<string name="receive_button_label">Receive</string> <string name="receive_button_label">Receive</string>
<string name="calibrate_button_label">Calibrate</string> <string name="calibrate_button_label">Calibrate</string>
<string name="calibration_description">Open up the website and start the calibration mode. Put your Smartphone on different locations on the sending device and note the value below. The location with the highest value is the most optimal for data transmission.</string> <string name="calibration_description">Open up the website and start the calibration mode. Put your Smartphone on different locations on the sending device and note the value below. The location with the highest value is the most optimal for data transmission.</string>
<string name="receive_description">Currently listening for transmissions. The text that was received so far is displayed below.</string> <string name="receive_description">Currently listening for transmissions.\nThe text that was received so far is displayed below.</string>
<string name="restart_description">To start listening to a new message click the following button.</string> <string name="restart_description">To start listening to a new message click the following button.</string>
<string name="restart_button_label">Restart</string> <string name="restart_button_label">Restart</string>
<string name="calibration_activity_label">Calibration</string> <string name="calibration_activity_label">Calibration</string>
@ -14,4 +14,7 @@
<string name="preamble_status_not_detected">Preamble not detected X</string> <string name="preamble_status_not_detected">Preamble not detected X</string>
<string name="preamble_status_detected">Preamble detected ✓</string> <string name="preamble_status_detected">Preamble detected ✓</string>
<string name="payload_length">The payload length is %1$d bytes</string> <string name="payload_length">The payload length is %1$d bytes</string>
<string name="receive_description_complete">The transmission is completed.\nThe received text is displayed below.</string>
<string name="crc_status_valid">The checksum is valid ✓.</string>
<string name="crc_status_invalid">The checksum is invalid X.</string>
</resources> </resources>