#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
//#include <termios.h>
#include <unistd.h>
//#include <sys/stat.h>
#include <fcntl.h>
#include <time.h>
/************************* defines ******************************************/
#define ESC 27 // escape
#define TRUE 1
#define FALSE 0
#define RECEIVE_BUF_SIZE 512
#define LOGFILEPATH "./comlog"
#define LOGFILESIZE 500000
#define ACTUALDATA "./actual_data.txt"
/************************* macros *******************************************/
/************************* typedefs *****************************************/
// log message identifier
typedef enum {
LOG_SEND,
LOG_RECEIVE,
LOG_ERR,
LOG_INFO
} T_LOG_IDENT;
typedef enum {
STM_INIT,
STM_RECEIVE_MSG,
STM_HANDLE_MA,
STM_HANDLE_M1,
STM_HANDLE_M2,
STM_HANDLE_MI
} T_STM_RECEIVE;
typedef enum {
STM_SUB_RECEIVE_HEADER,
STM_SUB_RECEIVE_REPLY_BODY,
STM_SUB_RECEIVE_MESSAGE_BODY,
} T_STM_RECEIVE_SUB;
typedef enum {
FROE_PARAM_WORKMODE = 155,
} T_FROE_PARAMID;
typedef enum {
FROE_WORKMODE_WINTER = 0,
FROE_WORKMODE_SOMMER = 1,
FROE_WORKMODE_UEBERGANG = 2,
FROE_WORKMODE_SCHEITHOLZ = 3,
FROE_WORKMODE_REINIGEN = 4,
} T_FROE_WORKMODE;
/************************* global variables *********************************/
int hCom;
int DEBUG = 1;
FILE *DataFile;
FILE *OutputFile;
int DataFileCounter = 0; // Zaehler, um nur jede DataFileDelay-te Sekunde einen Eintrag in DataFile vorzunehmen
int DataFileDelay = 1;
int OutputFileCounter = 0; // Zaehler, um nur jede OutputFileDelay-te Sekunde einen Eintrag in OutputFile vorzunehmen
int OutputFileDelay = 1;
int Output2Stdout = 1; // Datenausgabe auch nach stdout (1) oder nicht (0)
short glsUserID;
int ValueCount = 0;
char *ValueNames[100];
char DataFileName[37]; // fuer den Namen des Datalogs
struct tm *tmnow; // fuer die Bestimmung der aktuellen Uhrzeit
time_t tnow; // fuer die Bestimmung der aktuellen Uhrzeit
T_STM_RECEIVE tCurrentMainState;
T_STM_RECEIVE_SUB tCurrentSubState;
int k = 0;
int i = 0;
char cReceiveBuffer[RECEIVE_BUF_SIZE];
char cKb = '\0';
int iInBuffPointer = 0;
char cRbSendFlag = 0;
unsigned int iMsgLength = 0;
char cTime[50];
void setup() {
tCurrentMainState = STM_INIT;
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
// Message at:
// Byte: 1| 2| 3| 4| 5| 6 ...
// --------------------------------------------
// HEX: 4d|32|07|57|50|20|25|01|03|12|01|88
// --------------------------------------------
// ASCII: M| 2| ...
// --------------------------------------------
// Content: Ident| l| Datablock | CHS |
// Blocks : Header | Body | CHS |
//
// Byte 1,2: Message identifier (M1 = measurement values / M2 = time)
// Byte 3 Message data block length in bytes (l)
// Byte 4... Datablock
// Last 2 Bytes:Checksum (CHS)
/*
04< MA.I...+Zustand.. 4D 41 0C 49 00 1C 07 2B 5A 75 73 74 61 6E 64 04 1A OK
M A 12 Z u s t a n d | CHS
06< MA.I....ROST.h 4D 41 09 49 00 1D 07 1C 52 4F 53 54 02 68 OK
M A 09 R O S T | CHS
08< MA.I....Kesseltemp.. 4D 41 0F 49 00 00 00 03 4B 65 73 73 65 6C 74 65 6D 70 05 06 OK
M A 15 K e s s e l | CHS
10< MA.I....Abgastemp..� 4D 41 0F 49 00 05 01 04 41 62 67 61 73 74 65 6D 70 2E 04 B2 OK
M A 15 A b g a s t e | CHS
12< MA.I....Abgas..SW..� 4D 41 0F 49 00 06 05 0D 41 62 67 61 73 2E 20 53 57 20 03 F4 OK
M A 15 A b g a s
14< MA.I....KessStellGr.] 4D 41 10 49 00 19 05 05 4B 65 73 73 53 74 65 6C 6C 47 72 05 5D OK
M A 16 K e s s
16< MA.I...*Saugzug...G 4D 41 0E 49 00 0F 03 2A 53 61 75 67 7A 75 67 20 20 04 47 OK
M A 14 S a u g
18< MA.I....Zuluftgebl.2 4D 41 0F 49 00 1E 03 07 5A 75 6C 75 66 74 67 65 62 6C 05 32 OK
M A 15 Z u l u f t
20< MA.I....Einschub.9 4D 41 0D 49 00 1B 03 06 45 69 6E 73 63 68 75 62 04 39 OK
M A 13 E i n s c h
22< MA.I.,./Fuellst.:.? 4D 41 0E 49 00 2C 03 2F 46 75 65 6C 6C 73 74 2E 3A 04 8A OK
M A 14 F u e l l
24< MA.I....Feuerraumt.. 4D 41 0F 49 00 04 07 0B 46 65 75 65 72 72 61 75 6D 74 05 1C OK
M A 15 F e u e r
26< MA.I....Boilertemp.. 4D 41 0F 49 00 02 00 10 42 6F 69 6C 65 72 74 65 6D 70 05 0B OK
M A 15 B o i l
28< MA.I....Au�entemp., 4D 41 0E 49 00 0A 00 1D 41 75 E1 65 6E 74 65 6D 70 05 2C OK
M A 14 A u s
30< MA.I....Vorlauft.1sw.� 4D 41 11 49 00 15 03 1E 56 6F 72 6C 61 75 66 74 2E 31 73 77 05 BA OK
M A 17 V o r l
32< MA.I....Vorlauft.1.� 4D 41 0F 49 00 0B 01 1F 56 6F 72 6C 61 75 66 74 2E 31 04 C3 OK
M A 15 V o r l
34< MA.I.).(KTY6_H2.B 4D 41 0C 49 00 29 07 28 4B 54 59 36 5F 48 32 03 42 OK
M A 12 K T Y
36< MA.I.*.)KTY7_H2.E 4D 41 0C 49 00 2A 07 29 4B 54 59 37 5F 48 32 03 45 OK
M A 12 K T Y
38< MA.I.0.3Brenn.ST.. 4D 41 0D 49 00 30 05 33 42 72 65 6E 6E 2E 53 54 04 16 OK
M A 13 B r e n
40< MA.I...&Laufzeit:.? 4D 41 0E 49 00 12 01 26 4C 61 75 66 7A 65 69 74 3A 04 9C OK
M A 14 L a u f
42< MA.I...,Boardtemp..� 4D 41 0F 49 00 18 01 2C 42 6F 61 72 64 74 65 6D 70 2E 04 F7 OK
M A 15 B o a
44< MA.I...-Die.Kesseltemp..soll.sein.N 4D 41 1E 49 00 17 05 2D 44 69 65 20 4B 65 73 73 65 6C 74 65 6D 70 2E 0A 73 6F 6C 6C 20 73 65 69 6E 0A 4E OK
M A 30 D i e K e s s e l t e m p .
*/
// init globals
glsUserID = -7;
ValueCount = 0;
// init locals
k = 0;
iInBuffPointer = 0;
cRbSendFlag = 0;
iMsgLength = 0;
Serial.begin(9600);
Serial1.begin(9600);
// init communication by sendig "Ra" to P3100
if (DEBUG == 1) Serial.write("vor Send_Msg Ra\n");
Send_Msg("Ra");
if (DEBUG == 1) Serial.write("nach Send_Msg Ra\n");
// next states
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
tCurrentMainState = STM_RECEIVE_MSG;
}
void loop() {
switch (tCurrentMainState)
{
case STM_RECEIVE_MSG:
{
// read one character from the input buffer
if (ComReceive(&cReceiveBuffer[iInBuffPointer], 1) > 0) {
iInBuffPointer++;
if (DEBUG > 0) Serial.write("iInBuffPointer: %d\n", iInBuffPointer);
}
switch (tCurrentSubState)
{
case STM_SUB_RECEIVE_HEADER:
{
if (iInBuffPointer >= 3) {
// get parameter length
iMsgLength = (unsigned int)cReceiveBuffer[2] + 5;
if ((iMsgLength) > RECEIVE_BUF_SIZE) {
PrintComLog(LOG_ERR, "Buffersize to small for telegram", 32);
iInBuffPointer = 0;
iMsgLength = 0;
}
else if (cReceiveBuffer[0] == 'R') {
// set next state
tCurrentSubState = STM_SUB_RECEIVE_REPLY_BODY;
}
else if (cReceiveBuffer[0] == 'M') {
// set next state
tCurrentSubState = STM_SUB_RECEIVE_MESSAGE_BODY;
}
else {
PrintComLog(LOG_ERR, "Unvalid telegram startvalue", 27);
iInBuffPointer = 0;
}
}
break;
}
case STM_SUB_RECEIVE_REPLY_BODY:
{
// wait until 6 bytes have been received
if (iInBuffPointer >= 6) {
// check received checksum
if (checkCheckSum(cReceiveBuffer, 6)) {
PrintComLog(LOG_INFO, "ChkSum OK", 9);
Serial.write("\n");
}
else {
PrintComLog(LOG_INFO, "ChkSum NOT OK", 13);
}
iInBuffPointer = 0;
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
}
break;
}
case STM_SUB_RECEIVE_MESSAGE_BODY:
{
// is telegram complete?
if (iInBuffPointer >= iMsgLength) {
// check received checksum
if (checkCheckSum(cReceiveBuffer, iMsgLength)) {
//PrintComLog(LOG_INFO, "ChkSum OK", 9);
//Serial.write("\n");
//usleep(250 * 1000);
sendAcq(cReceiveBuffer, iMsgLength);
}
else {
PrintComLog(LOG_INFO, "ChkSum NOT OK", 13);
sendNAcq(cReceiveBuffer, iMsgLength);
}
// check if value names have been received (MA messages)
if (cReceiveBuffer[1] == 'A') {
tCurrentMainState = STM_HANDLE_MA;
}
// check if measurement values have been received (M1 messages)
else if (cReceiveBuffer[1] == '1') {
tCurrentMainState = STM_HANDLE_M1;
}
// check if date/time has been received
else if (cReceiveBuffer[1] == '2') {
tCurrentMainState = STM_HANDLE_M2;
}
// check if I frame has been received
else if (cReceiveBuffer[1] == 'I') {
tCurrentMainState = STM_HANDLE_MI;
}
else
{
PrintComLog(LOG_RECEIVE, cReceiveBuffer, iMsgLength);
// next states
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
tCurrentMainState = STM_RECEIVE_MSG;
}
iInBuffPointer = 0;
}
break;
}
}
break;
}
case STM_HANDLE_MA:
{
ValueNames[ValueCount] = (char*)malloc( (iMsgLength - 9) * sizeof(char));
memcpy(ValueNames[ValueCount], &cReceiveBuffer[8], iMsgLength - 10);
ValueNames[ValueCount][iMsgLength - 10] = '\0';
ValueCount++;
PrintComLog(LOG_RECEIVE, cReceiveBuffer, iMsgLength);
// next states
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
tCurrentMainState = STM_RECEIVE_MSG;
break;
}
case STM_HANDLE_M1:
{
int i;
int startindex = 3;
float sValue = 0;
// fuer Ausgabe am Bildschirm
if (Output2Stdout) {
Serial.write("%s", cTime);
for (i = 0; i < ValueCount; i++)
{
sValue = (float)(((unsigned char)(cReceiveBuffer[startindex + (i * 2)]) << 8) + (unsigned char)cReceiveBuffer[startindex + (i * 2 + 1)]);
// scale some values
switch (i) {
case 4: {
sValue = sValue / 2.0 ;
break;
}
case 11: {
sValue = sValue / 10.0 ;
break;
}
case 13: {
sValue = sValue / 207.0 ;
break;
}
case 15: {
sValue = sValue / 2.0 ;
break;
}
case 16: {
sValue = sValue / 2.0 ;
break;
}
case 18: {
sValue = sValue / 2.0 ;
break;
}
case 19: {
sValue = sValue / 2.0 ;
break;
}
case 20: {
sValue = sValue / 2.0 ;
break;
}
case 21: {
sValue = sValue / 2.0 ;
break;
}
case 22: {
sValue = sValue / 2.0;
break;
}
case 29: {
sValue = sValue / 2.0 ;
break;
}
}
// anlagenspezifischer hack, da ValueName[29] wohl \n enthaelt
char s [80];
if (i == 29)
{
sprintf (s, "%2d. %15s : %7.1f\n", i, "Kesselsolltemp.", sValue);
Serial.write(s);
}
else
{
sprintf (s, "%2d. %15s : %7.1f\n", i, ValueNames[i], sValue);
Serial.write(s);
}
}
LinesUp(ValueCount + 3); // steigt ValueCount+3 Zeilen nach oben
}
// Ende Bildschirmausgabe
// next states
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
tCurrentMainState = STM_RECEIVE_MSG;
break;
}
case STM_HANDLE_M2:
{
if (cRbSendFlag == 0) {
// init measurement value transfer by sending "Rb" to P3100
Send_Msg("Rb");
cRbSendFlag = 1;
//PrepareScreen();
//Set time on P3100
//Set_Time();
//Set workmode on P3100
//Set_ParamValue(FROE_PARAM_WORKMODE, FROE_WORKMODE_REINIGEN);
}
if (Output2Stdout) {
sprintf(cTime, "\nAnlagendatum: %02i.%02i.20%02i Anlagenzeit: %02i:%02i:%02i\n\n", \
convert_FroelingTime(cReceiveBuffer[6]), \
convert_FroelingTime(cReceiveBuffer[7]), \
convert_FroelingTime(cReceiveBuffer[9]), \
convert_FroelingTime(cReceiveBuffer[5]), \
convert_FroelingTime(cReceiveBuffer[4]), \
convert_FroelingTime(cReceiveBuffer[3]));
Serial.write(cTime);
}
// fuege Wartezeit ein, um Prozessorauslastung zu verringern, muss ans System angepasst werden
delay(900);
// next states
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
tCurrentMainState = STM_RECEIVE_MSG;
break;
}
case STM_HANDLE_MI:
{
PrintComLog(LOG_RECEIVE, cReceiveBuffer, iMsgLength);
// next states
tCurrentSubState = STM_SUB_RECEIVE_HEADER;
tCurrentMainState = STM_RECEIVE_MSG;
break;
}
}
}
/* ---------------------------------------------------
Send something via ComPort
---------------------------------------------------
*/
int ComSend(char* SendBuffer, int bytes2send)
{
long BytesWrite;
BytesWrite = Serial1.write(SendBuffer, bytes2send);
if (DEBUG == 1) Serial.write("BytelsWrite: %d\n", (int)BytesWrite);
if (BytesWrite < 0) {
return (-1);
}
return (0);
}
/* ---------------------------------------------------
Receive something via ComPort
---------------------------------------------------
*/
int ComReceive(char* ReceiveBuffer, int bytes2receive)
{
long BytesRead;
BytesRead = Serial1.readBytes(ReceiveBuffer, bytes2receive);
if (DEBUG > 0)
{
char s[80];
sprintf(s, "fuehre ComReceive aus: Anzahl gelesener Bytes: %ld / gelesene Zeichen: %s\n", BytesRead, ReceiveBuffer);
Serial.write(s);
}
if (BytesRead < 1) {
if (DEBUG > 0) {
Serial.write("Fuehre Send_Masg(\"Ra\"); zusaetzlich aus!\n");
Send_Msg("Ra");
}
}
return BytesRead;
}
/* ---------------------------------------------------
Construct and send a message in Froeling-Format
---------------------------------------------------
*/
void Send_Msg(char* msg)
{
char sendbuffer[8];
char arrayUserID[3];
char b[8];
char cs[2];
arrayUserID[0] = 0;
arrayUserID[1] = (char)((glsUserID >> 8) & 0xFF);
arrayUserID[2] = (char)(glsUserID & 0xFF);
memset(b, 0, (8)*sizeof(char));
b[0] = msg[0];
b[1] = msg[1];
b[2] = 3;
memcpy(&b[3], arrayUserID, 3);
CreateCheckSum(b, 6, cs);
memcpy(&b[6], cs, 2);
memcpy(sendbuffer, b, 8);
PrintComLog(LOG_SEND, sendbuffer, 8);
if (DEBUG > 0) Serial.write("vor ComSend\n");
ComSend(sendbuffer, 8);
if (DEBUG > 0) Serial.write("nach ComSend\n");
return;
}
/* ---------------------------------------------------
Set time on P3100
---------------------------------------------------
*/
void Set_Time(void)
{
time_t seconds;
struct tm* timeinfo;
// message prototype
// R 2 len sec min hour day month dow year | Checksum
char sendbuffer[] = {0x52, 0x32, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
char cs[2];
// get the systemtime
seconds = time(NULL);
// convert seconds from 1970 into tm - structure
timeinfo = (struct tm*)localtime(&seconds);
sendbuffer[8] = convert_2_FroelingTime(timeinfo->tm_wday);
sendbuffer[6] = convert_2_FroelingTime(timeinfo->tm_mday);
sendbuffer[7] = convert_2_FroelingTime(timeinfo->tm_mon + 1);
sendbuffer[9] = convert_2_FroelingTime(timeinfo->tm_year - 100);
sendbuffer[5] = convert_2_FroelingTime(timeinfo->tm_hour);
sendbuffer[4] = convert_2_FroelingTime(timeinfo->tm_min);
sendbuffer[3] = convert_2_FroelingTime(timeinfo->tm_sec);
CreateCheckSum(sendbuffer, 10, cs);
sendbuffer[10] = cs[0];
sendbuffer[11] = cs[1];
PrintComLog(LOG_SEND, sendbuffer, 12);
ComSend(sendbuffer, 12);
return;
}
/* ---------------------------------------------------
Set a parameter on P3100
---------------------------------------------------
*/
void Set_ParamValue(T_FROE_PARAMID ParamID, int value)
{
// message prototype
// R I len | ParamID | Value | Checksum
char sendbuffer[] = {0x52, 0x49, 0x04, 0x00, 0x9b, 0x00, 0x00, 0x00, 0x00};
char cs[2];
// set ParamID in msg prototype
sendbuffer[3] = (char)((ParamID >> 8) & 0xFF);
sendbuffer[4] = (char)(ParamID & 0xFF);
// set mode in msg prototype
sendbuffer[5] = (char)((value >> 8) & 0xFF);
sendbuffer[6] = (char)(value & 0xFF);
CreateCheckSum(sendbuffer, 7, cs);
sendbuffer[7] = cs[0];
sendbuffer[8] = cs[1];
PrintComLog(LOG_SEND, sendbuffer, 9);
ComSend(sendbuffer, 9);
return;
}
/* ---------------------------------------------------
Create a Froeling Checksum
---------------------------------------------------
*/
void CreateCheckSum(char* buf, int buffsize, char* checksum)
{
unsigned short cs = 0;
int i;
for (i = 0; i < buffsize; i++) {
cs += (unsigned char)buf[i];
}
checksum[0] = (unsigned char)(cs >> 8);
checksum[1] = (unsigned char) cs;
return;
}
/* ---------------------------------------------------
Check if a checksum is correct
---------------------------------------------------
*/
int checkCheckSum(char* buf, int buffsize)
{
int i;
int result = 0;
unsigned short cs1 = 0;
unsigned short cs2 = 0;
// take last 2 bytes from received string (received checksum)
cs1 = (unsigned short)(((unsigned char)buf[buffsize - 2] * 256) + (unsigned char)buf[buffsize - 1]);
// build own checksum from received string
for (i = 0; i < (buffsize - 2); i++) {
cs2 += (unsigned char)buf[i];
}
// compare both values
if (cs1 == cs2) {
result = 1;
}
return result;
}
/* ---------------------------------------------------
Send a Froeling acknowledge
---------------------------------------------------
*/
void sendAcq(char* buf, int buffsize)
{
char b[6];
char cs[2];
if (buffsize > 1)
{
b[0] = buf[0];
b[1] = buf[1];
b[2] = 1;
b[3] = 1;
b[4] = 0;
b[5] = 0;
CreateCheckSum(b, 6, cs);
memcpy(&b[4], cs, 2);
}
ComSend(b, 6);
return;
}
/* ---------------------------------------------------
Send a "Not acknowledge" to Froeling
---------------------------------------------------
*/
void sendNAcq(char* buf, int buffsize)
{
char b[6];
char cs[2];
if (buffsize > 1)
{
b[0] = buf[0];
b[1] = buf[1];
b[2] = 1;
b[3] = 0;
b[4] = 0;
b[5] = 0;
CreateCheckSum(b, 6, cs);
memcpy(&b[4], cs, 2);
}
PrintComLog(LOG_SEND, b, 6);
ComSend(b, 6);
return;
}
/* ---------------------------------------------------
Print a debug message to console
---------------------------------------------------
*/
void PrintComLog(T_LOG_IDENT logident, char* buffer, int bufferlength)
{
//todo time_t date;
//todo struct timeb tstruct;
char stream[2048];
char tmp[64];
int i;
// get actual date and time
//todo date = time(NULL);
//todo ftime( &tstruct );
// build date/time string
//if (DEBUG==3) printf("Bildschirmausgabe\n");
switch (logident)
{
case LOG_SEND:
sprintf(stream, "<<< ");
break;
case LOG_RECEIVE:
sprintf(stream, ">>> ");
break;
case LOG_ERR:
sprintf(stream, "ERR ");
break;
case LOG_INFO:
sprintf(stream, "INF ");
break;
}
// print buffer to stdio
for (i = 0; i < bufferlength; i++) {
if (((buffer[i] >= 48) && (buffer[i] <= 57)) || \
((buffer[i] >= 65) && (buffer[i] <= 90)) || \
((buffer[i] >= 97) && (buffer[i] <= 122)))
strncat(stream, &buffer[i], 1);
}
// print an "ASCII dump"
if ((logident == LOG_SEND) || (logident == LOG_RECEIVE))
{
strcat(stream, " {");
for (i = 0; i < bufferlength; i++) {
sprintf(tmp, "%02x ", (unsigned char)buffer[i]);
strcat(stream, tmp);
}
strcat(stream, "}\n \0");
}
Serial.write(stream);
return;
}
/* ---------------------------------------------------
set cursor to screen position x,y
---------------------------------------------------
*/
void GotoXY(int x, int y)
{
char s[80];
sprintf(s, "\033[%02d;%02dH", y, x);
Serial.write(s);
}
/* ---------------------------------------------------
convert Froeling Date/Time segment to an integer value
Froeling interprets a Hex value directly as integer...
0x12 means hour = 12; 0x55 means minutes = 55
---------------------------------------------------
*/
int convert_FroelingTime(char x)
{
int y = 0;
y = (int)(x >> 4);
y = (y * 10) + (x - (y << 4));
return (y);
}
char convert_2_FroelingTime(int x)
{
char t = 0;
char y = 0;
t = ((int)(x / 10));
y = t * 16 + (x - (t * 10));
return (y);
}
/* ---------------------------------------------------
Prepare the main console screen
---------------------------------------------------
*/
void PrepareScreen(void)
{
int i;
Serial.write("\033[2J\033[1;1H"); // clearscreen
// headline
Serial.write(
"\n*********************************************************************\n"
"* Froeling P3100 communication test (Build 0), *\n"
"* Markus Kotschenreuther, 2014 *\n"
"*********************************************************************\n\n");
Serial.write("Press (CTRL + C) to abort\n");
GotoXY(0, 10);
Serial.write("Name");
GotoXY(20, 10);
Serial.write("Value");
GotoXY(0, 11);
Serial.write("-----------------------------------------------------------");
for (i = 0; i < ValueCount; i++)
{
GotoXY(0, i + 12);
Serial.write("%s", ValueNames[i]);
}
return;
}
/* --------------------------------------------------------
steigt eine bestimmete Anzahl von Zeilen zurueck
---------------------------------------------------------
*/
void LinesUp(int nrows)
{
int i = 0;
for (i = 0; i < nrows; i++) Serial.write("\033[A\033[2K");
}
void SetDataFileName(void)
{
time(&tnow);
tmnow = localtime(&tnow);
sprintf(DataFileName, "./logfiles/froeling_data_%4i-%02i-%02i.log", tmnow->tm_year + 1900, tmnow->tm_mon + 1, tmnow->tm_mday);
}