The SDI12 library I use can be found in SDISerial/SDISerial.cpp at master · joranbeasley/SDISerial · GitHub
I just added two methods :
- sdi_write (identical with sdi_cmd from library but without code to send "Break" not relevant in case of response
- checkSlave (method I execute in ino main loop to check SDI buffer and process if needed
The code I added to the SDISerial class is
void SDISerial::sdi_write(const char* bytes) {
//clone of sdi_cmd(const char* bytes) but "Break" has been removed because not relevant when responding to a data-recorder query
//detach interrupt for this ...
flush();
detachInterrupt(pin2int[_receivePin]);
char buffer[255];
int i = 0;
char* p = (char*)bytes;
buffer[0] = '\0';
uint8_t oldSREG = SREG;
pinMode(_receivePin, OUTPUT);
while (*p != '\0') {
write(*p++);
}
pinMode(_receivePin, INPUT);
setRX(_receivePin);//, INPUT);
//reattach interrupt so we will see response stream
attachInterrupt(pin2int[_receivePin], handle_interrupt, CHANGE);
}
void SDISerial::initStatusLedPin()
{
if (_statusLedPin != 0)
{
pinMode(_statusLedPin, OUTPUT);
digitalWrite(_statusLedPin, LOW);
}
}
bool SDISerial::checkSlave() //parse SDI buffer and process buffer if SDI command is recognized (M!, D0!, D1!,...)
{
static char acc[20];
static int iChar = 0;
static int sentValue = -1;
char c;
char rep[50];
char buf[10];
static char chr_13[2]={(char)13,'\0'};
static char chr_10[2]={(char)10,'\0'};
bool returnValue = false;
bool responseTooLong = false;
while (available() > 0)
{
c = read()&0x7F; //read one byte in input buffer
if (c != '\0')
{
#if DEBUG == 1
Serial.print(".");
Serial.print(c);
Serial.print("(");
Serial.print((int)c);
Serial.print(")");
#endif
acc[++iChar] = c; //accumulate byte in acc buffer
}
}
if (acc[iChar]=='!' && acc[iChar-1] == 'M') // Measurement request (M!)
{
iChar = -1;
flush();
returnValue = true;
Serial.print("Received M");
rep[0] = '\0';
if (_statusLedPin != 0)
{
digitalWrite(_statusLedPin, HIGH); //switch on SDI-12 info led
}
strncpy(rep, "\0", 1);
sprintf(buf, "%i", _sdiAddress);
strcat(rep, buf);
strcat(rep, "001");
sprintf(buf, "%i", _nbValues);
strcat(rep, buf);
strcat(rep, chr_13);
strcat(rep, chr_10);
#if DEBUG == 1
Serial.print("->SDI:");
Serial.println(rep);
#endif
sdi_write(rep);
sentValue = 0;
}
else
{
if (acc[iChar] == '!' && acc[iChar-2]=='D' ) // Data requests (D0! , D1!,...)
{
iChar = -1;
flush();
rep[0] = '\0';
sprintf(buf, "%i", _sdiAddress);
strcat(rep, buf);
responseTooLong = false;
while (responseTooLong == false && sentValue < _nbValues)
{
sprintf(buf, "%+i", (int)dV[sentValue]);
if ((strlen(rep) + strlen(buf)) < 32) //check if length of data to send is greater that 32 (SDI12 limitation)
{
strcat(rep, buf);
sentValue++;
}
else //Length of data exceed 32... Next data will be sent in next data request
{
responseTooLong = false;
}
}
strcat(rep, chr_13);
strcat(rep, chr_10);
#if DEBUG == 1
Serial.print("->SDI:");
Serial.println(rep);
#endif
sdi_write(rep);
if (_statusLedPin != 0)
{
digitalWrite(_statusLedPin, LOW); //switch off SDI-12 info led
}
}
}
return returnValue;
}
The Hardware serial1 port (_oSerial in code) is checked from ino main loop by method check()
bool SerialListenerClass::check()
{
bool bRet = false;
if (_opened == true)
{
while (_oSerial->available() > 0 && bRet == false) {
char c = _oSerial->read();
if (c == '\n') {
_serialBuf[_serialBufPos++] = '\0';
_serialBufPos = 0;
decodeBuf(); //if \n received, decode input buffer
bRet = true;
}
else
{
_serialBuf[_serialBufPos++] = c;
_serialBuf[_serialBufPos] = '\0';
}
if (_serialBufPos > SERIAL_BUFFER_LENGTH)
_serialBufPos = 0;
}
}
return bRet;
}
void SerialListenerClass::decodeBuf() //parse buffer and extract values that must be kept
{
char acc[20];
int posAcc = 0;
int nbKept = -1;
int nbInBuf = 0;
long v[20];
char toKeep[50]={1,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0};
char *ptr = _serialBuf;
while (*ptr != '\0')
{
if (*ptr != 32)
{
acc[posAcc++] = *ptr;
}
else
{
if (posAcc > 0)
{
acc[posAcc] = '\0';
if (toKeep[nbInBuf] == 1)
{
nbKept++;
sscanf(acc,"%li",&v[nbKept]);
}
nbInBuf++;
}
posAcc = 0;
}
*ptr++;
}
if (posAcc > 0)
{
if (toKeep[nbInBuf] == 1)
{
acc[posAcc] = '\0';
nbKept++;
sscanf(acc,"%li",&v[nbKept]);
}
nbInBuf++;
}
if (nbInBuf != _nbBufValues)
{
Serial.println("************oupsbuffer length not ok");
_nbNotOk++;
}
else
{
if (nbKept != (_nbValues - 1))
{
Serial.println("**********oupsnb kept values not ok");
_nbNotOk++;
}
else
{
Serial.print("--> AVG:");
_nbOk++;
if (_resetNextData == true)
{
_nbOk = 1;
_nbNotOk = 0;
}
for (int i = 0; i < _nbValues; i++)
{
if (_resetNextData == true)
{
_avgS.reset();
- }*
avgS.addValue((double)v*);
}
}_
resetNextData = false;*
* }
}[/td]
[/tr]
[/table]
The ino main loop is
void loop()
{
if (oSDI.checkSlave()== true) //if Data request received from data recorder, update values in SDISerial class to be sent to data recorder*
* {_
for (int i = 0 ; i < SERIAL_NB_VALUES;i++)
_ {
oSDI.setValueSlave(i,oSerial1.AverageValues(i));
}
}
if (oSerial1.check()== true) //check if data received in Serial1 buffer*
* {
}
}*_