Minor updates

Added chrishamm's FTP fix
Fix spurious extra command word in http parser
Minor improvements to Heat and PrintMonitor
This commit is contained in:
David Crocker 2015-12-31 12:28:35 +00:00
parent aa7bac3cc0
commit 96e8d2010b
7 changed files with 212 additions and 202 deletions

View file

@ -30,7 +30,7 @@ Licence: GPL
#endif #endif
#ifndef DATE #ifndef DATE
#define DATE "2015-12-30" #define DATE "2015-12-31"
#endif #endif
#define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman" #define AUTHORS "reprappro, dc42, zpl, t3p3, dnewman"

View file

@ -1,7 +0,0 @@
duet
thermistor
debounce
struct
arduino
extruder
deprecated

366
Heat.cpp
View file

@ -22,35 +22,34 @@ Licence: GPL
const float invHeatPwmAverageCount = HEAT_SAMPLE_TIME/HEAT_PWM_AVERAGE_TIME; const float invHeatPwmAverageCount = HEAT_SAMPLE_TIME/HEAT_PWM_AVERAGE_TIME;
Heat::Heat(Platform* p) : platform(p), active(false), coldExtrude(false), Heat::Heat(Platform* p) : platform(p), active(false), coldExtrude(false), bedHeater(BED_HEATER), chamberHeater(-1)
bedHeater(BED_HEATER), chamberHeater(-1)
{ {
for (size_t heater = 0; heater < HEATERS; heater++) for (size_t heater = 0; heater < HEATERS; heater++)
{ {
pids[heater] = new PID(platform, heater); pids[heater] = new PID(platform, heater);
} }
} }
void Heat::Init() void Heat::Init()
{ {
for (size_t heater = 0; heater < HEATERS; heater++) for (size_t heater = 0; heater < HEATERS; heater++)
{ {
pids[heater]->Init(); pids[heater]->Init();
} }
lastTime = platform->Time(); lastTime = platform->Time();
longWait = lastTime; longWait = lastTime;
coldExtrude = false; coldExtrude = false;
active = true; active = true;
} }
void Heat::Exit() void Heat::Exit()
{ {
for (size_t heater = 0; heater < HEATERS; heater++) for (size_t heater = 0; heater < HEATERS; heater++)
{ {
pids[heater]->SwitchOff(); pids[heater]->SwitchOff();
} }
platform->Message(HOST_MESSAGE, "Heat class exited.\n"); platform->Message(HOST_MESSAGE, "Heat class exited.\n");
active = false; active = false;
} }
void Heat::Spin() void Heat::Spin()
@ -72,14 +71,14 @@ void Heat::Spin()
void Heat::Diagnostics() void Heat::Diagnostics()
{ {
platform->Message(GENERIC_MESSAGE, "Heat Diagnostics:\n"); platform->Message(GENERIC_MESSAGE, "Heat Diagnostics:\n");
for (size_t heater=0; heater < HEATERS; heater++) for (size_t heater=0; heater < HEATERS; heater++)
{ {
if (pids[heater]->active) if (pids[heater]->active)
{ {
platform->MessageF(GENERIC_MESSAGE, "Heater %d: I-accumulator = %.1f\n", heater, pids[heater]->temp_iState); platform->MessageF(GENERIC_MESSAGE, "Heater %d: I-accumulator = %.1f\n", heater, pids[heater]->temp_iState);
} }
} }
} }
bool Heat::AllHeatersAtSetTemperatures(bool includingBed) const bool Heat::AllHeatersAtSetTemperatures(bool includingBed) const
@ -87,7 +86,9 @@ bool Heat::AllHeatersAtSetTemperatures(bool includingBed) const
for (int8_t heater = (includingBed) ? 0 : 1; heater < HEATERS; heater++) for (int8_t heater = (includingBed) ? 0 : 1; heater < HEATERS; heater++)
{ {
if (!HeaterAtSetTemperature(heater)) if (!HeaterAtSetTemperature(heater))
{
return false; return false;
}
} }
return true; return true;
} }
@ -96,7 +97,9 @@ bool Heat::AllHeatersAtSetTemperatures(bool includingBed) const
bool Heat::HeaterAtSetTemperature(int8_t heater) const bool Heat::HeaterAtSetTemperature(int8_t heater) const
{ {
if (pids[heater]->SwitchedOff()) // If it hasn't anything to do, it must be right wherever it is... if (pids[heater]->SwitchedOff()) // If it hasn't anything to do, it must be right wherever it is...
{
return true; return true;
}
float dt = GetTemperature(heater); float dt = GetTemperature(heater);
float target = (pids[heater]->Active()) ? GetActiveTemperature(heater) : GetStandbyTemperature(heater); float target = (pids[heater]->Active()) ? GetActiveTemperature(heater) : GetStandbyTemperature(heater);
@ -111,33 +114,32 @@ PID::PID(Platform* p, int8_t h) : platform(p), heater(h)
void PID::Init() void PID::Init()
{ {
SetHeater(0.0); SetHeater(0.0);
temperature = platform->GetTemperature(heater); temperature = platform->GetTemperature(heater);
activeTemperature = ABS_ZERO; activeTemperature = ABS_ZERO;
standbyTemperature = ABS_ZERO; standbyTemperature = ABS_ZERO;
lastTemperature = temperature; lastTemperature = temperature;
temp_iState = 0.0; temp_iState = 0.0;
badTemperatureCount = 0; badTemperatureCount = 0;
temperatureFault = false; temperatureFault = false;
active = false; // Default to standby temperature active = false; // Default to standby temperature
switchedOff = true; switchedOff = true;
heatingUp = false; heatingUp = false;
averagePWM = 0.0; averagePWM = 0.0;
// Time the sensor was last sampled. During startup, we use the current // Time the sensor was last sampled. During startup, we use the current
// time as the initial value so as to not trigger an immediate warning from // time as the initial value so as to not trigger an immediate warning from
// the Tick ISR. // the Tick ISR.
lastSampleTime = platform->Time(); lastSampleTime = platform->Time();
} }
void PID::SwitchOn() void PID::SwitchOn()
{ {
// if(reprap.Debug()) if (reprap.Debug(Module::moduleHeat))
// { {
// snprintf(scratchString, STRING_LENGTH, "Heater %d switched on.\n", heater); platform->MessageF(GENERIC_MESSAGE, "Heater %d switched on.\n", heater);
// platform->Message(BOTH_MESSAGE, scratchString); }
// } switchedOff = temperatureFault;
switchedOff = false;
} }
void PID::SetHeater(float power) const void PID::SetHeater(float power) const
@ -147,153 +149,154 @@ void PID::SetHeater(float power) const
void PID::Spin() void PID::Spin()
{ {
// For temperature sensors which do not require frequent sampling and averaging, // For temperature sensors which do not require frequent sampling and averaging,
// their temperature is read here and error/safety handling performed. However, // their temperature is read here and error/safety handling performed. However,
// unlike the Tick ISR, this code is not executed at interrupt level and consequently // unlike the Tick ISR, this code is not executed at interrupt level and consequently
// runs the risk of having undesirable delays between calls. To guard against this, // runs the risk of having undesirable delays between calls. To guard against this,
// we record for each PID object when it was last sampled and have the Tick ISR // we record for each PID object when it was last sampled and have the Tick ISR
// take action if there is a significant delay since the time of last sampling. // take action if there is a significant delay since the time of last sampling.
lastSampleTime = platform->Time(); lastSampleTime = platform->Time();
// Always know our temperature, regardless of whether we have been switched on or not // Always know our temperature, regardless of whether we have been switched on or not
Platform::TempError err = Platform::TempError::errOpen; // Initially assign an error; call should update but if it doesn't, we'll treat as an error Platform::TempError err = Platform::TempError::errOpen; // Initially assign an error; call should update but if it doesn't, we'll treat as an error
temperature = platform->GetTemperature(heater, &err); // In the event of an error, err is set and BAD_ERROR_TEMPERATURE is returned temperature = platform->GetTemperature(heater, &err); // In the event of an error, err is set and BAD_ERROR_TEMPERATURE is returned
// If we're not switched on, or there's a fault, turn the power off and go home. // If we're not switched on, or there's a fault, turn the power off and go home.
// If we're not switched on, then nothing is using us. This probably means that // If we're not switched on, then nothing is using us. This probably means that
// we don't even have a thermistor connected. So don't even check for faults if we // we don't even have a thermistor connected. So don't even check for faults if we
// are not switched on. This is safe, as the next bit of code always turns our // are not switched on. This is safe, as the next bit of code always turns our
// heater off in that case anyway. // heater off in that case anyway.
if (temperatureFault || switchedOff) if (temperatureFault || switchedOff)
{ {
SetHeater(0.0); // Make sure... SetHeater(0.0); // Make sure...
averagePWM *= (1.0 - invHeatPwmAverageCount); averagePWM *= (1.0 - invHeatPwmAverageCount);
return; return;
} }
// We are switched on. Check for faults. Temperature silly-low or silly-high mean open-circuit // We are switched on. Check for faults. Temperature silly-low or silly-high mean open-circuit
// or shorted thermistor respectively. // or shorted thermistor respectively.
if (temperature < BAD_LOW_TEMPERATURE || temperature > BAD_HIGH_TEMPERATURE) if (temperature < BAD_LOW_TEMPERATURE || temperature > BAD_HIGH_TEMPERATURE)
{ {
if (platform->DoThermistorAdc(heater) || !(Platform::TempErrorPermanent(err))) if (platform->DoThermistorAdc(heater) || !(Platform::TempErrorPermanent(err)))
{ {
// Error may be a temporary error and may correct itself after a few additional reads // Error may be a temporary error and may correct itself after a few additional reads
badTemperatureCount++; badTemperatureCount++;
} }
else else
{ {
// Error condition is not expected to correct itself (e.g., digital device such // Error condition is not expected to correct itself (e.g., digital device such
// as a MAX31855 reporting that the temp sensor is shorted -- even a temporary // as a MAX31855 reporting that the temp sensor is shorted -- even a temporary
// short in such a situation warrants manual attention and correction). // short in such a situation warrants manual attention and correction).
badTemperatureCount = MAX_BAD_TEMPERATURE_COUNT + 1; badTemperatureCount = MAX_BAD_TEMPERATURE_COUNT + 1;
} }
if (badTemperatureCount > MAX_BAD_TEMPERATURE_COUNT) if (badTemperatureCount > MAX_BAD_TEMPERATURE_COUNT)
{ {
SetHeater(0.0); SetHeater(0.0);
temperatureFault = true; temperatureFault = true;
//switchedOff = true; //switchedOff = true;
platform->MessageF(GENERIC_MESSAGE, "Temperature fault on heater %d%s%s, T = %.1f\n", platform->MessageF(GENERIC_MESSAGE, "Temperature fault on heater %d%s%s, T = %.1f\n",
heater, heater,
(err != Platform::TempError::errOk) ? ", " : "", (err != Platform::TempError::errOk) ? ", " : "",
(err != Platform::TempError::errOk) ? Platform::TempErrorStr(err) : "", (err != Platform::TempError::errOk) ? Platform::TempErrorStr(err) : "",
temperature); temperature);
reprap.FlagTemperatureFault(heater); reprap.FlagTemperatureFault(heater);
} }
} }
else else
{ {
badTemperatureCount = 0; badTemperatureCount = 0;
} }
// Now check how long it takes to warm up. If too long, maybe the thermistor is not in contact with the heater // Now check how long it takes to warm up. If too long, maybe the thermistor is not in contact with the heater
if (heatingUp && heater != BED_HEATER) // FIXME - also check bed warmup time? if (heatingUp && heater != BED_HEATER) // FIXME - also check bed warmup time?
{ {
float tmp = (active) ? activeTemperature : standbyTemperature; float tmp = (active) ? activeTemperature : standbyTemperature;
if (temperature < tmp - TEMPERATURE_CLOSE_ENOUGH) if (temperature < tmp - TEMPERATURE_CLOSE_ENOUGH)
{ {
float tim = platform->Time() - timeSetHeating; float tim = platform->Time() - timeSetHeating;
float limit = platform->TimeToHot(); float limit = platform->TimeToHot();
if (tim > limit && limit > 0.0) if (tim > limit && limit > 0.0)
{ {
SetHeater(0.0); SetHeater(0.0);
temperatureFault = true; temperatureFault = true;
//switchedOff = true; //switchedOff = true;
platform->MessageF(GENERIC_MESSAGE, "Heating fault on heater %d, T = %.1f C; still not at temperature %.1f after %f seconds.\n", heater, temperature, tmp, tim); platform->MessageF(GENERIC_MESSAGE, "Heating fault on heater %d, T = %.1f C; still not at temperature %.1f after %f seconds.\n", heater, temperature, tmp, tim);
reprap.FlagTemperatureFault(heater); reprap.FlagTemperatureFault(heater);
} }
} }
else else
{ {
heatingUp = false; heatingUp = false;
} }
} }
float targetTemperature = (active) ? activeTemperature : standbyTemperature; float targetTemperature = (active) ? activeTemperature : standbyTemperature;
float error = targetTemperature - temperature; float error = targetTemperature - temperature;
const PidParameters& pp = platform->GetPidParameters(heater); const PidParameters& pp = platform->GetPidParameters(heater);
if (!pp.UsePID())
{
float heaterValue = (error > 0.0) ? min<float>(pp.kS, 1.0) : 0.0;
SetHeater(heaterValue);
averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + heaterValue;
return;
}
if(error < -pp.fullBand)
{
// actual temperature is well above target
temp_iState = (targetTemperature + pp.fullBand - 25.0) * pp.kT; // set the I term to our estimate of what will be needed ready for the switch to PID
SetHeater(0.0);
averagePWM *= (1.0 - invHeatPwmAverageCount);
lastTemperature = temperature;
return;
}
if(error > pp.fullBand)
{
// actual temperature is well below target
temp_iState = (targetTemperature - pp.fullBand - 25.0) * pp.kT; // set the I term to our estimate of what will be needed ready for the switch to PID
float heaterValue = min<float>(pp.kS, 1.0);
SetHeater(heaterValue);
averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + heaterValue;
lastTemperature = temperature;
return;
}
float sampleInterval = platform->HeatSampleTime();
temp_iState += error * pp.kI * sampleInterval;
if (temp_iState < pp.pidMin)
{
temp_iState = pp.pidMin;
}
else if (temp_iState > pp.pidMax)
{
temp_iState = pp.pidMax;
}
float temp_dState = pp.kD * (temperature - lastTemperature) / sampleInterval;
float result = (pp.kP * error + temp_iState - temp_dState) * pp.kS / 255.0;
lastTemperature = temperature; if (!pp.UsePID())
{
float heaterValue = (error > 0.0) ? min<float>(pp.kS, 1.0) : 0.0;
SetHeater(heaterValue);
averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + heaterValue;
return;
}
if (result < 0.0) if (error < -pp.fullBand)
{ {
result = 0.0; // actual temperature is well above target
} temp_iState = (targetTemperature + pp.fullBand - 25.0) * pp.kT; // set the I term to our estimate of what will be needed ready for the switch to PID
else if (result > 1.0) SetHeater(0.0);
{ averagePWM *= (1.0 - invHeatPwmAverageCount);
result = 1.0; lastTemperature = temperature;
} return;
}
if (!temperatureFault) if (error > pp.fullBand)
{ {
SetHeater(result); // actual temperature is well below target
} temp_iState = (targetTemperature - pp.fullBand - 25.0) * pp.kT; // set the I term to our estimate of what will be needed ready for the switch to PID
float heaterValue = min<float>(pp.kS, 1.0);
SetHeater(heaterValue);
averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + heaterValue;
lastTemperature = temperature;
return;
}
averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + result; float sampleInterval = platform->HeatSampleTime();
temp_iState += error * pp.kI * sampleInterval;
if (temp_iState < pp.pidMin)
{
temp_iState = pp.pidMin;
}
else if (temp_iState > pp.pidMax)
{
temp_iState = pp.pidMax;
}
float temp_dState = pp.kD * (temperature - lastTemperature) / sampleInterval;
float result = (pp.kP * error + temp_iState - temp_dState) * pp.kS / 255.0;
lastTemperature = temperature;
if (result < 0.0)
{
result = 0.0;
}
else if (result > 1.0)
{
result = 1.0;
}
if (!temperatureFault)
{
SetHeater(result);
}
averagePWM = averagePWM * (1.0 - invHeatPwmAverageCount) + result;
// debugPrintf("Heater %d: e=%f, P=%f, I=%f, d=%f, r=%f\n", heater, error, pp.kP*error, temp_iState, temp_dState, result); // debugPrintf("Heater %d: e=%f, P=%f, I=%f, d=%f, r=%f\n", heater, error, pp.kP*error, temp_iState, temp_dState, result);
} }
@ -304,4 +307,3 @@ float PID::GetAveragePWM() const
} }
// End // End

