From e87f2fe79d59681fc1a3acce58eccddf56ef49b9 Mon Sep 17 00:00:00 2001 From: Wolfgang Thaller Date: Mon, 7 May 2018 22:39:24 +0200 Subject: [PATCH] LaunchAPPLServer: Extend status display --- LaunchAPPL/Common/ReliableStream.cc | 4 + LaunchAPPL/Common/ReliableStream.h | 5 + LaunchAPPL/Server/LaunchAPPLServer.cc | 3 + LaunchAPPL/Server/LaunchAPPLServer.r | 14 ++- LaunchAPPL/Server/StatusDisplay.cc | 158 ++++++++++++++++++++++++-- LaunchAPPL/Server/StatusDisplay.h | 16 ++- 6 files changed, 187 insertions(+), 13 deletions(-) diff --git a/LaunchAPPL/Common/ReliableStream.cc b/LaunchAPPL/Common/ReliableStream.cc index 1f3598540a..43aedbb7a7 100644 --- a/LaunchAPPL/Common/ReliableStream.cc +++ b/LaunchAPPL/Common/ReliableStream.cc @@ -46,6 +46,8 @@ void ReliableStream::reset(int sendReset) sentOutputPacket = 0; ackedOutputPacket = 0; + failedReceiveCount = failedSendCount = 0; + incomingPacket.clear(); state = State::waiting; sentPackets.clear(); @@ -82,6 +84,7 @@ void ReliableStream::nack() }; underlying().write(packet, 8); //printf("nack sent\n"); + failedReceiveCount++; } void ReliableStream::gotAck(uint8_t id) @@ -111,6 +114,7 @@ void ReliableStream::gotNack(uint8_t id) sentOutputPacket = ackedOutputPacket; + failedSendCount += packetsToSend.size(); packetsToSend.splice(packetsToSend.begin(), sentPackets); sendPackets(); diff --git a/LaunchAPPL/Common/ReliableStream.h b/LaunchAPPL/Common/ReliableStream.h index 20e55b57e6..38f2815ae4 100644 --- a/LaunchAPPL/Common/ReliableStream.h +++ b/LaunchAPPL/Common/ReliableStream.h @@ -32,6 +32,9 @@ class ReliableStream : public StreamWrapper unsigned sentOutputPacket = 0; unsigned ackedOutputPacket = 0; + unsigned failedReceiveCount = 0; + unsigned failedSendCount = 0; + State state = State::waiting; std::vector incomingPacket; int inputMatchMagic1, inputMatchMagic2; @@ -55,6 +58,8 @@ public: virtual bool readyToWrite() { return packetsToSend.empty() && underlying().readyToWrite(); } bool allDataArrived() { return packetsToSend.empty() && sentPackets.empty() && underlying().readyToWrite(); } + unsigned getFailedReceiveCount() const { return failedReceiveCount; } + unsigned getFailedSendCount() const { return failedSendCount; } }; #endif diff --git a/LaunchAPPL/Server/LaunchAPPLServer.cc b/LaunchAPPL/Server/LaunchAPPLServer.cc index 1eabed27ec..1589a1e3cf 100644 --- a/LaunchAPPL/Server/LaunchAPPLServer.cc +++ b/LaunchAPPL/Server/LaunchAPPLServer.cc @@ -526,7 +526,10 @@ int main() nullEventCounter++; if(server.state != LaunchServer::State::wait) + { stream.idle(); + statusDisplay->SetErrorCount(rStream.getFailedReceiveCount() + rStream.getFailedSendCount()); + } statusDisplay->Idle(); if(server.state == LaunchServer::State::launch) diff --git a/LaunchAPPL/Server/LaunchAPPLServer.r b/LaunchAPPL/Server/LaunchAPPLServer.r index 9f9ff5a36e..9b591d2157 100644 --- a/LaunchAPPL/Server/LaunchAPPLServer.r +++ b/LaunchAPPL/Server/LaunchAPPLServer.r @@ -96,7 +96,7 @@ resource 'WIND' (129, "Main") { centerMainScreen; }; -resource 'STR#' (128) { +resource 'STR#' (128, purgeable) { { "Listening on Modem Port..."; "Downloading Application..."; @@ -105,7 +105,17 @@ resource 'STR#' (128) { } }; - +resource 'STR#' (129, purgeable) { + { + "Heap Size:", " KB"; + "Free Memory:", " KB"; + "File Size:", " KB"; + "Transferred:", " KB"; + "Speed:", " B/s"; + "Time remaining:", " s"; + "Transmission errors:", ""; + } +}; resource 'SIZE' (-1) { dontSaveScreen, diff --git a/LaunchAPPL/Server/StatusDisplay.cc b/LaunchAPPL/Server/StatusDisplay.cc index af691aacb4..6369794e32 100644 --- a/LaunchAPPL/Server/StatusDisplay.cc +++ b/LaunchAPPL/Server/StatusDisplay.cc @@ -1,6 +1,22 @@ #include "StatusDisplay.h" #include #include +#include + +const short tableTop = 50; +const short tableLineHeight = 20; +const short tableBaseline = 15; + +enum class StatusDisplay::Stat : short +{ + heapSize, + freeMem, + fileSize, + transferred, + speed, + timeRemaining, + transmissionErrors +}; StatusDisplay::StatusDisplay() { @@ -10,12 +26,48 @@ StatusDisplay::StatusDisplay() SetRect(&statusRect, 10, 0, bounds.right-10, 30); SetRect(&progressRect, 10, 30, bounds.right-10, 46); - SetRect(&memRect, 10, 70, bounds.right-10, 100); + + memset(columnWidths, 0, sizeof(columnWidths)); + columnWidths[1] = columnWidths[4] = 50; + + SetPort(statusWindow); + TextSize(9); + TextFace(bold); + for(int i = 0; i < 2 * nValues; i++) + { + Str255 str; + GetIndString(str, 129, i+1); + short& col = columnWidths[(i&1)*2 + (i&2)*3/2]; + col = std::max(col, StringWidth(str)); + } + + for(int i = 0; i < nValues; i+=2) + { + SetRect(&valueRects[i], + 10 + columnWidths[0], + tableTop + i/2 * tableLineHeight, + 10 + columnWidths[0] + columnWidths[1], + tableTop + (i/2+1) * tableLineHeight); + } + for(int i = 1; i < nValues; i+=2) + { + SetRect(&valueRects[i], + bounds.right - 10 - columnWidths[5] - columnWidths[4], + tableTop + i/2 * tableLineHeight, + bounds.right - 10 - columnWidths[5], + tableTop + (i/2+1) * tableLineHeight); + } + RgnHandle tmp = NewRgn(); background = NewRgn(); RectRgn(background, &bounds); RectRgn(tmp, &progressRect); DiffRgn(background, tmp, background); + for(int i = 0; i < nValues; i++) + { + RectRgn(tmp, &valueRects[i]); + DiffRgn(background, tmp, background); + } DisposeRgn(tmp); SetStatus(AppStatus::ready); @@ -27,6 +79,24 @@ StatusDisplay::~StatusDisplay() DisposeRgn(background); } +void StatusDisplay::DrawValue(Stat stat, ConstStr255Param str) +{ + Rect& r = valueRects[(short)stat]; + MoveTo(r.right - StringWidth(str), r.top + tableBaseline); + EraseRect(&r); + DrawString(str); +} +void StatusDisplay::DrawValue(Stat stat, long val) +{ + Str255 str; + NumToString(val, str); + if(val >= 0) + DrawValue(stat, str); + else + DrawValue(stat, "\p--"); +} + + void StatusDisplay::Update() { #if TARGET_API_MAC_CARBON @@ -37,6 +107,9 @@ void StatusDisplay::Update() BeginUpdate(statusWindow); EraseRgn(background); + TextSize(12); + TextFace(normal); + MoveTo(statusRect.left,statusRect.bottom-10); DrawString(statusString); @@ -58,23 +131,73 @@ void StatusDisplay::Update() EraseRect(&progressRect); Str255 str; - NumToString(freeMem, str); - MoveTo(memRect.left,memRect.bottom-10); - DrawString(str); DrawString("\p / "); - NumToString(ApplicationZone()->bkLim - (Ptr)ApplicationZone(), str); - DrawString(str); DrawString("\p bytes free"); + + TextSize(9); + TextFace(bold); + + for(int i = 0; i < nValues; i++) + { + GetIndString(str, 129, (i*2)+1); + MoveTo(valueRects[i].left - StringWidth(str), valueRects[i].top + tableBaseline); + DrawString(str); + GetIndString(str, 129, (i*2)+2); + MoveTo(valueRects[i].right, valueRects[i].top + tableBaseline); + DrawString(str); + } + + TextFace(normal); + DrawValue(Stat::heapSize, (ApplicationZone()->bkLim - (Ptr)ApplicationZone()) / 1024); + DrawValue(Stat::freeMem, freeMem); + if(progressTotal) + { + DrawValue(Stat::fileSize, progressTotal / 1024); + DrawValue(Stat::transferred, progressDone / 1024); + } + else + { + DrawValue(Stat::fileSize, "\p--"); + DrawValue(Stat::transferred, "\p--"); + } + DrawValue(Stat::speed, speed); + DrawValue(Stat::timeRemaining, timeRemaining); + DrawValue(Stat::transmissionErrors, errorCount); EndUpdate(statusWindow); } void StatusDisplay::Idle() { - long newFreeMem = FreeMem(); + long newFreeMem = FreeMem() / 1024; if(newFreeMem != freeMem) { freeMem = newFreeMem; SetPort(statusWindow); - InvalRect(&memRect); + InvalRect(&valueRects[(short)Stat::freeMem]); + } + + long newTimeRemaining = -1; + if(status == AppStatus::downloading) + { + long now = TickCount(); + if(now - startTime > 60 && progressDone > 4000) + { + long newSpeed = progressDone * 6015LL / (now-startTime) / 100; + newTimeRemaining = (uint64_t(now-startTime) * (progressTotal - progressDone) * 100 + / progressDone + 6014) / 6015; + if(newSpeed != speed) + { + speed = newSpeed; + SetPort(statusWindow); + InvalRect(&valueRects[(short)Stat::speed]); + } + } + } + + if(newTimeRemaining != timeRemaining) + { + timeRemaining = newTimeRemaining; + SetPort(statusWindow); + InvalRect(&valueRects[(short)Stat::timeRemaining]); } } @@ -83,6 +206,8 @@ void StatusDisplay::SetStatus(AppStatus stat) if(stat != status) { status = stat; + if(status == AppStatus::downloading) + startTime = TickCount(); GetIndString(statusString,128,(short)stat); SetPort(statusWindow); InvalRect(&statusRect); @@ -93,10 +218,13 @@ void StatusDisplay::SetProgress(int done, int total) { if(done != progressDone || total != progressTotal) { - progressTotal = total; - progressDone = done; SetPort(statusWindow); InvalRect(&progressRect); + if(total != progressTotal) + InvalRect(&valueRects[(short)Stat::fileSize]); + InvalRect(&valueRects[(short)Stat::transferred]); + progressTotal = total; + progressDone = done; } } @@ -105,3 +233,13 @@ void StatusDisplay::SetStatus(AppStatus stat, int done, int total) SetStatus(stat); SetProgress(done, total); } + +void StatusDisplay::SetErrorCount(int newErrorCount) +{ + if(newErrorCount != errorCount) + { + errorCount = newErrorCount; + SetPort(statusWindow); + InvalRect(&valueRects[(short)Stat::transmissionErrors]); + } +} diff --git a/LaunchAPPL/Server/StatusDisplay.h b/LaunchAPPL/Server/StatusDisplay.h index 99e3c9f8a2..55394ba8f7 100644 --- a/LaunchAPPL/Server/StatusDisplay.h +++ b/LaunchAPPL/Server/StatusDisplay.h @@ -18,11 +18,24 @@ class StatusDisplay AppStatus status = AppStatus::empty; int progressDone, progressTotal = 0; long freeMem; + long startTime; + long speed = -1; + long timeRemaining = -1; + int errorCount; RgnHandle background; Rect statusRect; Rect progressRect; - Rect memRect; + + static const int nValues = 7; + Rect valueRects[nValues]; + short columnWidths[6]; + + enum class Stat : short; + + void DrawValue(Stat stat, ConstStr255Param str); + void DrawValue(Stat stat, long val); + public: StatusDisplay(); ~StatusDisplay(); @@ -35,4 +48,5 @@ public: void SetStatus(AppStatus s); void SetProgress(int done = 0, int total = 0); void SetStatus(AppStatus stat, int done, int total); + void SetErrorCount(int errorCount); };