SerialConnect: implement XMODEM send.
This commit is contained in:
parent
b32b6a8633
commit
ce058fa0a9
@ -10,6 +10,7 @@ Application SerialConnect :
|
|||||||
SerialApp.cpp
|
SerialApp.cpp
|
||||||
SerialWindow.cpp
|
SerialWindow.cpp
|
||||||
TermView.cpp
|
TermView.cpp
|
||||||
|
XModem.cpp
|
||||||
encoding.c
|
encoding.c
|
||||||
input.c
|
input.c
|
||||||
parser.c
|
parser.c
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Adrien Destugues, pulkomandy@gmail.com
|
* Copyright 2012-2017, Adrien Destugues, pulkomandy@gmail.com
|
||||||
* Distributed under the terms of the MIT licence.
|
* Distributed under the terms of the MIT licence.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -65,6 +65,7 @@ const BPropertyInfo SerialApp::kScriptingProperties(sProperties);
|
|||||||
SerialApp::SerialApp()
|
SerialApp::SerialApp()
|
||||||
: BApplication(SerialApp::kApplicationSignature)
|
: BApplication(SerialApp::kApplicationSignature)
|
||||||
, fLogFile(NULL)
|
, fLogFile(NULL)
|
||||||
|
, fFileSender(NULL)
|
||||||
{
|
{
|
||||||
fWindow = new SerialWindow();
|
fWindow = new SerialWindow();
|
||||||
|
|
||||||
@ -78,6 +79,7 @@ SerialApp::SerialApp()
|
|||||||
SerialApp::~SerialApp()
|
SerialApp::~SerialApp()
|
||||||
{
|
{
|
||||||
delete fLogFile;
|
delete fLogFile;
|
||||||
|
delete fFileSender;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -99,21 +101,32 @@ void SerialApp::MessageReceived(BMessage* message)
|
|||||||
} else {
|
} else {
|
||||||
fSerialPort.Close();
|
fSerialPort.Close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Forward to the window so it can enable/disable menu items
|
||||||
|
fWindow->PostMessage(message);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case kMsgDataRead:
|
case kMsgDataRead:
|
||||||
{
|
{
|
||||||
// forward the message to the window, which will display the
|
const char* bytes;
|
||||||
// incoming data
|
ssize_t length;
|
||||||
fWindow->PostMessage(message);
|
message->FindData("data", B_RAW_TYPE, (const void**)&bytes,
|
||||||
|
&length);
|
||||||
|
|
||||||
if (fLogFile) {
|
if (fFileSender != NULL) {
|
||||||
const char* bytes;
|
if (fFileSender->BytesReceived(bytes, length)) {
|
||||||
ssize_t length;
|
delete fFileSender;
|
||||||
message->FindData("data", B_RAW_TYPE, (const void**)&bytes,
|
fFileSender = NULL;
|
||||||
&length);
|
}
|
||||||
if (fLogFile->Write(bytes, length) != length) {
|
} else {
|
||||||
// TODO error handling
|
// forward the message to the window, which will display the
|
||||||
|
// incoming data
|
||||||
|
fWindow->PostMessage(message);
|
||||||
|
|
||||||
|
if (fLogFile) {
|
||||||
|
if (fLogFile->Write(bytes, length) != length) {
|
||||||
|
// TODO error handling
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -121,6 +134,10 @@ void SerialApp::MessageReceived(BMessage* message)
|
|||||||
}
|
}
|
||||||
case kMsgDataWrite:
|
case kMsgDataWrite:
|
||||||
{
|
{
|
||||||
|
// Do not allow sending if a file transfer is in progress.
|
||||||
|
if (fFileSender != NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
const char* bytes;
|
const char* bytes;
|
||||||
ssize_t size;
|
ssize_t size;
|
||||||
|
|
||||||
@ -147,6 +164,25 @@ void SerialApp::MessageReceived(BMessage* message)
|
|||||||
debugger("Invalid BMessage received");
|
debugger("Invalid BMessage received");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case kMsgSendXmodem:
|
||||||
|
{
|
||||||
|
entry_ref ref;
|
||||||
|
|
||||||
|
if (message->FindRef("refs", &ref) == B_OK) {
|
||||||
|
BFile* file = new BFile(&ref, B_READ_ONLY);
|
||||||
|
status_t error = file->InitCheck();
|
||||||
|
if (error != B_OK)
|
||||||
|
puts(strerror(error));
|
||||||
|
else {
|
||||||
|
delete fFileSender;
|
||||||
|
fFileSender = new XModemSender(file, &fSerialPort, fWindow);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
message->PrintToStream();
|
||||||
|
debugger("Invalid BMessage received");
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
case kMsgCustomBaudrate:
|
case kMsgCustomBaudrate:
|
||||||
{
|
{
|
||||||
// open the custom baudrate selector window
|
// open the custom baudrate selector window
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012, Adrien Destugues, pulkomandy@gmail.com
|
* Copyright 2012-2017, Adrien Destugues, pulkomandy@gmail.com
|
||||||
* Distributed under the terms of the MIT licence.
|
* Distributed under the terms of the MIT licence.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -13,6 +13,8 @@
|
|||||||
#include <SerialPort.h>
|
#include <SerialPort.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
|
#include "XModem.h"
|
||||||
|
|
||||||
|
|
||||||
class BFile;
|
class BFile;
|
||||||
class SerialWindow;
|
class SerialWindow;
|
||||||
@ -44,6 +46,8 @@ class SerialApp: public BApplication
|
|||||||
BFile* fLogFile;
|
BFile* fLogFile;
|
||||||
BString fPortPath;
|
BString fPortPath;
|
||||||
|
|
||||||
|
XModemSender* fFileSender;
|
||||||
|
|
||||||
static status_t PollSerial(void*);
|
static status_t PollSerial(void*);
|
||||||
|
|
||||||
static const BPropertyInfo kScriptingProperties;
|
static const BPropertyInfo kScriptingProperties;
|
||||||
@ -57,7 +61,9 @@ enum messageConstants {
|
|||||||
kMsgDataWrite = 'dawr',
|
kMsgDataWrite = 'dawr',
|
||||||
kMsgLogfile = 'logf',
|
kMsgLogfile = 'logf',
|
||||||
kMsgOpenPort = 'open',
|
kMsgOpenPort = 'open',
|
||||||
|
kMsgProgress = 'prog',
|
||||||
kMsgSettings = 'stty',
|
kMsgSettings = 'stty',
|
||||||
|
kMsgSendXmodem = 'xmtx',
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2015, Adrien Destugues, pulkomandy@pulkomandy.tk
|
* Copyright 2012-2017, Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||||
* Distributed under the terms of the MIT licence.
|
* Distributed under the terms of the MIT licence.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -15,6 +15,7 @@
|
|||||||
#include <MenuItem.h>
|
#include <MenuItem.h>
|
||||||
#include <ScrollView.h>
|
#include <ScrollView.h>
|
||||||
#include <SerialPort.h>
|
#include <SerialPort.h>
|
||||||
|
#include <StatusBar.h>
|
||||||
|
|
||||||
#include "SerialApp.h"
|
#include "SerialApp.h"
|
||||||
#include "TermView.h"
|
#include "TermView.h"
|
||||||
@ -63,18 +64,27 @@ SerialWindow::SerialWindow()
|
|||||||
|
|
||||||
ResizeTo(r.right - 1, r.bottom + B_H_SCROLL_BAR_HEIGHT - 1);
|
ResizeTo(r.right - 1, r.bottom + B_H_SCROLL_BAR_HEIGHT - 1);
|
||||||
|
|
||||||
|
r = fTermView->Frame();
|
||||||
|
r.top = r.bottom - 37;
|
||||||
|
|
||||||
|
fStatusBar = new BStatusBar(r, "file transfer progress", NULL, NULL);
|
||||||
|
fStatusBar->SetResizingMode(B_FOLLOW_BOTTOM | B_FOLLOW_LEFT_RIGHT);
|
||||||
|
fStatusBar->SetViewUIColor(B_PANEL_BACKGROUND_COLOR);
|
||||||
|
fStatusBar->Hide();
|
||||||
|
|
||||||
AddChild(menuBar);
|
AddChild(menuBar);
|
||||||
AddChild(fTermView);
|
AddChild(fTermView);
|
||||||
AddChild(scrollBar);
|
AddChild(scrollBar);
|
||||||
|
AddChild(fStatusBar);
|
||||||
|
|
||||||
fConnectionMenu = new BMenu("Connection");
|
fConnectionMenu = new BMenu("Connection");
|
||||||
BMenu* fileMenu = new BMenu("File");
|
fFileMenu = new BMenu("File");
|
||||||
BMenu* settingsMenu = new BMenu("Settings");
|
BMenu* settingsMenu = new BMenu("Settings");
|
||||||
|
|
||||||
fConnectionMenu->SetRadioMode(true);
|
fConnectionMenu->SetRadioMode(true);
|
||||||
|
|
||||||
menuBar->AddItem(fConnectionMenu);
|
menuBar->AddItem(fConnectionMenu);
|
||||||
menuBar->AddItem(fileMenu);
|
menuBar->AddItem(fFileMenu);
|
||||||
menuBar->AddItem(settingsMenu);
|
menuBar->AddItem(settingsMenu);
|
||||||
|
|
||||||
// TODO edit menu - what's in it ?
|
// TODO edit menu - what's in it ?
|
||||||
@ -83,15 +93,17 @@ SerialWindow::SerialWindow()
|
|||||||
|
|
||||||
BMenuItem* logFile = new BMenuItem("Log to file" B_UTF8_ELLIPSIS,
|
BMenuItem* logFile = new BMenuItem("Log to file" B_UTF8_ELLIPSIS,
|
||||||
new BMessage(kMsgLogfile));
|
new BMessage(kMsgLogfile));
|
||||||
fileMenu->AddItem(logFile);
|
fFileMenu->AddItem(logFile);
|
||||||
#if 0
|
|
||||||
// TODO implement these
|
// TODO implement these
|
||||||
BMenuItem* xmodemSend = new BMenuItem("X/Y/ZModem send" B_UTF8_ELLIPSIS,
|
BMenuItem* xmodemSend = new BMenuItem("XModem send" B_UTF8_ELLIPSIS,
|
||||||
NULL);
|
new BMessage(kMsgSendXmodem));
|
||||||
fileMenu->AddItem(xmodemSend);
|
fFileMenu->AddItem(xmodemSend);
|
||||||
|
xmodemSend->SetEnabled(false);
|
||||||
|
#if 0
|
||||||
BMenuItem* xmodemReceive = new BMenuItem(
|
BMenuItem* xmodemReceive = new BMenuItem(
|
||||||
"X/Y/Zmodem receive" B_UTF8_ELLIPSIS, NULL);
|
"X/Y/Zmodem receive" B_UTF8_ELLIPSIS, NULL);
|
||||||
fileMenu->AddItem(xmodemReceive);
|
fFileMenu->AddItem(xmodemReceive);
|
||||||
|
xmodemReceive->SetEnabled(false);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Configuring all this by menus may be a bit unhandy. Make a setting
|
// Configuring all this by menus may be a bit unhandy. Make a setting
|
||||||
@ -279,6 +291,18 @@ void SerialWindow::MessageReceived(BMessage* message)
|
|||||||
{
|
{
|
||||||
switch (message->what)
|
switch (message->what)
|
||||||
{
|
{
|
||||||
|
case kMsgOpenPort:
|
||||||
|
{
|
||||||
|
BString path;
|
||||||
|
bool open = (message->FindString("port name", &path) == B_OK);
|
||||||
|
int i = 1; // Skip "log to file", which woeks even when offline.
|
||||||
|
BMenuItem* item;
|
||||||
|
while((item = fFileMenu->ItemAt(i++)))
|
||||||
|
{
|
||||||
|
item->SetEnabled(open);
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
case kMsgDataRead:
|
case kMsgDataRead:
|
||||||
{
|
{
|
||||||
const char* bytes;
|
const char* bytes;
|
||||||
@ -289,11 +313,13 @@ void SerialWindow::MessageReceived(BMessage* message)
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case kMsgLogfile:
|
case kMsgLogfile:
|
||||||
|
case kMsgSendXmodem:
|
||||||
{
|
{
|
||||||
// Let's lazy init the file panel
|
// Let's lazy init the file panel
|
||||||
if (fLogFilePanel == NULL) {
|
if (fLogFilePanel == NULL) {
|
||||||
fLogFilePanel = new BFilePanel(B_SAVE_PANEL, &be_app_messenger,
|
fLogFilePanel = new BFilePanel(
|
||||||
NULL, B_FILE_NODE, false);
|
message->what == kMsgSendXmodem ? B_OPEN_PANEL : B_SAVE_PANEL,
|
||||||
|
&be_app_messenger, NULL, B_FILE_NODE, false);
|
||||||
fLogFilePanel->SetMessage(message);
|
fLogFilePanel->SetMessage(message);
|
||||||
}
|
}
|
||||||
fLogFilePanel->Show();
|
fLogFilePanel->Show();
|
||||||
@ -391,6 +417,30 @@ void SerialWindow::MessageReceived(BMessage* message)
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
case kMsgProgress:
|
||||||
|
{
|
||||||
|
// File transfer progress
|
||||||
|
int32 pos = message->FindInt32("pos");
|
||||||
|
int32 size = message->FindInt32("size");
|
||||||
|
BString label = message->FindString("info");
|
||||||
|
|
||||||
|
if (pos >= size) {
|
||||||
|
if (!fStatusBar->IsHidden()) {
|
||||||
|
fStatusBar->Hide();
|
||||||
|
fTermView->ResizeBy(0, fStatusBar->Bounds().Height() - 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
BString text;
|
||||||
|
text.SetToFormat("%" B_PRId32 "/%" B_PRId32, pos, size);
|
||||||
|
fStatusBar->SetMaxValue(size);
|
||||||
|
fStatusBar->SetTo(pos, label, text);
|
||||||
|
if (fStatusBar->IsHidden()) {
|
||||||
|
fStatusBar->Show();
|
||||||
|
fTermView->ResizeBy(0, -(fStatusBar->Bounds().Height() - 1));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
BWindow::MessageReceived(message);
|
BWindow::MessageReceived(message);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright 2012-2015, Adrien Destugues, pulkomandy@pulkomandy.tk
|
* Copyright 2012-2017, Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||||
* Distributed under the terms of the MIT licence.
|
* Distributed under the terms of the MIT licence.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -9,6 +9,7 @@
|
|||||||
|
|
||||||
class BFilePanel;
|
class BFilePanel;
|
||||||
class BMenu;
|
class BMenu;
|
||||||
|
class BStatusBar;
|
||||||
class TermView;
|
class TermView;
|
||||||
|
|
||||||
|
|
||||||
@ -32,7 +33,9 @@ class SerialWindow: public BWindow
|
|||||||
BMenu* fFlowcontrolMenu;
|
BMenu* fFlowcontrolMenu;
|
||||||
BMenu* fBaudrateMenu;
|
BMenu* fBaudrateMenu;
|
||||||
BMenu* fLineTerminatorMenu;
|
BMenu* fLineTerminatorMenu;
|
||||||
|
BMenu* fFileMenu;
|
||||||
BFilePanel* fLogFilePanel;
|
BFilePanel* fLogFilePanel;
|
||||||
|
BStatusBar* fStatusBar;
|
||||||
|
|
||||||
static const int kBaudrates[];
|
static const int kBaudrates[];
|
||||||
static const int kBaudrateConstants[];
|
static const int kBaudrateConstants[];
|
||||||
|
129
src/apps/serialconnect/XModem.cpp
Normal file
129
src/apps/serialconnect/XModem.cpp
Normal file
@ -0,0 +1,129 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017, Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#include "XModem.h"
|
||||||
|
|
||||||
|
#include "SerialApp.h"
|
||||||
|
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
|
||||||
|
// ASCII control characters used in XMODEM protocol
|
||||||
|
static const char kSOH = 1;
|
||||||
|
static const char kEOT = 4;
|
||||||
|
static const char kACK = 6;
|
||||||
|
static const char kNAK = 21;
|
||||||
|
static const char kSUB = 26;
|
||||||
|
|
||||||
|
static const int kBlockSize = 128;
|
||||||
|
|
||||||
|
|
||||||
|
XModemSender::XModemSender(BDataIO* source, BSerialPort* sink, BHandler* listener)
|
||||||
|
: fSource(source),
|
||||||
|
fSink(sink),
|
||||||
|
fListener(listener),
|
||||||
|
fBlockNumber(0),
|
||||||
|
fEotSent(false)
|
||||||
|
{
|
||||||
|
fStatus = "Waiting for receiver" B_UTF8_ELLIPSIS;
|
||||||
|
|
||||||
|
BPositionIO* pos = dynamic_cast<BPositionIO*>(source);
|
||||||
|
if (pos)
|
||||||
|
pos->GetSize(&fSourceSize);
|
||||||
|
else
|
||||||
|
fSourceSize = 0;
|
||||||
|
|
||||||
|
NextBlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
XModemSender::~XModemSender()
|
||||||
|
{
|
||||||
|
delete fSource;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool
|
||||||
|
XModemSender::BytesReceived(const char* data, size_t length)
|
||||||
|
{
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < length; i++)
|
||||||
|
{
|
||||||
|
switch (data[i])
|
||||||
|
{
|
||||||
|
case kNAK:
|
||||||
|
if (fEotSent) {
|
||||||
|
fSink->Write(&kEOT, 1);
|
||||||
|
} else {
|
||||||
|
fStatus = "Checksum error, re-send block";
|
||||||
|
SendBlock();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case kACK:
|
||||||
|
if (fEotSent) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (NextBlock() == B_OK) {
|
||||||
|
fStatus = "Sending" B_UTF8_ELLIPSIS;
|
||||||
|
SendBlock();
|
||||||
|
} else {
|
||||||
|
fStatus = "Everything sent, waiting for acknowledge";
|
||||||
|
fSink->Write(&kEOT, 1);
|
||||||
|
fEotSent = true;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
XModemSender::SendBlock()
|
||||||
|
{
|
||||||
|
uint8_t header[3];
|
||||||
|
uint8_t checksum = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
header[0] = kSOH;
|
||||||
|
header[1] = fBlockNumber;
|
||||||
|
header[2] = 255 - fBlockNumber;
|
||||||
|
|
||||||
|
for (i = 0; i < kBlockSize; i++)
|
||||||
|
checksum += fBuffer[i];
|
||||||
|
|
||||||
|
fSink->Write(header, 3);
|
||||||
|
fSink->Write(fBuffer, kBlockSize);
|
||||||
|
fSink->Write(&checksum, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
status_t
|
||||||
|
XModemSender::NextBlock()
|
||||||
|
{
|
||||||
|
memset(fBuffer, kSUB, kBlockSize);
|
||||||
|
|
||||||
|
if (fSource->Read(fBuffer, kBlockSize) > 0) {
|
||||||
|
fBlockNumber++;
|
||||||
|
BMessage msg(kMsgProgress);
|
||||||
|
msg.AddInt32("pos", fBlockNumber);
|
||||||
|
msg.AddInt32("size", fSourceSize / kBlockSize);
|
||||||
|
msg.AddString("info", fStatus);
|
||||||
|
fListener.SendMessage(&msg);
|
||||||
|
return B_OK;
|
||||||
|
}
|
||||||
|
return B_ERROR;
|
||||||
|
}
|
44
src/apps/serialconnect/XModem.h
Normal file
44
src/apps/serialconnect/XModem.h
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2017, Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||||
|
* Distributed under terms of the MIT license.
|
||||||
|
*/
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef XMODEM_H
|
||||||
|
#define XMODEM_H
|
||||||
|
|
||||||
|
|
||||||
|
#include <Messenger.h>
|
||||||
|
#include <String.h>
|
||||||
|
|
||||||
|
|
||||||
|
class BDataIO;
|
||||||
|
class BHandler;
|
||||||
|
class BSerialPort;
|
||||||
|
|
||||||
|
|
||||||
|
class XModemSender {
|
||||||
|
public:
|
||||||
|
XModemSender(BDataIO* source, BSerialPort* sink,
|
||||||
|
BHandler* listener);
|
||||||
|
~XModemSender();
|
||||||
|
|
||||||
|
bool BytesReceived(const char* data, size_t length);
|
||||||
|
private:
|
||||||
|
|
||||||
|
void SendBlock();
|
||||||
|
status_t NextBlock();
|
||||||
|
|
||||||
|
private:
|
||||||
|
BDataIO* fSource;
|
||||||
|
BSerialPort* fSink;
|
||||||
|
BMessenger fListener;
|
||||||
|
off_t fBlockNumber;
|
||||||
|
off_t fSourceSize;
|
||||||
|
uint8_t fBuffer[128];
|
||||||
|
bool fEotSent;
|
||||||
|
BString fStatus;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#endif /* !XMODEM_H */
|
Loading…
Reference in New Issue
Block a user