diff --git a/src/MagSend/app/src/main/java/dev/kaderli/magsend/Utility.kt b/src/MagSend/app/src/main/java/dev/kaderli/magsend/Utility.kt new file mode 100644 index 0000000..5c7d2b3 --- /dev/null +++ b/src/MagSend/app/src/main/java/dev/kaderli/magsend/Utility.kt @@ -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 { + 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; + } + } + + +} diff --git a/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/BaseSensorActivity.kt b/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/BaseSensorActivity.kt index 427fc40..85fb35b 100644 --- a/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/BaseSensorActivity.kt +++ b/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/BaseSensorActivity.kt @@ -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) } diff --git a/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/ReceiveActivity.kt b/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/ReceiveActivity.kt index 491ed65..b7368ae 100644 --- a/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/ReceiveActivity.kt +++ b/src/MagSend/app/src/main/java/dev/kaderli/magsend/activity/ReceiveActivity.kt @@ -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() var lastSignal: Sample? = 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() } diff --git a/src/MagSend/app/src/main/res/layout/activity_receive.xml b/src/MagSend/app/src/main/res/layout/activity_receive.xml index 0a9eb9e..40aef03 100644 --- a/src/MagSend/app/src/main/res/layout/activity_receive.xml +++ b/src/MagSend/app/src/main/res/layout/activity_receive.xml @@ -8,7 +8,7 @@ @@ -40,21 +40,31 @@ app:layout_constraintTop_toBottomOf="@+id/preambleStatus" /> + + - #FFFF0000 - #FF00FF00 + #FFFF5454 + #FF4BB543 diff --git a/src/MagSend/app/src/main/res/values/dimens.xml b/src/MagSend/app/src/main/res/values/dimens.xml index 3064a82..b8e7bdc 100644 --- a/src/MagSend/app/src/main/res/values/dimens.xml +++ b/src/MagSend/app/src/main/res/values/dimens.xml @@ -4,4 +4,5 @@ 24dp 48sp 8dp + 48dp diff --git a/src/MagSend/app/src/main/res/values/strings.xml b/src/MagSend/app/src/main/res/values/strings.xml index 1d4e639..6856c5c 100644 --- a/src/MagSend/app/src/main/res/values/strings.xml +++ b/src/MagSend/app/src/main/res/values/strings.xml @@ -5,7 +5,7 @@ Receive Calibrate 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. - Currently listening for transmissions. The text that was received so far is displayed below. + Currently listening for transmissions.\nThe text that was received so far is displayed below. To start listening to a new message click the following button. Restart Calibration @@ -14,4 +14,7 @@ Preamble not detected X Preamble detected ✓ The payload length is %1$d bytes + The transmission is completed.\nThe received text is displayed below. + The checksum is valid ✓. + The checksum is invalid X.