Clean up some strings and show checksum check
Signed-off-by: Severin Kaderli <severin@kaderli.dev>
This commit is contained in:
parent
308104f321
commit
1a221761b8
7 changed files with 118 additions and 27 deletions
51
src/MagSend/app/src/main/java/dev/kaderli/magsend/Utility.kt
Normal file
51
src/MagSend/app/src/main/java/dev/kaderli/magsend/Utility.kt
Normal 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;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -27,6 +27,7 @@ abstract class BaseSensorActivity : BaseActivity(), SensorEventListener {
|
|||
override fun onAccuracyChanged(sensor: Sensor?, accuracy: Int) {}
|
||||
|
||||
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))
|
||||
sensorValueReceived(magneticFieldStrength)
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
package dev.kaderli.magsend.activity
|
||||
|
||||
import android.os.Bundle
|
||||
import android.util.Log
|
||||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.ContextCompat
|
||||
import dev.kaderli.magsend.R
|
||||
import dev.kaderli.magsend.Utility
|
||||
import dev.kaderli.magsend.model.Sample
|
||||
import dev.kaderli.magsend.model.Signal
|
||||
import java.lang.Integer.min
|
||||
import java.util.stream.Collectors
|
||||
|
||||
class ReceiveActivity : BaseSensorActivity() {
|
||||
private lateinit var receiveDescription: TextView
|
||||
private lateinit var preambleStatus: TextView
|
||||
private lateinit var crcStatus: TextView
|
||||
private lateinit var headerStatus: TextView
|
||||
private lateinit var receiveValue: TextView
|
||||
|
||||
|
@ -30,9 +33,13 @@ class ReceiveActivity : BaseSensorActivity() {
|
|||
*/
|
||||
private var preambleReceived = false
|
||||
|
||||
private var receivingComplete = false
|
||||
|
||||
override fun onCreate(savedInstanceState: Bundle?) {
|
||||
super.onCreate(savedInstanceState)
|
||||
receiveDescription = findViewById(R.id.receiveDescription)
|
||||
preambleStatus = findViewById(R.id.preambleStatus)
|
||||
crcStatus = findViewById(R.id.crcStatus)
|
||||
headerStatus = findViewById(R.id.headerStatus)
|
||||
receiveValue = findViewById(R.id.receiveValue)
|
||||
}
|
||||
|
@ -168,13 +175,13 @@ class ReceiveActivity : BaseSensorActivity() {
|
|||
var maxSamplesInARow = 0
|
||||
var count = 0
|
||||
cleanedSignal.forEachIndexed { index, sample ->
|
||||
if(index == 0) {
|
||||
if (index == 0) {
|
||||
return@forEachIndexed
|
||||
}
|
||||
|
||||
if(sample.value == cleanedSignal[index - 1].value) {
|
||||
count ++
|
||||
if(count > maxSamplesInARow) {
|
||||
if (sample.value == cleanedSignal[index - 1].value) {
|
||||
count++
|
||||
if (count > maxSamplesInARow) {
|
||||
maxSamplesInARow = count
|
||||
}
|
||||
} else {
|
||||
|
@ -182,7 +189,6 @@ class ReceiveActivity : BaseSensorActivity() {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
val packetData = ArrayList<Int>()
|
||||
var lastSignal: Sample<Signal>? = null
|
||||
var isFirstSignal = true
|
||||
|
@ -193,28 +199,28 @@ class ReceiveActivity : BaseSensorActivity() {
|
|||
}
|
||||
|
||||
if (sample.value != lastSignal!!.value) {
|
||||
if(samplesSinceLastSignal > (maxSamplesInARow * 0.75) || isFirstSignal) {
|
||||
//Log.i(TAG, "$samplesSinceLastSignal")
|
||||
if (samplesSinceLastSignal > (maxSamplesInARow * 0.75) || isFirstSignal) {
|
||||
if (sample.value == Signal.High) {
|
||||
packetData.add(0)
|
||||
} else {
|
||||
packetData.add(1)
|
||||
}
|
||||
isFirstSignal = false
|
||||
samplesSinceLastSignal=0
|
||||
samplesSinceLastSignal = 0
|
||||
}
|
||||
lastSignal = sample
|
||||
}
|
||||
samplesSinceLastSignal++
|
||||
}
|
||||
|
||||
|
||||
//Log.i(TAG, "$cleanSignal")
|
||||
|
||||
return packetData
|
||||
}
|
||||
|
||||
override fun sensorValueReceived(magneticFieldStrength: Float) {
|
||||
if (receivingComplete) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the current received sensor value to the samples
|
||||
samples.add(Sample(magneticFieldStrength))
|
||||
|
||||
|
@ -252,14 +258,26 @@ class ReceiveActivity : BaseSensorActivity() {
|
|||
for (i in 1..numberOfAvailablePayloadBytes) {
|
||||
payload += listToInteger(packet.take(4 + (8 * i)).takeLast(8)).toChar().toString()
|
||||
}
|
||||
|
||||
receiveValue.text = payload
|
||||
|
||||
// TODO: CRC show and calculate if it's correct
|
||||
if (packet.size >= 4 + (8 * payloadLength) + 8) {
|
||||
// CRC Check
|
||||
val crc = listToInteger(packet.take(4 + (8 * payloadLength) + 8).takeLast(8))
|
||||
Log.i(TAG, "CRC: $crc")
|
||||
val receivedCrc = listToInteger(packet.take(4 + (8 * payloadLength) + 8).takeLast(8))
|
||||
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) {
|
||||
preambleReceived = false
|
||||
receivingComplete = false
|
||||
|
||||
receiveDescription.setText(R.string.receive_description)
|
||||
preambleStatus.setText(R.string.preamble_status_not_detected)
|
||||
preambleStatus.setTextColor(ContextCompat.getColor(this, R.color.error))
|
||||
headerStatus.text = ""
|
||||
crcStatus.text = ""
|
||||
receiveValue.text = ""
|
||||
|
||||
samples.clear()
|
||||
signal.clear()
|
||||
}
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
|
||||
<TextView
|
||||
android:id="@+id/receiveDescription"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/layout_margins"
|
||||
android:paddingHorizontal="@dimen/layout_margins"
|
||||
|
@ -21,10 +21,10 @@
|
|||
android:id="@+id/preambleStatus"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/component_spacing_small"
|
||||
android:layout_marginTop="@dimen/component_spacing"
|
||||
android:paddingHorizontal="@dimen/layout_margins"
|
||||
android:text="@string/preamble_status_not_detected"
|
||||
android:textColor="#FF0000"
|
||||
android:textColor="@color/error"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/receiveDescription" />
|
||||
|
@ -40,21 +40,31 @@
|
|||
app:layout_constraintTop_toBottomOf="@+id/preambleStatus" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/receiveValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:id="@+id/crcStatus"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="@dimen/component_spacing"
|
||||
android:text="___"
|
||||
android:textSize="48sp"
|
||||
android:layout_marginTop="@dimen/component_spacing_small"
|
||||
android:paddingHorizontal="@dimen/layout_margins"
|
||||
android:textColor="@color/success"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toBottomOf="@+id/headerStatus" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/restartDescription"
|
||||
android:id="@+id/receiveValue"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
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:text="@string/restart_description"
|
||||
app:layout_constraintEnd_toEndOf="parent"
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="error">#FFFF0000</color>
|
||||
<color name="success">#FF00FF00</color>
|
||||
<color name="error">#FFFF5454</color>
|
||||
<color name="success">#FF4BB543</color>
|
||||
</resources>
|
||||
|
|
|
@ -4,4 +4,5 @@
|
|||
<dimen name="component_spacing">24dp</dimen>
|
||||
<dimen name="title_text_size">48sp</dimen>
|
||||
<dimen name="component_spacing_small">8dp</dimen>
|
||||
<dimen name="component_spacing_large">48dp</dimen>
|
||||
</resources>
|
||||
|
|
|
@ -5,7 +5,7 @@
|
|||
<string name="receive_button_label">Receive</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="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_button_label">Restart</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_detected">Preamble detected ✓</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>
|
||||
|
|
Reference in a new issue