View file

@ -137,14 +137,14 @@ a lot of data that needs to be copied, this should be set high. */
#define LWIP_TCP (1) #define LWIP_TCP (1)
#define TCP_TTL (255) #define TCP_TTL (255)
/* TCP receive window. */ /* TCP receive window. */
#define TCP_WND (2 * 1432) #define TCP_WND (2 * 1460)
/* Controls if TCP should queue segments that arrive out of /* Controls if TCP should queue segments that arrive out of
order. Define to 0 if your device is low on memory. */ order. Define to 0 if your device is low on memory. */
#define TCP_QUEUE_OOSEQ 1 #define TCP_QUEUE_OOSEQ 1
/* TCP Maximum segment size. */ /* TCP Maximum segment size. */
#define TCP_MSS (1432) // 1432 is optimal for Windows clients #define TCP_MSS (1460) // 1432 is optimal for Windows clients
/* TCP sender buffer space (bytes). */ /* TCP sender buffer space (bytes). */
#define TCP_SND_BUF (2 * 1432) //changed from 2150 to pass LWIP sanity checks #define TCP_SND_BUF (2 * 1460) //changed from 2150 to pass LWIP sanity checks
/* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */ /* TCP sender buffer space (pbufs). This must be at least = 2 * TCP_SND_BUF/TCP_MSS for things to work. */
#define TCP_SND_QUEUELEN (3 * TCP_SND_BUF / TCP_MSS) #define TCP_SND_QUEUELEN (3 * TCP_SND_BUF / TCP_MSS)
/* Maximum number of retransmissions of data segments. */ /* Maximum number of retransmissions of data segments. */

View file

@ -470,7 +470,7 @@ bool PrintMonitor::GetFileInfo(const char *directory, const char *fileName, GCod
} }
// Go to the last sector and proceed from there on // Go to the last sector and proceed from there on
const FilePosition seekFromEnd = fileBeingParsed->Length() % GCODE_READ_SIZE; const FilePosition seekFromEnd = ((fileBeingParsed->Length() - 1) % GCODE_READ_SIZE) + 1;
fileBeingParsed->Seek(fileBeingParsed->Length() - seekFromEnd); fileBeingParsed->Seek(fileBeingParsed->Length() - seekFromEnd);
fileOverlapLength = 0; fileOverlapLength = 0;
parseState = parsingFooter; parseState = parsingFooter;

Binary file not shown.

View file

@ -209,7 +209,7 @@ void Webserver::Spin()
{ {
telnetInterpreter->SendGCodeReply(transaction); telnetInterpreter->SendGCodeReply(transaction);
} }
// Process other messages (unless this is an HTTP request which may need special treatement) // Process other messages (unless this is an HTTP request which may need special treatment)
else if (interpreter != httpInterpreter || httpInterpreter->IsReady()) else if (interpreter != httpInterpreter || httpInterpreter->IsReady())
{ {
for(size_t i = 0; i < 500; i++) for(size_t i = 0; i < 500; i++)
@ -236,6 +236,7 @@ void Webserver::Spin()
} }
} }
} }
// else the HTTP server is not ready
} }
else else
{ {
@ -1042,6 +1043,10 @@ bool Webserver::HttpInterpreter::NeedMoreData()
// At this stage we've processed the first chunk of a POST upload request. Store the // At this stage we've processed the first chunk of a POST upload request. Store the
// initial payload and reset the HTTP reader again in order to process new requests // initial payload and reset the HTTP reader again in order to process new requests
WriteUploadedData(clientMessage + (clientPointer - uploadedBytes), uploadedBytes); WriteUploadedData(clientMessage + (clientPointer - uploadedBytes), uploadedBytes);
if (reprap.Debug(moduleWebserver))
{
platform->MessageF(HOST_MESSAGE, "Wrote %lu bytes of file\n", uploadedBytes);
}
ResetState(); ResetState();
return false; return false;
} }
@ -1228,7 +1233,6 @@ bool Webserver::HttpInterpreter::CharFromClient(char c)
case '\t': case '\t':
clientMessage[clientPointer++] = 0; clientMessage[clientPointer++] = 0;
qualifiers[numQualKeys].key = clientMessage + clientPointer; // so that we can read the whole value even if it contains a null qualifiers[numQualKeys].key = clientMessage + clientPointer; // so that we can read the whole value even if it contains a null
++numCommandWords;
commandWords[numCommandWords] = clientMessage + clientPointer; commandWords[numCommandWords] = clientMessage + clientPointer;
state = doingCommandWord; state = doingCommandWord;
break; break;
@ -1431,12 +1435,18 @@ bool Webserver::HttpInterpreter::ProcessMessage()
{ {
if (reprap.Debug(moduleWebserver)) if (reprap.Debug(moduleWebserver))
{ {
platform->MessageF(HOST_MESSAGE, "HTTP requests with %d command words:", numCommandWords); platform->Message(HOST_MESSAGE, "HTTP req, command words {");
for (size_t i = 0; i < numCommandWords; ++i) for (size_t i = 0; i < numCommandWords; ++i)
{ {
platform->MessageF(HOST_MESSAGE, " %s", commandWords[i]); platform->MessageF(HOST_MESSAGE, " %s", commandWords[i]);
} }
platform->Message(HOST_MESSAGE, "\n"); platform->Message(HOST_MESSAGE, " }, parameters {");
for (size_t i = 0; i < numQualKeys; ++i)
{
platform->MessageF(HOST_MESSAGE, " %s=%s", qualifiers[i].key, qualifiers[i].value);
}
platform->Message(HOST_MESSAGE, " }\n");
} }
if (numCommandWords < 2) if (numCommandWords < 2)
@ -1498,6 +1508,10 @@ bool Webserver::HttpInterpreter::ProcessMessage()
FileStore *file = platform->GetFileStore("0:/", qualifiers[0].value, true); FileStore *file = platform->GetFileStore("0:/", qualifiers[0].value, true);
if (StartUpload(file)) if (StartUpload(file))
{ {
if (reprap.Debug(moduleWebserver))
{
platform->MessageF(HOST_MESSAGE, "Start uploading file %s length %lu\n", qualifiers[0].value, postFileLength);
}
// Start new file upload // Start new file upload
uploadingTextData = false; uploadingTextData = false;
uploadedBytes = numContinuationBytes = 0; uploadedBytes = numContinuationBytes = 0;
@ -2307,27 +2321,28 @@ void Webserver::FtpInterpreter::ProcessLine()
else if (StringStartsWith(clientMessage, "RETR")) else if (StringStartsWith(clientMessage, "RETR"))
{ {
ReadFilename(4); ReadFilename(4);
FileStore *fs = platform->GetFileStore(currentDir, filename, false); FileStore *file = platform->GetFileStore(currentDir, filename, false);
if (fs == nullptr) if (file == nullptr)
{ {
SendReply(550, "Failed to open file."); SendReply(550, "Failed to open file.");
} }
else else
{ {
snprintf(ftpResponse, ftpResponseLength, "Opening data connection for %s (%lu bytes).", filename, fs->Length()); snprintf(ftpResponse, ftpResponseLength, "Opening data connection for %s (%lu bytes).", filename, file->Length());
SendReply(150, ftpResponse); SendReply(150, ftpResponse);
if (network->AcquireDataTransaction()) if (network->AcquireDataTransaction())
{ {
// send the file via data port // send the file via data port
NetworkTransaction *dataTransaction = network->GetTransaction(); NetworkTransaction *dataTransaction = network->GetTransaction();
dataTransaction->SetFileToWrite(fs); dataTransaction->SetFileToWrite(file);
dataTransaction->Commit(false); dataTransaction->Commit(false);
state = doingPasvIO; state = doingPasvIO;
} }
else else
{ {
file->Close();
SendReply(500, "Unknown error."); SendReply(500, "Unknown error.");
network->CloseDataPort(); network->CloseDataPort();
state = authenticated; state = authenticated;