Documentation | Spandan SDK v1.0.22
Installation: #
implementation("in.sunfox.healthcare.commons.android.spandan-sdk:spandan_sdk:1.0.22")
implementation("in.sunfox.healthcare.commons.java.ecg-processor:conclusions:2.0.34")
implementation("in.sunfox.healthcare.commons.java.ecg-processor:core:2.0.34")
NOTE: AGP version should be 7.4.0 or higher
Repository setup and authentication: #
Add below code in your settings.gradle file.
maven {
url 'https://maven.pkg.github.com/sunfox-technologies/spandan_ecg_android_sdk'
credentials {
username <Authorisation Token>
password <Authorisation Token>
}
}
Initialization: #
Initialize the Spandan SDK by creating an object in Application class.
onCreate(){
super.onCreate()
SpandanSDK.initialize(application:Application,masterKey:String,onInitializationCompleteListener:OnInitializationCompleteListener);
}
NOTE: masterKey is provided by Sunfox technologies.
Initialize the connection #
Bind device connection handler with the sdk by calling bind() inside the onCreate method of Application class:
onCreate(){
super.onCreate();
val spnSdk = SpandanSDK.getInstance();
spnSdk.bind(this);
}
Else throw TokenNotValidException, TokenExpiredException
Register Spandan Device Interface: #
Register setOnDeviceConnectionStateChangeListener to get a callback whenever the Spandan device’s connection state changes.
Register listener in Application class.
onCreate(){
super.onCreate();
val spnSdk = SpandanSDK.getInstance(); spnSdk.setOnDeviceConnectionStateChangeListener(listener:OnDeviceConnectionStateChangeListener);
}
OnDeviceConnectionStateChangeListener is defined as:
interface OnDeviceConnectionStateChangeListener {
fun onDeviceConnectionStateChanged(deviceConnectionState: DeviceConnectionState)
fun onDeviceTypeChange(deviceType:String)
fun onDeviceVerified(deviceInfo:DeviceInfo)
DeviceConnectionState is an enum that contains different states defined as:
enum class DeviceConnectionState {
CONNECTED,
DISCONNECTED,
VERIFICATION_TIME_OUT,
USB_CONNECTION_PERMISSION_DENIED
}
Create Test: #
For each test, an object of EcgTest need to be created, taking test type in the parameter,authToken and an instance of EcgTestCallback. The different options in EcgTestType are EcgTestType.LEAD_TWO.
NOTE: authToken is generated via the api
val leadTwoTest:EcgTest = spnSdk.createTest(testType:EcgTestType,authToken:String,callback:EcgTestCallback);
EcgTestCallback is defined as:
interface EcgTestCallback {
fun onTestFailed(statusCode:Int)
fun onTestStarted(ecgPosition: EcgPosition)
fun onElapsedTimeChanged(elapsedTime: Long, remainingTime: Long)
fun onReceivedData(data: String)
fun onPositionRecordingComplete(ecgPosition: EcgPosition, ecgPoints: ArrayList<Double>?)
}
Test failure codes:
1 -> Ecg data is not valid
2 -> Test canceled by the user
3 -> Device disconnected during the test
Start ecg test: #
Simply call the start method of EcgTest class to start a test. ECG Position can be specified through EcgPosition enum in the method for which the test is being started. Follow the below steps to start the ECG test according to the device.
For Spandan Legacy and Spandan Neo:
ecgTest.start(position:EcgPosition);
For Spandan Pro:
//Step 1. Initialize the lead
ecgTest.initializeLead(position:EcgPosition);
//Step 2. Start the test
ecgTest.start(position:EcgPosition);
Note: Add the delay of 3 seconds between steps 1 and 2 in the case of Spandan Pro.
EcgPosition is the enum for the lead position defined as:
enum class EcgPosition {
V1,
V2,
V3,
V4,
V5,
V6,
LEAD_1,
LEAD_2
}
Collect the ecg data: #
When a particular ecg lead reading is completed. You can retrieve ECG data from onPositionRecordingComplete callback method in EcgTestCallback.
Override the method onPositionRecordingComplete of EcgTestCallback to retrieve the ECG data for the test when the test completes.
fun onPositionRecordingComplete(ecgPosition: EcgPosition, ecgPoints: ArrayList<Double>?)
Collect ECG data point in real-time: #
Override the method fun onReceivedData of EcgTestCallback to get ECG data in realtime from the device.
fun onReceivedData(data: String)
NOTE: onPositionRecordingComplete gives the overall data of the test. Use onReceivedData method only if you want to plot the live data on the screen or any other use case where live data need to be used.
Cancel ecg test: #
To cancel the ongoing test, call the cancel method of EcgTest class on the test instance.
ecgTest.cancel();
Generate Report: #
To generate report, call the generateReport method of SpandanSDK class. The method takes age, ECG data and an object of OnReportGenerationStateListener as parameters.
spnSdk.generateReport(age:Int, ecgData:HashMap<EcgPosition,ArrayList<Double>>,listener:OnReportGenerationStateListener);
Where ecgData is a HashMap<EcgPosition,ArrayList<Double>> that maps ECG data to position and OnReportGenerationStateListener is defined as:
interface OnReportGenerationStateListener{
void onReportGenerationSuccess(ecgReport: EcgReport);
void onReportGenerationFailead(errorCode:Int, errorMsg:String);
}
And EcgReport is defined as:
data class EcgReport(
val reportType: EcgTestType,
var timeStamp: String,
val ecgCharacteristics: Characteristics,
var conclusion: Conclusion,
var ecgData: EcgData,
var sdkVersion: String):Serializable
NOTE: Conclusion is an abstract class. Therefore it needs to be casted to a proper Subclass i.e. LeadTwoConclusion or TwelveLeadConclusion for Lead Two and Twelve lead test respectively.
Eg: If the test is Lead Two,
val leadTwoEcgReport:EcgReport = spnSdk.generateReport(.....)
val leadTwoConclusion = leadTwoEcgReport.conclusion as LeadTwoConclusion
If the test is Twelve lead,
val twelveLeadEcgReport:EcgReport = spnSdk.generateReport(.....)
val twelveLeadConclusion = twelveLeadEcgReport.conclusion as TwelveLeadConclusion
TwelveLeadConclusion is defined as:
class TwelveLeadConclusion(
val detection: String,
val ecgType: String,
val recommendation: String,
val anomalies: String,
val risk: Risk) : Conclusion()
LeadTwoConclusion is defined as:
class LeadTwoConclusion(
val detection: String,
val ecgType: String,
val qrsType: String,
val pWaveType: String,
val baselineWandering: Boolean,
val powerLineInterference: Boolean): Conclusion()
Characteristics is defined as:
class Characteristics(
var pr: Int,
var qrs: Int,
var qt: Int,
var qtc: Double,
var rr: Int,
var heartRate: Int,
var stElevation: Double,
var qrsIntervals: ArrayList<Double>,
var rrIntervals: ArrayList<Double>,
var prStopIndices: ArrayList<Double>,
var prStartIndices: ArrayList<Double>,
var pWavePoints: ArrayList<Double>,
var qWavePoints: ArrayList<Double>,
var sWavePoints: ArrayList<Double>,
var tWavePoints: ArrayList<Double>,
var rPeakPoints: ArrayList<Double>,
var tWaveEndPoints: ArrayList<Double>,
var averagePAmplitudeInLead: Double,
var averageQAmplitudeInLead: Double,
var averageSAmplitudeInLead: Double,
var averageTAmplitudeInLead: Double,
var averageRAmplitudeInLead: Double,
var pWidth: Double,
var tWidth: Double,
var qrsDirectionUpward:Boolean,
var ratioRS: Double,
var ventricularActivationLOR: Double,
var ventricularActivationROR: Double,
var concavity: Boolean,
var frequencyOfPatternInQRS: Int,
var frequencyOfPatternInRR: Int,
var pAmplitudeArrayInMv: ArrayList<Double>,
var TRRatioSatisfy:Boolean,
var TSRatioSatisfy:Boolean,) : Serializable
Example for populating ecgData HashMap: #
private var ecgData:HashMap<EcgPosition,ArrayList<Double>>=hashMapOf()
override fun onPositionRecordingComplete(ecgPosition:EcgPosition , ecgPoints: ArrayList<Double>?) { ecgPoints.let {
if (it != null){ ecgData[ecgPosition] = it } }}
Unbind #
Unbind the device connection with the sdk by calling unbind method on the onDestroy of the activity:
spnSdk.unbind(application:Application);