Installation: #
implementation("in.sunfox.healthcare.commons.android:spandan_sdk:1.0.0-beta9")
Repository setup and authentication: #
maven {
url 'https://sunfox-in-040487387791.d.codeartifact.ap-south-1.amazonaws.com/maven/spandan-android-sdk-repository'
credentials {
username "spandan_sdk_beta"
password <Authorisation Token>
}
}
Authorisation token generation: #
Get authorisation token by making a GET request on the following REST endpoint with necessary headers
ENDPOINT: https://api.sunfox.in/v3/artifact
Headers: #
Key: x-api-key
Value: <provided separately>
NOTE: Token will be refreshed in every 12 hours(find reference in the document), if you are building APK please generate fresh token using the API keyInitialization: #
Initialize the Spandan SDK by creating an object.
val spnSdk:SpandanSdk = SpandanSdk.getInstance(offlineToken:String);
Initialise the connection #
Bind device connection handler with the sdk by calling bind() inside the onCreate method:
onCreate(){
super.onCreate();
spnSdk.initialize(applicationContext:ApplicationContext);
}
Else throw TokenNotValidException, TokenExpiredException
Authenticate #
Set company name and ecg test required by calling following methods in onCreate method:
onCreate(){
super.onCreate();
spnSdk.setEcgTests(arrayOf(EcgTestType.LEAD_TWO…));
}
Register Spandan Device Interface: #
Register setOnDeviceConnectionStateChangeListener to get a callback whenever the Spandan device’s connection state changes.
spnSdk.setOnDeviceConnectionStateChangeListener(listener:OnDeviceConnectionStateChangeListener);
OnDeviceConnectionStateChangeListener is defined as:
interface OnDeviceConnectionStateChangeListener {
fun onDeviceConnectionStateChanged(deviceConnectionState: DeviceConnectionState)
DeviceConnectionState is an enum that contains different states defined as:
enum class DeviceConnectionState {
CONNECTED,
DISCONNECTED,
VERIFIED,
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>?)
}
Auth token generation/refresh: #
Get authorisation token by making a GET request on the following REST endpoint with necessary headers
ENDPOINT: https://api.sunfox.in/v2/spandan/token-refresh/
Headers: #
Authorization: x-api-key
Used-Token: <provided separately>
Test failure codes:
- Ecg data is not valid
- Test canceled by the user
- 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.
ecgTest.start(position:EcgPosition);
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
):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);