Skip to content

Instantly share code, notes, and snippets.

@chintanp
Created February 10, 2016 21:06
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chintanp/a22fb7e43f89d987d183 to your computer and use it in GitHub Desktop.
Save chintanp/a22fb7e43f89d987d183 to your computer and use it in GitHub Desktop.
Arduino Code for Sendyne Sensor - SFP101
/*
Copyright 2015-2016 Sendyne Corp., New York, USA
http://www.sendyne.com
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "SFP_Protocol.h"
#include <SoftwareSerial.h>
SFP_Protocol sfp(10,11);
bool poll = false;
unsigned long timer = 0;
void setup()
{
// put your setup code here, to run once:
Serial.begin(19200);
// if(!sfp.SetBaudRate(RATE_9600))
// Serial.println("Error when changing Rate");
// sfp.Reset();
sfp.RequestRegister(CUR_DATA,THREE);
}
uint8_t data[8];
int32_t CUR_OUT;
byte CUR_OUTL, CUR_OUTM, CUR_OUTH;
float ISH_COUNT = 0.00006119; // 100 uOhm shunt resistor datasheet - pg-29
void loop()
{
// the SFPLoop checks and collects data
if(sfp.SFPLoop())
{
// got a message, how much time has gone by?
//Serial.print("MS passed = ");
//Serial.print(micros() - timer);
//Serial.print("\t");
// get the data from the SFP library once available
int number_of_bytes = sfp.GetData(data);
float IRAW = 0.0;
// print out the returned data
// for(int i = 0; i < number_of_bytes; i++)
// {
// Serial.print(data[i],DEC);
// Serial.print(", ");
// }
// Serial.println(" ");
// data2=[];
// for(int i=0;i<1000;i++){
//
// }
// Description registers can be found on datasheet pg-56
CUR_OUTL = data[1];
CUR_OUTM = data[2];
CUR_OUTH = data[3];
// Concatenating the three bytes to a 24-bit number
CUR_OUT = CUR_OUTH;
CUR_OUT = (CUR_OUT << 8) | CUR_OUTM;
CUR_OUT = (CUR_OUT << 8) | CUR_OUTL;
// 2's complement
if(CUR_OUT > 8388608){
CUR_OUT = CUR_OUT - 16777216;
}
// Current measurement on datasheet pg-29
IRAW = CUR_OUT * ISH_COUNT;
Serial.println(IRAW, DEC);
if(poll)
sfp.RequestRegister(CUR_DATA,THREE);
delay(1);
timer = micros();
}
if(sfp.GetError())
{
Serial.println("A communication error has occurred");
}
// check if there is any input from the user
if(Serial.available())
{
char tmp = Serial.read();
//Serial.println("reading serial");
// if the user sent an r, send the mode packet
if(tmp == 'r')
sfp.Reset();
else if(tmp == 's')
sfp.RequestRegister(CUR_DATA,THREE);
else if(tmp == 'b')
{
if(!sfp.SetBaudRate(RATE_9600))
Serial.println("Error when changing Rate");
}
else if(tmp == 'n')
{
if(!sfp.SetBaudRate(RATE_19200))
Serial.println("Error when changing Rate");
}
else if(tmp == 'm')
{
if(!sfp.SetBaudRate(RATE_115200))
Serial.println("Error when changing Rate");
}
else if(tmp == 'p')
{
if(poll)
poll = false;
else
{
poll = true;
//delay(1000);
sfp.RequestRegister(CUR_DATA,THREE);
//delay(1000);
}
}
else if(tmp == 'k')
{
uint8_t temp_data[8] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
sfp.SendWriteMessage(temp_data, C_THRESH, TWO);
}
}
}
/*
Copyright 2015-2016 Sendyne Corp., New York, USA
http://www.sendyne.com
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#include "SFP_Protocol.h"
// constructor
SFP_Protocol::SFP_Protocol(int RX, int TX)
{
// set up the Serial Communication with the SFP module
soft_serial = new SoftwareSerial(RX,TX);
soft_serial->begin(19200);
// set the default settings
SetNumberOfBytes(SIX);
SetRegister(PNS_1);
SetMode(READ);
error = false;
}
/*********************************************
* Returns the byte on the line if available
* if not available, returns 0.
*********************************************/
uint8_t SFP_Protocol::GetByte()
{
// check if the serial is available
if(soft_serial->available())
{
// return what is on the wire
return soft_serial->read();
}
else
// return 0 - as an error
return 0;
}
/*********************************************
* checks if there is any data on the wire
* coming from the SFP module
*
* RETURNS: true or false
*********************************************/
bool SFP_Protocol::IsAvailable()
{
if(soft_serial->available())
return 1;
else
return 0;
}
/*********************************************
* Writes the passed in byte to the wire
* The byte has to be constructed by the user
*
* RETURNS: nothing
*********************************************/
void SFP_Protocol::WriteByte(uint8_t byte_to_send)
{
// write the byte on the line
soft_serial->write(byte_to_send);
}
/*********************************************
* Sets the Mode for the message
*
* RETURNS: nothing
*********************************************/
void SFP_Protocol::SetMode(uint8_t mode_byte)
{
mode = mode_byte;
}
/*********************************************
* Sets the register for the message
*
* RETURNS: nothing
*********************************************/
void SFP_Protocol::SetRegister(uint8_t reg_address)
{
register_address = reg_address;
}
/*********************************************
* Sets how many bytes to request as well as
* sets the counter of the number of bytes
* that are expected in response
*
* RETURNS: nothing
*********************************************/
void SFP_Protocol::SetNumberOfBytes(uint8_t bytes_to_request)
{
request_bytes = bytes_to_request;
// set the request bytes integer to the expected number of bytes to be returned
switch(request_bytes)
{
case ONE:
request_bytes_int = 3;
break;
case TWO:
request_bytes_int = 4;
break;
case THREE:
request_bytes_int = 5;
break;
case SIX:
request_bytes_int = 8;
break;
}
}
/*********************************************
* Sends the message with previously set
* parameters
*
* RETURNS: nothing
*********************************************/
void SFP_Protocol::SendModePacket()
{
// construct a packet based on the set parameters
// packet to be sent out
uint8_t packet;
// shift left to have the mode as the most significant bit
packet = mode << 7;
// OR the number of requested bytes into the least significant bits
packet = packet | request_bytes;
// send the mode
soft_serial->write(packet);
// send the address
soft_serial->write(register_address);
// save the begining of the message
message[0] = packet;
message[1] = register_address;
// start the timer
StartTimer();
// idicate that the transmition has been started
t_start = true;
}
/*********************************************
* Send a request for X number of bytes at
* the passed in address
*
* RETURNS: nothing
*********************************************/
void SFP_Protocol::RequestRegister(uint8_t reg_address, uint8_t bytes_to_request)
{
// set all parameters
SetNumberOfBytes(bytes_to_request);
SetRegister(reg_address);
SetMode(READ);
// call on the send function
SendModePacket();
}
/*********************************************
* Should be called on each of the main loop
* iterations. This function fetches data
* from the wire and puts it in the
* data variable
*
* RETURNS: true when all data is available
*********************************************/
bool SFP_Protocol::SFPLoop()
{
// while there is data on the serial, loop
while(soft_serial->available())
{
if( recieved_data_counter == 0)
{
// flush the data and set all to be 0
for(int i = 0; i < 8; i++)
{
data[i] = 0;
}
}
// make sure that the counter is within spec
if(recieved_data_counter < request_bytes_int)
{
// write the incoming byte to the data variable
data[recieved_data_counter] = soft_serial->read();
// increment the counter
recieved_data_counter++;
}
// if the counter is equal to the bytes requested, we have
// reached the limit, if there is more data on the
// bus, we should break the available loop.
// i.e. something went wrong
if(recieved_data_counter == request_bytes_int)
{
// this should never occur as the counter goes up to request_bytes_int - 1
// we have recieved more bytes that we expected
// set error flag to true
error = true;
}
}
// check if the timer did not overflow
if(Timeout() && t_start)
{
// we have timed out. check if there is anything in the data variable
if(recieved_data_counter > 0)
// there is data, we timed out, flush everything and throw an error
recieved_data_counter = 0;
//StartTimer(); // not needed as the t_start flag will keep us out of here
Serial.println("Timed out");
error = true;
t_start = false;
return false;
}
else
error = false;
// counter is equal to the requested bytes
// we have the data we asked for
if(recieved_data_counter == request_bytes_int)
{
// we recieved the right amount of data
// write it to the message array
for(int i = 0; i < request_bytes_int; i++)
{
message[i+2] = data[i];
}
// check the CRC to make sure the message is correct
if(CRC(request_bytes_int + 2) == 0)
{
// reset the counter and return true
recieved_data_counter = 0;
error = false;
// indicate the end of the transaction
t_start = false;
return true;
}
}
else
return false;
}
/*********************************************
* RETURNS: all the data in the data variable
* via reference - an 8 byte array should
* always be passed!
*
* Also, returns the length of the data
*********************************************/
uint8_t SFP_Protocol::GetData(uint8_t * _data)
{
// write all the data into the referenced variable
for(int i = 0; i < 8; i++)
_data[i] = data[i];
// return the number of bytes that were requested
return request_bytes_int;
}
/*********************************************
* Set the data for writing to the SFP module
*
* RETURNS: Nothing
*********************************************/
void SFP_Protocol::SetData(uint8_t * _data)
{
// set the data for writing to the SFP module
for(int i = 0; i < 8; i++)
data[i] = _data[i];
}
/*********************************************
* Sets the new baud rate for the board.
* rates possible: 9600
* 19600
* 115200
*
* RETURNS: true if succeeded
*********************************************/
bool SFP_Protocol::SetBaudRate(uint8_t rate)
{
// construct the change baud rate packet
uint8_t packet = rate;
message[2] = packet;
// set the mode
SetMode(WRITE);
// set the register
SetRegister(COM_C);
// set the number of bytes
SetNumberOfBytes(ONE);
// send the new baud rate request
SendModePacket();
// send the change byte packet
soft_serial->write(packet);
// send CRC
soft_serial->write(CRC(3));
//soft_serial->begin(9600);
// request the new baud rate
RequestRegister(COM_C,ONE);
while(1)
{
if(SFPLoop())
{
// the message is avaialble for reading
break;
}
else if(error)
{
Serial.println("read error");
break;
}
}
if(data[1] == packet)
{
Serial.println("Switching baud rate");
error = false;
t_start = false;
// switch the local baudrate and reconnect
switch (rate)
{
case RATE_9600:
Serial.println("switched to 9600");
soft_serial->flush();
delay(20);
soft_serial->begin(9600);
break;
case RATE_19200:
Serial.println("switched to 19200");
soft_serial->flush();
delay(20);
soft_serial->begin(19200);
break;
case RATE_115200:
Serial.println("switched to 115200");
soft_serial->flush();
delay(20);
soft_serial->begin(115200);
break;
}
soft_serial->listen();
return true;
}
else
// the data did not match our packet, something went wrong
return false;
}
bool SFP_Protocol::GetError()
{
return error;
}
/*********************************************
* Resets the module
* A reset erases all the volitale registers
*
* RETURNS: Nothing
*********************************************/
void SFP_Protocol::Reset()
{
// send the reset message to the SFP module
// construct the reset packet
data[0] = 0x01;
message[2] = data[0];
// set the mode
SetMode(WRITE);
// set the number of bytes
SetNumberOfBytes(ONE);
// set the register
SetRegister(RST);
// send the mode and register packets
SendModePacket();
// send the reset byte packet
soft_serial->write(data[0]);
// send the CRC byte packet
soft_serial->write(CRC(3));
delay(600);
t_start = false;
error = false;
// set baud rate to 19200
soft_serial->begin(19200);
soft_serial->flush();
delay(20);
soft_serial->listen();
Serial.println("RESET");
}
/*********************************************
* Computes the CRC checksum
* It is called on read and writes
* the SFP module returns a CRC on a read, this
* should be used to compare it with the CRC
* given by the SFP module
*
* if out going message then use i = 0
* if incoming message then use i = 1
*
* RETURNS: Nothing
*********************************************/
uint8_t SFP_Protocol::CRC(int length)
{
uint8_t rem = 0;
for (int i = 0; i < length; ++i)
{
rem = (uint8_t)(rem ^ (message[i]));
for (int j = 0; j < 8; ++j)
{
if ((rem & 0x80) > 0)
{
rem = (uint8_t)((rem << 1) ^ 0x07);
}
else
{
rem = (uint8_t)(rem << 1);
}
}
}
return rem;
}
/*********************************************
* writes the data to the bus based on the
* set values and the CRC of the message
*
*
* RETURNS: Nothing
*********************************************/
void SFP_Protocol::WriteData()
{
// write each byte to the line
for(int i = 0; i < request_bytes_int-2; i++)
{
// Serial.print("writing data to serial: ");
// Serial.println(data[i], HEX);
soft_serial->write(data[i]);
message[i+2] = data[i];
}
// write the CRC
soft_serial->write(CRC(request_bytes_int));
t_start = false;
}
void SFP_Protocol::SendWriteMessage(uint8_t * _data, uint8_t reg_address, uint8_t num_of_bytes)
{
for(int i = 0; i < 8; i++)
data[i] = _data[i];
SetMode(WRITE);
SetRegister(SHNT_CAL);
SetNumberOfBytes(num_of_bytes);
SendModePacket();
WriteData();
}
// ************ Private functions ************
/*********************************************
* Starts/restarts the timer
* This function helps to determine if we have
* waited long enough for the data to come
* back from the SFP10X module
*
* RETURNS: Nothing
*********************************************/
void SFP_Protocol::StartTimer()
{
// start/restart the timer
timer_start_time = millis();
}
/*********************************************
* This function checks if the timer has gone
* over the set time out. If it goes over then
* there was something wrong with the
* communication to the SFP module
*
* RETURNS: true on timeout, else false
*********************************************/
bool SFP_Protocol::Timeout()
{
// has the timer gone over the timer_timeout?
if((millis() - timer_start_time) > timer_timeout)
{
// timer has gone over the timer_timeout limit
// return true indicating that something went wrong
return true;
}
else
return false;
}
/*
Copyright 2015-2016 Sendyne Corp., New York, USA
http://www.sendyne.com
THE SOFTWARE IS PROVIDED AS IS, WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
*/
#ifndef SFP_PROTOCOL
#define SFP_PROTOCOL
#include <SoftwareSerial.h>
#include <Arduino.h>
// ************ General purpose ************
#define GP_STAT 0X00 // GENERAL PURPOSE STATUS
#define COM_C 0x01 // COMMUNICATIONS
#define RST 0x10 // RESET
#define PNS_1 0x11 // PART NUMBER STRING 1
#define PNS_7 0x17 // PART NUMBER STRING 2
#define SerNo 0x1E // SERIAL NUMBER
#define MC 0x21 // MANUFACTURING CODE
#define PN 0x24 // PART NUMBER CODE
#define VER_C 0x26 // VERSION CODE
// ************ Flash interface ************
#define F_DATA 0x28 // FLASH DATA
#define F_ENTRY 0x2C // FLASH ENTRY
#define F_TABLE 0X2D // FLASH TABLE
#define F_ERASE 0X2E // FLASH ERASE
// ************ Current Measurement ************
#define CUR_S 0x30 // CURRENT STATUS
#define CUR_C 0x31 // CURRENT CONTROL
#define CUR_DATA 0x32 // CURRENT DATA
#define CUR_COUNTL 0x35 // COULOMB COUNTING DATA LOW
#define CUR_COUNTH 0x37 // COULOMB COUNTING DATA HIGH
#define SHNT_CAL 0x41 // SHUNT CALIBRATION DATA
#define CUR_GAIN 0x43 // CURRENT GAIN CONTROL
#define COMP_CTRL 0x44 // COMPENSATION CONTROL
#define C_THRESH 0x45 // CHARGE THRESHOLD VALUE
#define D_THRESH 0x48 // DISCHARGE THRESHOLD VALUE
#define CHRG_ACCL 0xC0 // ACCUMULATED CHARGE DATA LOW
#define CHRG_ACCH 0xC2 // ACCUMULATED CHARGE DATA HIGH
#define DSCHRG_ACCL 0xC8 // ACCUMULATED DISCHARGE DATA LOW
#define DSCHRG_ACCH 0xCA // ACCUMULATED DISCHARGE DATA HIGH
// ************ Voltage Measurement ************
#define VOLT_S 0x50 // VOLTAGE STATUS
#define VOLT_C 0x51 // VOLTAGE CONTROL
#define VOLT_DATA 0x52 // VOLTAGE DATA
#define VOLT_CAL 0x55 // VOLTAGE CALIBRATION DATA
#define VOLT_GCC 0x57 // VOLTAGE GAIN AND CALIBRATION CONTROL
// ************ Temperature Measurement ************
#define TEMP_S 0x70 // TEMPERATURE STATUS
#define TEMP_C 0x71 // TEMPERATURE CONTROL
#define TEMP_OUT 0x72 // REMOTE SENSOR TEMPERATURE DATA
#define TEMP1_OB_OUT 0x90 // ON-BOARD SENSORS TEMPERATURE DATA 1
#define TEMP2_OB_OUT 0x93 // ON-BOARD SENSORS TEMPERATURE DATA 2
#define TEMP3_OB_OUT 0x96 // ON-BOARD SENSORS TEMPERATURE DATA 3
#define TEMP0_R_C 0x99 // REMOTE SENSOR CELSIUS DATA
#define TEMP1_OB_C 0x9C // ON-BOARD SENSORS CELSIUS DATA 1
#define TEMP2_OB_C 0x9F // ON-BOARD SENSORS CELSIUS DATA 2
#define TEMP3_OB_C 0xA2 // ON-BOARD SENSORS CELSIUS DATA 3
// ************ not in the datasheet ************
#define ETH_AD 0x7B // EXTERNAL THERMISTOR ADC DATA
#define EXT_REF 0x7E // EXTERNAL REFERENCE RESISTOR ADC DATA
#define STH_2_AD 0x81 // ON-BOARD THERMISTOR 2 ADC DATA
#define INT_REF 0x84 // ON-BOARD REFERENCE RESISTOR ADC DATA
#define SHT_1_AD 0x87 // ON-BOARD THERMISTOR 1 ADC DATA
#define SHT_3_AD 0x8A // ON-BOARD THERMISTOR 3 ADC DATA
// ************ Other ************
// error code
#define ERROR_CODE 0xF8000000
// message mode
#define WRITE 0x00
#define READ 0x01
// number of bytes to be returned/written to
#define ONE 0x00
#define TWO 0x01
#define THREE 0x02
#define SIX 0x03
#define RATE_9600 0x00
#define RATE_19200 0x01
#define RATE_115200 0x02
class SFP_Protocol
{
public:
// constructor
SFP_Protocol(int, int);
/*********************************************
* RETURNS: the byte on the line if available
* if not available, returns 0.
*********************************************/
uint8_t GetByte();
/*********************************************
* checks if there is any data on the wire
* coming from the SFP module
*
* RETURNS: true or false
*********************************************/
bool IsAvailable();
/*********************************************
* Writes the passed in byte to the wire
* The byte has to be constructed by the user
*
* RETURNS: nothing
*********************************************/
void WriteByte(uint8_t);
/*********************************************
* Sets the Mode for the message
*
* RETURNS: nothing
*********************************************/
void SetMode(uint8_t);
/*********************************************
* Sets the register for the message
*
* RETURNS: nothing
*********************************************/
void SetRegister(uint8_t);
/*********************************************
* Sets how many bytes to request as well as
* sets the counter of the number of bytes
* that are expected in response
*
* RETURNS: nothing
*********************************************/
void SetNumberOfBytes(uint8_t);
/*********************************************
* Sends the message with previously set
* parameters
*
* RETURNS: nothing
*********************************************/
void SendModePacket();
/*********************************************
* Send a request for X number of bytes at
* the passed in address
*
* RETURNS: nothing
*********************************************/
void RequestRegister(uint8_t, uint8_t);
/*********************************************
* Should be called on each of the main loop
* iterations. This function fetches data
* from the wire and puts it in the
* data variable
*
* RETURNS: true when all data is available
*********************************************/
bool SFPLoop();
/*********************************************
* RETURNS: all the data in the data variable
* via reference - an 8 byte array should
* always be passed!
*
* Also, returns the length of the data
*********************************************/
uint8_t GetData(uint8_t * );
/*********************************************
* Set the data for writing to the SFP module
*
* RETURNS: Nothing
*********************************************/
void SetData(uint8_t *);
/*********************************************
* Sets the new baud rate for the board.
* rates possible: 9600
* 19600
* 115200
*
* RETURNS: true if succeeded
*********************************************/
bool SetBaudRate(uint8_t);
/*********************************************
* Resets the module
*
* RETURNS: Nothing
*********************************************/
void Reset();
/*********************************************
* Computes the CRC checksum
* It is called on read and writes
* the SFP module returns a CRC on a read, this
* should be used to compare it with the CRC
* given by the SFP module
*
* RETURNS: remainder
*********************************************/
uint8_t CRC(int);
/*********************************************
* writes the data to the bus based on the
* set values.
*
*
* RETURNS: Nothing
*********************************************/
void WriteData();
/*********************************************
* Gets the state of the error flag
*
*
* RETURNS: error flag
*********************************************/
bool GetError();
void SendWriteMessage(uint8_t *, uint8_t, uint8_t);
private:
// serial communications object
SoftwareSerial * soft_serial;
// usage - message: mode of the message
uint8_t mode;
// usage - message: register adderss of the message
uint8_t register_address;
// usage - message: number of bytes to be returned
uint8_t request_bytes;
// usage - loop: number of bytes that we requested
uint8_t request_bytes_int;
// usage - loop: number of data that has been returned
uint8_t recieved_data_counter;
// usage - stores data: is updated every time there is a
// new complete message available
uint8_t data[8];
// usage - timing: storest the message send time
unsigned long timer_start_time;
// usage - timing: stores the timeout period
const unsigned long timer_timeout = 20;
// usage - error indicator: stores true if there was an error
bool error;
// usage - indicates that there is active communication: transmition start variable
bool t_start;
uint8_t message[20];
/*********************************************
* Starts/restarts the timer
* This function helps to determine if we have
* waited long enough for the data to come
* back from the SFP10X module
*
* RETURNS: Nothing
*********************************************/
void StartTimer();
/*********************************************
* This function checks if the timer has gone
* over the set time out. If it goes over, then
* there was something wrong with the
* communication to the SFP module
*
* RETURNS: true on timeout, else false
*********************************************/
bool Timeout();
};
#endif
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment