Preliminary version for serving all files for Duet

Changed webserver and network code to support multiple concurrent
connections
Removed support for differential-mode ultrasonic z-sensor
Reduced X and Y instantDv from 15 to 10 mm/sec to allow outlines of
holes to e drawn at lower speed
Changed temperature reading code to give thermistor disconnected reading
of -273C when there is a negative high ADC offset correction
This commit is contained in:
David Crocker 2014-04-06 22:50:24 +01:00
parent 9149a1eb3a
commit 68e6ed2575
11 changed files with 1284 additions and 1383 deletions

View file

@ -24,8 +24,8 @@ Licence: GPL
#define CONFIGURATION_H
#define NAME "RepRapFirmware"
#define VERSION "0.57y-dc42"
#define DATE "2014-03-28"
#define VERSION "0.57z-alpha-dc42"
#define DATE "2014-04-06"
#define LAST_AUTHOR "dc42"
// Other firmware that we might switch to be compatible with.

439
Network.cpp Normal file
View file

@ -0,0 +1,439 @@
/****************************************************************************************************
RepRapFirmware - Network: RepRapPro Ormerod with Arduino Due controller
Separated out from Platform.cpp by dc42, 2014-04-05
****************************************************************************************************/
#include "RepRapFirmware.h"
#include "DueFlashStorage.h"
const uint8_t windowedSendPackets = 2;
//***************************************************************************************************
// Network/Ethernet class
// C calls to interface with LWIP (http://savannah.nongnu.org/projects/lwip/)
// These are implemented in, and called from, a modified version of httpd.c
// in the network directory.
extern "C"
{
// Transmit data to the Network
void RepRapNetworkSendOutput(char* data, int length, void* pcb, void* hs);
// Ask whether it is OK to send
int RepRapNetworkCanSend(void* hs);
void RepRapNetworkConnectionError(void* h)
{
reprap.GetPlatform()->GetNetwork()->ConnectionError(h);
}
// Called to put out a message via the RepRap firmware.
void RepRapNetworkMessage(const char* s)
{
reprap.GetPlatform()->Message(HOST_MESSAGE, s);
}
// Called to push data into the RepRap firmware.
void RepRapNetworkReceiveInput(const char* data, int length, void* pcb, void* hs)
{
reprap.GetPlatform()->GetNetwork()->ReceiveInput(data, length, pcb, hs);
}
// Called when transmission of outgoing data is complete to allow
// the RepRap firmware to write more.
void RepRapNetworkSentPacketAcknowledged(void *hs)
{
reprap.GetPlatform()->GetNetwork()->SentPacketAcknowledged(hs);
}
} // extern "C"
Network::Network()
{
active = false;
ethPinsInit();
//ResetEther();
// Construct the free list buffer
freeTransactions = NULL;
readyTransactions = NULL;
writingTransactions = NULL;
closingTransactions = NULL;
for (int8_t i = 0; i < HTTP_STATE_SIZE; i++)
{
freeTransactions = new NetRing(freeTransactions);
}
}
void Network::AppendTransaction(NetRing** list, NetRing *r)
{
r->next = NULL;
while (*list != NULL)
{
list = &((*list)->next);
}
*list = r;
}
void Network::Init()
{
init_ethernet(reprap.GetPlatform()->IPAddress(), reprap.GetPlatform()->NetMask(), reprap.GetPlatform()->GateWay());
active = true;
}
void Network::Spin()
{
// debugPrintf("NetSpinEnter\n");
if (active)
{
ethernet_task(); // keep the Ethernet running
// See if we can send anything
NetRing* r = writingTransactions;
if (r != NULL)
{
bool doClose = r->TrySendData(); // we must leave r on the list for now because of possible callback to release the input buffer
writingTransactions = r->next;
if (doClose)
{
r->closeRequestedTime = reprap.GetPlatform()->Time();
AppendTransaction(&closingTransactions, r);
}
else
{
AppendTransaction(&writingTransactions, r);
}
}
// See if we can close any connections
r = closingTransactions;
if (r != NULL)
{
if (reprap.GetPlatform()->Time() - r->closeRequestedTime >= CLIENT_CLOSE_DELAY)
{
r->Close();
closingTransactions = r->next;
AppendTransaction(&freeTransactions, r);
}
}
}
// debugPrintf("NetSpinExit\n");
}
bool Network::HaveData() const
{
return active && readyTransactions != NULL;
}
bool Network::Read(char& b)
{
if (readyTransactions != NULL)
{
return readyTransactions->Read(b);
}
return false;
}
void Network::Write(char b)
{
if (readyTransactions != NULL)
{
readyTransactions->Write(b);
}
}
void Network::Write(const char* s)
{
if (readyTransactions != NULL)
{
readyTransactions->Write(s);
}
}
void Network::SentPacketAcknowledged(void *hs)
{
NetRing *r = writingTransactions;
while (r != NULL && r->hs != hs)
{
r = r->next;
}
if (r != NULL)
{
r->SentPacketAcknowledged();
return;
}
r = closingTransactions;
while (r != NULL && r->hs != hs)
{
r = r->next;
}
if (r != NULL)
{
r->SentPacketAcknowledged();
return;
}
debugPrintf("Network SentPacketAcknowledged: didn't find hs=%08x\n", (unsigned int)hs);
}
void Network::ConnectionError(void* hs)
{
// h points to an http state block that the caller is about to release, so we need to stop referring to it.
debugPrintf("Network: ConnectionError\n");
// See if it's a ready transaction
NetRing* r = readyTransactions;
while (r != NULL && r->hs == hs)
{
r = r->next;
}
if (r != NULL)
{
r->SetConnectionLost();
return;
}
// See if we were sending it
r = writingTransactions;
while (r != NULL && r->hs == hs)
{
r = r->next;
}
if (r != NULL)
{
r->SetConnectionLost();
return;
}
// See if we were closing it
r = closingTransactions;
while (r != NULL && r->hs == hs)
{
r = r->next;
}
if (r != NULL)
{
r->SetConnectionLost();
return;
}
// Else we didn't identify the transaction - maybe we already asked to close it
debugPrintf("Network ConnectionError: didn't find hs=%08x\n", (unsigned int)hs);
}
void Network::ReceiveInput(const char* data, int length, void* pcb, void* hs)
{
NetRing* r = freeTransactions;
if (r == NULL)
{
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::ReceiveInput() - no free transactions!\n");
return;
}
freeTransactions = r->next;
r->Set(data, length, pcb, hs);
AppendTransaction(&readyTransactions, r);
// debugPrintf("Network - input received\n");
}
// Send the output data we already have, optionally with a file appended, then close the connection.
// The file may be too large for our buffer, so we may have to send it in multiple transactions.
void Network::SendAndClose(FileStore *f)
{
NetRing *r = readyTransactions;
if (r != NULL)
{
readyTransactions = r->next;
if (r->LostConnection())
{
if (f != NULL)
{
f->Close();
}
AppendTransaction(&freeTransactions, r);
debugPrintf("Conn lost before send\n");
}
else
{
r->fileBeingSent = f;
AppendTransaction(&writingTransactions, r);
//debug
// r->outputBuffer[r->outputPointer] = 0;
// debugPrintf("Transaction queued for writing to network, file=%c, data=%s\n", (f ? 'Y' : 'N'), r->outputBuffer);
}
}
}
//queries the PHY for link status, true = link is up, false, link is down or there is some other error
bool Network::LinkIsUp()
{
return status_link_up();
}
bool Network::Active() const
{
return active;
}
// NetRing class members
NetRing::NetRing(NetRing* n) : next(n)
{
}
void NetRing::Set(const char* d, int l, void* pc, void* h)
{
pcb = pc;
hs = h;
inputData = d;
inputLength = l;
inputPointer = 0;
outputPointer = 0;
sentPacketsOutstanding = 0;
fileBeingSent = NULL;
}
// Webserver calls this to read bytes that have come in from the network
bool NetRing::Read(char& b)
{
if (LostConnection() || inputPointer >= inputLength)
{
return false;
}
b = inputData[inputPointer];
inputPointer++;
return true;
}
// Webserver calls this to write bytes that need to go out to the network
void NetRing::Write(char b)
{
if (LostConnection()) return;
if (outputPointer >= ARRAY_SIZE(outputBuffer))
{
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::Write(char b) - Output buffer overflow! \n");
return;
}
// Add the byte to the buffer
outputBuffer[outputPointer] = b;
outputPointer++;
}
// This is not called for data, only for internally-
// generated short strings at the start of a transmission,
// so it should never overflow the buffer (which is checked
// anyway).
void NetRing::Write(const char* s)
{
while (*s)
{
Write(*s++);
}
}
// Send some data if we can, returning true if all data has been sent
bool NetRing::TrySendData()
{
if (LostConnection())
{
return true;
}
if (!RepRapNetworkCanSend(hs))
{
// debugPrintf("Send busy\n");
return false;
}
if (sentPacketsOutstanding >= windowedSendPackets)
{
// debugPrintf("Awaiting ack\n");
return false; // still waiting for earlier packets to be acknowledged
}
if (fileBeingSent != NULL)
{
while (outputPointer < ARRAY_SIZE(outputBuffer))
{
bool ok = fileBeingSent->Read(outputBuffer[outputPointer]);
if (!ok)
{
fileBeingSent->Close();
fileBeingSent = NULL;
break;
}
++outputPointer;
}
// debugPrintf("Read from file\n");
}
if (outputPointer == 0)
{
// debugPrintf("All data sent\n");
return true;
// return sentPacketsOutstanding == 0; // no more data to send, so tell caller to close file if all packets acknowledged
}
else
{
// debugPrintf("Sending data, hs=%08x, length=%d\n", (unsigned int)hs, outputPointer);
++sentPacketsOutstanding;
RepRapNetworkSendOutput(outputBuffer, outputPointer, pcb, hs);
outputPointer = 0;
return false;
}
}
void NetRing::SentPacketAcknowledged()
{
if (sentPacketsOutstanding != 0)
{
--sentPacketsOutstanding;
}
}
// Close this connection. Return true if it really is closed, false if it needs to go in the deferred close list.
bool NetRing::Close()
{
if (LostConnection())
{
return true;
}
// debugPrintf("Closing connection hs=%08x\n", (unsigned int)hs);
RepRapNetworkSendOutput((char*) NULL, 0, pcb, hs);
return true; // try not using deferred close for now
}
void NetRing::SetConnectionLost()
{
hs = NULL;
}
bool NetRing::LostConnection() const
{
return hs == NULL;
}
// End

104
Network.h Normal file
View file

@ -0,0 +1,104 @@
/****************************************************************************************************
RepRapFirmware - Network: RepRapPro Ormerod with Duet controller
Separated out from Platform.h by dc42
****************************************************************************************************/
#ifndef NETWORK_H
#define NETWORK_H
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <malloc.h>
#include <stdlib.h>
#include <limits.h>
// Platform-specific includes
#include "Arduino.h"
#include "ethernet_sam.h"
// This class handles the network - typically an Ethernet.
// The size of the http output buffer is critical to getting fast load times in the browser.
// If this value is less than the TCP MSS, then Chrome under Windows will delay ack messages by about 120ms,
// which results in very slow page loading. Any value higher than that will cause the TCP packet to be split
// into multiple transmissions, which avoids this behaviour. Using a value of twice the MSS is most efficient because
// each TCP packet will be full.
// Currently we set the MSS (in file network/lwipopts.h) to 1432 which matches the value used by most versions of Windows
// and therefore avoids additional memory use and fragmentation.
const unsigned int httpOutputBufferSize = 2 * 1432;
// Start with a ring buffer to hold input from the network that needs to be responded to.
class NetRing
{
public:
friend class Network;
protected:
NetRing(NetRing* n);
void Set(const char* d, int l, void* pc, void* h);
bool Read(char& b);
void SentPacketAcknowledged();
void Write(char b);
void Write(const char* s);
bool Close();
bool TrySendData();
void SetConnectionLost();
bool LostConnection() const;
private:
void Reset();
void* pcb;
void* hs;
NetRing* next;
const char* inputData;
int inputLength;
int inputPointer;
uint8_t sentPacketsOutstanding; // count of TCP packets we have sent that have not been acknowledged
char outputBuffer[httpOutputBufferSize];
int outputPointer;
bool closePending;
FileStore *fileBeingSent;
float closeRequestedTime;
};
// The main network class that drives the network.
class Network
{
public:
void ReceiveInput(const char* data, int length, void* pc, void* h);
void InputBufferReleased(void *hs, void* pb);
void SentPacketAcknowledged(void *hs);
void ConnectionError(void* h);
bool Active() const;
bool LinkIsUp();
bool Read(char& b);
void Write(char b);
void Write(const char* s);
void SendAndClose(FileStore *f);
bool HaveData() const;
Network();
void Init();
void Spin();
private:
void AppendTransaction(NetRing** list, NetRing *r);
NetRing *freeTransactions;
NetRing *readyTransactions;
NetRing *writingTransactions;
NetRing *closingTransactions;
bool active;
};
#endif

View file

@ -286,7 +286,6 @@ void Platform::InitZProbe()
{
zProbeOnFilter.Init();
zProbeOffFilter.Init();
ResetZProbeMinSum();
if (nvData.zProbeType == 1 || nvData.zProbeType == 2)
{
@ -294,7 +293,7 @@ void Platform::InitZProbe()
digitalWrite(zProbeModulationPin, HIGH); // enable the IR LED
SetZProbing(false);
}
else if (nvData.zProbeType == 3 || nvData.zProbeType == 4)
else if (nvData.zProbeType == 3)
{
pinMode(zProbeModulationPin, OUTPUT);
digitalWrite(zProbeModulationPin, LOW); // enable the ultrasonic sensor
@ -323,20 +322,7 @@ int Platform::ZProbe()
case 2:
// Modulated IR sensor. We assume that zProbeOnFilter and zprobeOffFilter average the same number of readings.
// Because of noise, it is possible to get a negative reading, so allow for this.
return (int) (((int32_t) zProbeOnFilter.GetSum() - (int32_t) zProbeOffFilter.GetSum())
/ (4 * numZProbeReadingsAveraged));
case 4:
// Ultrasonic sensor in differential mode. We assume that zProbeOnFilter and zprobeOffFilter average the same number of readings.
{
uint32_t sum = zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum();
if (sum < zProbeMinSum)
{
zProbeMinSum = sum;
}
uint32_t total = zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum();
return (int) ((total - zProbeMinSum) / (4 * numZProbeReadingsAveraged));
}
return (int) (((int32_t) zProbeOnFilter.GetSum() - (int32_t) zProbeOffFilter.GetSum()) / (4 * numZProbeReadingsAveraged));
default:
break;
@ -355,17 +341,6 @@ int Platform::GetZProbeSecondaryValues(int& v1, int& v2)
case 2: // modulated IR sensor
v1 = (int) (zProbeOnFilter.GetSum() / (4 * numZProbeReadingsAveraged)); // pass back the reading with IR turned on
return 1;
case 4: // differential ultrasonic
{
uint32_t sum = zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum();
if (sum < zProbeMinSum)
{
zProbeMinSum = sum;
}
v1 = (int) ((zProbeOnFilter.GetSum() + zProbeOffFilter.GetSum()) / (8 * numZProbeReadingsAveraged)); // pass back the raw reading
v2 = (int) (zProbeMinSum / (8 * numZProbeReadingsAveraged)); // pass back the minimum found
}
return 2;
default:
break;
}
@ -386,7 +361,6 @@ float Platform::ZProbeStopHeight() const
case 2:
return nvData.irZProbeParameters.GetStopHeight(GetTemperature(0));
case 3:
case 4:
return nvData.ultrasonicZProbeParameters.GetStopHeight(GetTemperature(0));
default:
return 0;
@ -395,7 +369,7 @@ float Platform::ZProbeStopHeight() const
void Platform::SetZProbeType(int pt)
{
int newZProbeType = (pt >= 0 && pt <= 4) ? pt : 0;
int newZProbeType = (pt >= 0 && pt <= 3) ? pt : 0;
if (newZProbeType != nvData.zProbeType)
{
nvData.zProbeType = newZProbeType;
@ -413,7 +387,6 @@ bool Platform::GetZProbeParameters(struct ZProbeParameters& params) const
params = nvData.irZProbeParameters;
return true;
case 3:
case 4:
params = nvData.ultrasonicZProbeParameters;
return true;
default:
@ -434,7 +407,6 @@ bool Platform::SetZProbeParameters(const struct ZProbeParameters& params)
}
return true;
case 3:
case 4:
if (nvData.ultrasonicZProbeParameters != params)
{
nvData.ultrasonicZProbeParameters = params;
@ -459,15 +431,6 @@ void Platform::WriteNvData()
void Platform::SetZProbing(bool starting)
{
if (starting && nvData.zProbeType == 4)
{
ResetZProbeMinSum(); // look for a new minimum
}
}
void Platform::ResetZProbeMinSum()
{
zProbeMinSum = adRangeReal * numZProbeReadingsAveraged * 2;
}
// Note: the use of floating point time will cause the resolution to degrade over time.
@ -607,8 +570,7 @@ void Platform::DisableInterrupts()
// 0. Kick the watchdog.
// 1. Kick off a new ADC conversion.
// 2. Fetch and process the result of the last ADC conversion.
// 3a. If the last ADC conversion was for the Z probe, toggle the modulation output if using a modulated IR sensor,
// or update the minimum reading if using an ultrasonic sensor in differential mode.
// 3a. If the last ADC conversion was for the Z probe, toggle the modulation output if using a modulated IR sensor.
// 3b. If the last ADC reading was a thermistor reading, check for an over-temperature situation and turn off the heater if necessary.
// We do this here because the usual polling loop sometimes gets stuck trying to send data to the USB port.
@ -619,21 +581,19 @@ void Platform::Tick()
#ifdef TIME_TICK_ISR
uint32_t now = micros();
#endif
WDT_Restart(WDT);
WDT_Restart(WDT); // kick the watchdog
switch (tickState)
{
case 1: // last conversion started was a thermistor
case 3:
{
ThermistorAveragingFilter& currentFilter =
const_cast<ThermistorAveragingFilter&>(thermistorFilters[currentHeater]);
ThermistorAveragingFilter& currentFilter = const_cast<ThermistorAveragingFilter&>(thermistorFilters[currentHeater]);
currentFilter.ProcessReading(GetAdcReading(heaterAdcChannels[currentHeater]));
StartAdcConversion(zProbeAdcChannel);
if (currentFilter.IsValid())
{
uint32_t sum = currentFilter.GetSum();
if (sum < thermistorOverheatSums[currentHeater]
|| sum >= adDisconnectedReal * numThermistorReadingsAveraged)
if (sum < thermistorOverheatSums[currentHeater] || sum >= adDisconnectedReal * numThermistorReadingsAveraged)
{
// We have an over-temperature or bad reading from this thermistor, so turn off the heater
// NB - the SetHeater function we call does floating point maths, but this is an exceptional situation so we allow it
@ -692,7 +652,7 @@ void Platform::Tick()
/*static*/void Platform::StartAdcConversion(adc_channel_num_t chan)
{
adc_enable_channel(ADC, chan);
adc_start(ADC );
adc_start(ADC);
}
// Convert an Arduino Due pin number to the corresponding ADC channel number
@ -815,16 +775,25 @@ void Platform::ClassReport(char* className, float &lastTime)
float Platform::GetTemperature(size_t heater) const
{
// If the ADC reading is N then for an ideal ADC, the input voltage is at least N/(AD_RANGE + 1) and less than (N + 1)/(AD_RANGE + 1), times the analog reference.
// So we add 0.5 to to the reading to get a better estimate of the input. But first, recognise the special case of thermistor disconnected.
int rawTemp = GetRawTemperature(heater);
// If the ADC reading is N then for an ideal ADC, the input voltage is at least N/(AD_RANGE + 1) and less than (N + 1)/(AD_RANGE + 1), times the analog reference.
// So we add 0.5 to to the reading to get a better estimate of the input.
float reading = (float) rawTemp + 0.5;
// Recognise the special case of thermistor disconnected.
// For some ADCs, the high-end offset is negative, meaning that the ADC never returns a high enough value. We need to allow for this here.
const PidParameters& p = nvData.pidParams[heater];
if (p.adcHighOffset < 0)
{
rawTemp -= (int)p.adcHighOffset;
}
if (rawTemp >= adDisconnectedVirtual)
{
// Thermistor is disconnected
return ABS_ZERO;
return ABS_ZERO; // thermistor is disconnected
}
float reading = (float) rawTemp + 0.5;
const PidParameters& p = nvData.pidParams[heater];
// Correct for the low and high ADC offsets
reading -= p.adcLowOffset;
@ -872,8 +841,8 @@ EndStopHit Platform::Stopped(int8_t drive)
{
int zProbeVal = ZProbe();
int zProbeADValue =
(nvData.zProbeType == 3 || nvData.zProbeType == 4) ?
nvData.ultrasonicZProbeParameters.adcValue : nvData.irZProbeParameters.adcValue;
(nvData.zProbeType == 3) ? nvData.ultrasonicZProbeParameters.adcValue
: nvData.irZProbeParameters.adcValue;
if (zProbeVal >= zProbeADValue)
return lowHit;
else if (zProbeVal * 10 >= zProbeADValue * 9) // if we are at/above 90% of the target value
@ -1390,411 +1359,4 @@ void Line::Spin()
}
}
//***************************************************************************************************
// Network/Ethernet class
// C calls to interface with LWIP (http://savannah.nongnu.org/projects/lwip/)
// These are implemented in, and called from, a modified version of httpd.c
// in the network directory.
extern "C"
{
//void ResetEther();
// Transmit data to the Network
void RepRapNetworkSendOutput(char* data, int length, void* pbuf, void* pcb, void* hs);
// When lwip releases storage, set the local copy of the pointer to 0 to stop
// it being used again.
void RepRapNetworkInputBufferReleased(void* pb)
{
reprap.GetPlatform()->GetNetwork()->InputBufferReleased(pb);
}
void RepRapNetworkConnectionError(void* h)
{
reprap.GetPlatform()->GetNetwork()->ConnectionError(h);
reprap.GetWebserver()->ConnectionError();
}
// Called to put out a message via the RepRap firmware.
void RepRapNetworkMessage(char* s)
{
reprap.GetPlatform()->Message(HOST_MESSAGE, s);
}
// Called to push data into the RepRap firmware.
void RepRapNetworkReceiveInput(char* data, int length, void* pbuf, void* pcb, void* hs)
{
reprap.GetPlatform()->GetNetwork()->ReceiveInput(data, length, pbuf, pcb, hs);
}
// Called when transmission of outgoing data is complete to allow
// the RepRap firmware to write more.
void RepRapNetworkSentPacketAcknowledged()
{
reprap.GetPlatform()->GetNetwork()->SentPacketAcknowledged();
}
bool RepRapNetworkHasALiveClient()
{
return reprap.GetPlatform()->GetNetwork()->Status() & clientLive;
}
} // extern "C"
Network::Network()
{
active = false;
ethPinsInit();
//ResetEther();
// Construct the ring buffer
netRingAddPointer = new NetRing(NULL);
netRingGetPointer = netRingAddPointer;
for (int8_t i = 1; i < HTTP_STATE_SIZE; i++)
netRingGetPointer = new NetRing(netRingGetPointer);
netRingAddPointer->SetNext(netRingGetPointer);
}
// Reset the network to its disconnected and ready state.
void Network::Reset()
{
//reprap.GetPlatform()->Message(HOST_MESSAGE, "Reset.\n");
inputPointer = 0;
inputLength = -1;
outputPointer = 0;
writeEnabled = false;
closePending = false;
status = nothing;
sentPacketsOutstanding = 0;
}
void Network::CleanRing()
{
for (int8_t i = 0; i <= HTTP_STATE_SIZE; i++)
{
netRingGetPointer->Free();
netRingGetPointer = netRingGetPointer->Next();
}
netRingAddPointer = netRingGetPointer;
}
void Network::Init()
{
CleanRing();
Reset();
init_ethernet(reprap.GetPlatform()->IPAddress(), reprap.GetPlatform()->NetMask(), reprap.GetPlatform()->GateWay());
active = true;
sentPacketsOutstanding = 0;
}
void Network::Spin()
{
if (!active)
{
//ResetEther();
return;
}
// Keep the Ethernet running
ethernet_task();
// Anything come in from the network to act on?
if (!netRingGetPointer->Active())
return;
// Finished reading the active ring element?
if (!netRingGetPointer->ReadFinished())
{
// No - Finish reading any data that's been received.
if (inputPointer < inputLength)
return;
// Haven't started reading it yet - set that up.
inputPointer = 0;
inputLength = netRingGetPointer->Length();
inputBuffer = netRingGetPointer->Data();
}
}
// Webserver calls this to read bytes that have come in from the network
bool Network::Read(char& b)
{
if (inputPointer >= inputLength)
{
inputLength = -1;
inputPointer = 0;
netRingGetPointer->SetReadFinished(); // Past tense...
SetWriteEnable(true);
//reprap.GetPlatform()->Message(HOST_MESSAGE, "Network - data read.\n");
return false;
}
b = inputBuffer[inputPointer];
inputPointer++;
return true;
}
// Webserver calls this to write bytes that need to go out to the network
void Network::Write(char b)
{
// Check for horrible things...
if (!CanWrite())
{
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::Write(char b) - Attempt to write when disabled.\n");
return;
}
if (outputPointer >= ARRAY_SIZE(outputBuffer))
{
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::Write(char b) - Output buffer overflow! \n");
return;
}
// Add the byte to the buffer
outputBuffer[outputPointer] = b;
outputPointer++;
// Buffer full? If so, send it.
if (outputPointer == ARRAY_SIZE(outputBuffer))
{
#if WINDOWED_SEND_PACKETS > 1
++sentPacketsOutstanding;
#else
SetWriteEnable(false); // Stop further writing from Webserver until the network tells us that this has gone
#endif
RepRapNetworkSendOutput(outputBuffer, outputPointer, netRingGetPointer->Pbuf(), netRingGetPointer->Pcb(),
netRingGetPointer->Hs());
outputPointer = 0;
}
}
void Network::InputBufferReleased(void* pb)
{
if (netRingGetPointer->Pbuf() != pb)
{
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::InputBufferReleased() - Pointers don't match!\n");
return;
}
netRingGetPointer->ReleasePbuf();
}
void Network::ConnectionError(void* h)
{
// h points to an http state block that the caller is about to release, so we need to stop referring to it.
// The state block is usually but not always in use by the current http request being processed, in which case we abandon the current request.
if (netRingGetPointer != netRingAddPointer && netRingGetPointer->Hs() == h)
{
netRingGetPointer->Free();
netRingGetPointer = netRingGetPointer->Next();
}
// Reset the network layer. In particular, this clears the output buffer to make sure nothing more gets sent,
// and sets status to 'nothing' so that we can accept another connection attempt.
Reset();
}
void Network::ReceiveInput(char* data, int length, void* pbuf, void* pcb, void* hs)
{
status = clientLive;
if (netRingAddPointer->Active())
{
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::ReceiveInput() - Ring buffer full!\n");
return;
}
netRingAddPointer->Set(data, length, pbuf, pcb, hs);
netRingAddPointer = netRingAddPointer->Next();
//reprap.GetPlatform()->Message(HOST_MESSAGE, "Network - input received.\n");
}
bool Network::CanWrite() const
{
#if WINDOWED_SEND_PACKETS > 1
return writeEnabled && sentPacketsOutstanding < WINDOWED_SEND_PACKETS;
#else
return writeEnabled;
#endif
}
void Network::SetWriteEnable(bool enable)
{
writeEnabled = enable;
if (!writeEnabled)
return;
if (closePending)
Close();
}
void Network::SentPacketAcknowledged()
{
#if WINDOWED_SEND_PACKETS > 1
if (sentPacketsOutstanding != 0)
{
--sentPacketsOutstanding;
}
if (closePending && sentPacketsOutstanding == 0)
{
Close();
}
#else
SetWriteEnable(true);
#endif
}
// This is not called for data, only for internally-
// generated short strings at the start of a transmission,
// so it should never overflow the buffer (which is checked
// anyway).
void Network::Write(const char* s)
{
int i = 0;
while (s[i])
Write(s[i++]);
}
void Network::Close()
{
if (Status() && clientLive)
{
if (outputPointer > 0)
{
SetWriteEnable(false);
RepRapNetworkSendOutput(outputBuffer, outputPointer, netRingGetPointer->Pbuf(), netRingGetPointer->Pcb(),
netRingGetPointer->Hs());
outputPointer = 0;
closePending = true;
return;
}
RepRapNetworkSendOutput((char*) NULL, 0, netRingGetPointer->Pbuf(), netRingGetPointer->Pcb(),
netRingGetPointer->Hs());
netRingGetPointer->Free();
netRingGetPointer = netRingGetPointer->Next();
//reprap.GetPlatform()->Message(HOST_MESSAGE, "Network - output sent and closed.\n");
}
else
reprap.GetPlatform()->Message(HOST_MESSAGE, "Network::Close() - Attempt to close a closed connection!\n");
closePending = false;
status = nothing;
//Reset();
}
int8_t Network::Status() const
{
if (inputPointer >= inputLength)
return status;
return status | clientConnected | byteAvailable;
}
NetRing::NetRing(NetRing* n)
{
next = n;
Free();
}
void NetRing::Free()
{
pbuf = 0;
pcb = 0;
hs = 0;
data = "";
length = 0;
read = false;
active = false;
}
bool NetRing::Set(char* d, int l, void* pb, void* pc, void* h)
{
if (active)
return false;
pbuf = pb;
pcb = pc;
hs = h;
data = d;
length = l;
read = false;
active = true;
return true;
}
NetRing* NetRing::Next()
{
return next;
}
char* NetRing::Data()
{
return data;
}
int NetRing::Length()
{
return length;
}
bool NetRing::ReadFinished()
{
return read;
}
void NetRing::SetReadFinished()
{
read = true;
}
bool NetRing::Active()
{
return active;
}
void NetRing::SetNext(NetRing* n)
{
next = n;
}
void* NetRing::Pbuf()
{
return pbuf;
}
void NetRing::ReleasePbuf()
{
pbuf = 0;
}
void* NetRing::Pcb()
{
return pcb;
}
void* NetRing::Hs()
{
return hs;
}
void NetRing::ReleaseHs()
{
hs = 0;
}
// End

View file

@ -101,7 +101,7 @@ const unsigned int numZProbeReadingsAveraged = 8; // we average this number of r
#define MAX_FEEDRATES {50.0, 50.0, 3.0, 16.0} // mm/sec
#define ACCELERATIONS {800.0, 800.0, 10.0, 250.0} // mm/sec^2
#define DRIVE_STEPS_PER_UNIT {87.4890, 87.4890, 4000.0, 420.0}
#define INSTANT_DVS {15.0, 15.0, 0.2, 2.0} // (mm/sec)
#define INSTANT_DVS {10.0, 10.0, 0.2, 2.0} // (mm/sec)
// AXES
@ -212,21 +212,12 @@ const unsigned int adDisconnectedVirtual = adDisconnectedReal << adOversampleBit
#define CLIENT_CLOSE_DELAY 0.002
#define HTTP_STATE_SIZE 5
#define HTTP_STATE_SIZE 7
#define IP_ADDRESS {192, 168, 1, 10} // Need some sort of default...
#define NET_MASK {255, 255, 255, 0}
#define GATE_WAY {192, 168, 1, 1}
// The size of the http output buffer is critical to getting fast load times in the browser.
// If this value is less than the TCP MSS, then Chrome under Windows will delay ack messages by about 120ms,
// which results in very slow page loading. Any value higher than that will cause the TCP packet to be split
// into multiple transmissions, which avoids this behaviour. Using a value of twice the MSS is most efficient because
// each TCP packet will be full.
// Currently we set the MSS (in file network/lwipopts.h) to 1432 which matches the value used by most versions of Windows
// and therefore avoids additional memory use and fragmentation.
const unsigned int httpOutputBufferSize = 2 * 1432;
/****************************************************************************************************/
@ -263,103 +254,6 @@ enum IOStatus
clientConnected = 8
};
//// All IO is done by classes derived from this class.
//
//class InputOutput
//{
//public:
// void TakeInputFrom(InputOutput* altIp);
// void SendOutputTo(InputOutput* altOp);
//
//protected:
// InputOutput* alternateInput;
// InputOutput* alternateOutput;
//};
// This class handles the network - typically an Ethernet.
// Start with a ring buffer to hold input from the network
// that needs to be responded to.
class NetRing
{
public:
friend class Network;
protected:
NetRing(NetRing* n);
NetRing* Next();
bool Set(char* d, int l, void* pb, void* pc, void* h);
char* Data();
int Length();
bool ReadFinished();
void SetReadFinished();
void* Pbuf();
void* Pcb();
void* Hs();
bool Active();
void Free();
void SetNext(NetRing* n);
void ReleasePbuf();
void ReleaseHs();
private:
void Reset();
void* pbuf;
void* pcb;
void* hs;
char* data;
int length;
bool read;
bool active;
NetRing* next;
};
// The main network class that drives the network.
class Network //: public InputOutput
{
public:
int8_t Status() const; // Returns OR of IOStatus
bool Read(char& b);
bool CanWrite() const;
void SetWriteEnable(bool enable);
void SentPacketAcknowledged();
void Write(char b);
void Write(const char* s);
void Close();
void ReceiveInput(char* data, int length, void* pb, void* pc, void* h);
void InputBufferReleased(void* pb);
void ConnectionError(void* h);
bool Active() const;
bool LinkIsUp();
friend class Platform;
protected:
Network();
void Init();
void Spin();
private:
void Reset();
void CleanRing();
char* inputBuffer;
char outputBuffer[httpOutputBufferSize];
int inputPointer;
int inputLength;
int outputPointer;
bool writeEnabled;
bool closePending;
int8_t status;
NetRing* netRingGetPointer;
NetRing* netRingAddPointer;
bool active;
uint8_t sentPacketsOutstanding; // count of TCP packets we have sent that have not been acknowledged
};
// This class handles serial I/O - typically via USB
@ -722,7 +616,6 @@ private:
void InitialiseInterrupts();
int GetRawZHeight() const;
void ResetZProbeMinSum();
// DRIVES
@ -747,7 +640,6 @@ private:
volatile ZProbeAveragingFilter zProbeOnFilter; // Z probe readings we took with the IR turned on
volatile ZProbeAveragingFilter zProbeOffFilter; // Z probe readings we took with the IR turned off
volatile ThermistorAveragingFilter thermistorFilters[HEATERS]; // bed and extruder thermistor readings
uint32_t zProbeMinSum; // minimum Z probe sums seen, used with ultrasonic probe
// AXES
@ -1088,17 +980,5 @@ inline void Platform::PopMessageIndent()
//***************************************************************************************
//queries the PHY for link status, true = link is up, false, link is down or there is some other error
inline bool Network::LinkIsUp()
{
return status_link_up();
}
inline bool Network::Active() const
{
return active;
}
#endif

View file

@ -304,6 +304,17 @@ void RepRap::SetDebug(int d)
char scratchString[STRING_LENGTH];
// For debug use
void debugPrintf(const char* fmt, ...)
{
va_list p;
va_start(p, fmt);
vsnprintf(scratchString, ARRAY_SIZE(scratchString), fmt, p);
va_end(p);
scratchString[ARRAY_SIZE(scratchString) - 1] = 0;
reprap.GetPlatform()->Message(HOST_MESSAGE, scratchString);
}
#if 0 // no longer used, we use snprinf or sncatf instead
// Float to a string.

View file

@ -27,12 +27,14 @@ Licence: GPL
// Warn of what's to come, so we can use pointers to classes...
class Network;
class Platform;
class Webserver;
class GCodes;
class Move;
class Heat;
class RepRap;
class FileStore;
// A single instance of the RepRap class contains all the others
@ -40,8 +42,9 @@ extern RepRap reprap;
// Functions and globals not part of any class
void debugPrintf(const char* fmt, ...);
int sncatf(char *dst, size_t len, const char* fmt, ...);
#if 0 // n longer used
#if 0 // no longer used
char* ftoa(char *a, const float& f, int prec);
#endif
bool StringEndsWith(const char* string, const char* ending);
@ -55,6 +58,7 @@ int StringContains(const char* string, const char* match);
extern char scratchString[];
#include "Configuration.h"
#include "Network.h"
#include "Platform.h"
#include "Webserver.h"
#include "GCodes.h"

File diff suppressed because it is too large Load diff

View file

@ -53,7 +53,6 @@ class Webserver
void Diagnostics();
void SetPassword(const char* pw);
void SetName(const char* nm);
void ConnectionError();
void HandleReply(const char *s, bool error);
void AppendReply(const char* s);
@ -61,11 +60,9 @@ class Webserver
void ParseClientLine();
void SendFile(const char* nameOfFileToSend);
bool WriteBytes();
void ParseQualifier();
void CheckPassword();
void LoadGcodeBuffer(const char* gc, bool convertWeb);
void CloseClient();
bool PrintHeadString();
bool PrintLinkTable();
void GetGCodeList();
@ -84,8 +81,6 @@ class Webserver
bool active;
float lastTime;
float longWait;
FileStore* fileBeingSent;
bool writing;
bool receivingPost;
char postBoundary[POST_LENGTH];
int boundaryCount;
@ -94,8 +89,6 @@ class Webserver
bool postSeen;
bool getSeen;
bool clientLineIsBlank;
float clientCloseTime;
bool needToCloseClient;
char clientLine[STRING_LENGTH+2]; // 2 chars extra so we can append \n\0
char clientRequest[STRING_LENGTH];
@ -103,13 +96,12 @@ class Webserver
char jsonResponse[STRING_LENGTH+1];
char gcodeBuffer[gcodeBufLength];
unsigned int gcodeReadIndex, gcodeWriteIndex; // head and tail indices into gcodeBuffer
int jsonPointer;
int clientLinePointer;
bool gotPassword;
char password[SHORT_STRING_LENGTH+1];
char myName[SHORT_STRING_LENGTH+1];
char gcodeReply[STRING_LENGTH+1];
uint16_t seq; // reply sequence number, so that the client can tell if a reply is new or not
uint16_t seq; // reply sequence number, so that the client can tell if a json reply is new or not
};

View file

@ -61,21 +61,22 @@
#include "lwip/src/include/lwip/tcp.h"
#include "fs.h"
struct http_state {
char *file;
u16_t left;
u8_t retries;
struct http_state
{
// Receive fields
struct pbuf *pb;
// Transmit fields
char *file;
u16_t left;
u8_t retries;
};
// Prototypes for the RepRap functions in Platform.cpp that we
// need to call.
// Prototypes for the RepRap functions in Platform.cpp that we need to call.
void RepRapNetworkReceiveInput(char* ip, int length, void* pbuf, void* pcb, void* hs);
void RepRapNetworkInputBufferReleased(void* pbuf);
void RepRapNetworkConnectionError(void* h);
void RepRapNetworkMessage(char* s);
void RepRapNetworkSentPacketAcknowledged();
bool RepRapNetworkHasALiveClient();
void RepRapNetworkReceiveInput(const char* ip, int length, void* pcb, void* hs);
void RepRapNetworkConnectionError(void* hs);
void RepRapNetworkMessage(const char* s);
void RepRapNetworkSentPacketAcknowledged(void *hs);
// Sanity check on initialisations.
@ -104,7 +105,7 @@ conn_err(void *arg, err_t err)
static void
close_conn(struct tcp_pcb *pcb, struct http_state *hs)
{
//RepRapNetworkMessage("close_conn called.\n");
// RepRapNetworkMessage("close_conn called.\n");
tcp_arg(pcb, NULL);
tcp_sent(pcb, NULL);
tcp_recv(pcb, NULL);
@ -147,8 +148,6 @@ send_data(struct tcp_pcb *pcb, struct http_state *hs)
tcp_output(pcb);
hs->file += len;
hs->left -= len;
//if(hs->left <= 0)
// RepRapNetworkAllowWriting();
} else
{
RepRapNetworkMessage("send_data: error\n");
@ -160,18 +159,19 @@ send_data(struct tcp_pcb *pcb, struct http_state *hs)
static err_t
http_poll(void *arg, struct tcp_pcb *pcb)
{
struct http_state *hs;
struct http_state *hs = arg;
hs = arg;
/* printf("Polll\n");*/
if (hs == NULL) {
/* printf("Null, close\n");*/
if (hs == NULL)
{
RepRapNetworkMessage("Null, abort\n");
tcp_abort(pcb);
return ERR_ABRT;
} else {
}
else
{
++hs->retries;
if (hs->retries == 4) {
if (hs->retries == 4)
{
tcp_abort(pcb);
return ERR_ABRT;
}
@ -186,12 +186,10 @@ http_poll(void *arg, struct tcp_pcb *pcb)
static err_t
http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
{
struct http_state *hs;
struct http_state *hs = arg;
LWIP_UNUSED_ARG(len);
hs = arg;
hs->retries = 0;
//RepRapNetworkMessage("..sent\n");
@ -199,10 +197,11 @@ http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
if (hs->left > 0)
{
send_data(pcb, hs);
} else
}
else
{
// See if there is more to send
RepRapNetworkSentPacketAcknowledged();
RepRapNetworkSentPacketAcknowledged(hs);
}
return ERR_OK;
@ -210,26 +209,29 @@ http_sent(void *arg, struct tcp_pcb *pcb, u16_t len)
/*-----------------------------------------------------------------------------------*/
// ReoRap calls this with data to send.
// RepRap calls this with data to send.
// A null transmission implies the end of the data to be sent.
void RepRapNetworkSendOutput(char* data, int length, void* pb, void* pc, void* h)
void RepRapNetworkSendOutput(char* data, int length, void* pc, void* h)
{
struct pbuf* p = pb;
struct tcp_pcb* pcb = pc;
struct http_state* hs = h;
if(length <= 0)
if (hs == 0)
{
//tcp_output(pcb);
//pbuf_free(p);
close_conn(pcb, hs);
RepRapNetworkMessage("Attempt to write with null structure.\n");
return;
}
if(hs == 0)
if (hs->pb != NULL)
{
RepRapNetworkMessage("Attempt to write with null structure.\n");
pbuf_free(hs->pb);
hs->pb = NULL;
}
if (length <= 0)
{
close_conn(pcb, hs);
return;
}
@ -237,30 +239,25 @@ void RepRapNetworkSendOutput(char* data, int length, void* pb, void* pc, void* h
hs->left = length;
hs->retries = 0;
if(pb != 0)
{
RepRapNetworkInputBufferReleased(p);
pbuf_free(p);
}
send_data(pcb, hs);
//if(hs->left <= 0)
//RepRapNetworkAllowWriting();
/* Tell TCP that we wish be to informed of data that has been
successfully sent by a call to the http_sent() function. */
/* Tell TCP that we wish be to informed of data that has been successfully sent by a call to the http_sent() function. */
tcp_sent(pcb, http_sent);
}
// Return 1 if sending is OK, i.e. there is no send in progress, else 0
int RepRapNetworkCanSend(void *arg)
{
struct http_state *hs = arg;
return hs->left <= 0;
}
static err_t
http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
{
int i;
struct http_state *hs;
hs = arg;
struct http_state *hs = arg;
if (err == ERR_OK && p != NULL)
{
@ -269,16 +266,15 @@ http_recv(void *arg, struct tcp_pcb *pcb, struct pbuf *p, err_t err)
if (hs->file == NULL)
{
RepRapNetworkReceiveInput(p->payload, p->len, p, pcb, hs);
} else
hs->pb = p;
RepRapNetworkReceiveInput(p->payload, p->len, pcb, hs);
}
else
{
// We are already sending data on this connection, so not expecting any messages on it
pbuf_free(p);
}
}
if (err == ERR_OK && p == NULL) {
close_conn(pcb, hs);
}
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
@ -288,12 +284,6 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
{
struct http_state *hs;
// This is a bit nasty. Fake an out of memory error to prevent new page
// requests coming in while we are still sending the old ones.
if(RepRapNetworkHasALiveClient())
return ERR_MEM;
LWIP_UNUSED_ARG(arg);
LWIP_UNUSED_ARG(err);
@ -303,22 +293,22 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
hs = (struct http_state *)mem_malloc(sizeof(struct http_state));
if (hs == NULL) {
if (hs == NULL)
{
RepRapNetworkMessage("Out of memory!\n");
return ERR_MEM;
return ERR_MEM;
}
/* Initialize the structure. */
hs->pb = NULL;
hs->file = NULL;
hs->left = 0;
hs->retries = 0;
/* Tell TCP that this is the structure we wish to be passed for our
callbacks. */
/* Tell TCP that this is the structure we wish to be passed for our callbacks. */
tcp_arg(pcb, hs);
/* Tell TCP that we wish to be informed of incoming data by a call
to the http_recv() function. */
/* Tell TCP that we wish to be informed of incoming data by a call to the http_recv() function. */
tcp_recv(pcb, http_recv);
tcp_err(pcb, conn_err);
@ -326,6 +316,7 @@ http_accept(void *arg, struct tcp_pcb *pcb, err_t err)
tcp_poll(pcb, http_poll, 4);
return ERR_OK;
}
/*-----------------------------------------------------------------------------------*/
// This function (is)x should be called only once at the start.
@ -337,7 +328,9 @@ httpd_init(void)
initCount++;
if(initCount > 1)
{
RepRapNetworkMessage("httpd_init() called more than once.\n");
}
pcb = tcp_new();
tcp_bind(pcb, IP_ADDR_ANY, 80);

View file

@ -104,7 +104,7 @@ a lot of data that needs to be copied, this should be set high. */
#define MEMP_NUM_UDP_PCB 4
/* MEMP_NUM_TCP_PCB: the number of simultaneously active TCP connections. */
#define MEMP_NUM_TCP_PCB 2
#define MEMP_NUM_TCP_PCB 6
/* MEMP_NUM_TCP_PCB_LISTEN: the number of listening TCP connections. */
#define MEMP_NUM_TCP_PCB_LISTEN 1
/* MEMP_NUM_TCP_SEG: the number of simultaneously queued TCP segments. */