SerialConnect: add scripting support
It's now possible to configure the serial port through scripting: hey SerialConnect set databits to 8 hey SerialConnect set parity to even etc. More useful is the ability to connect and disconnect from the port: hey SerialConnect get port # returns "usb0" hey SerialConnect set port to usb0 hey SerialConnect delete port This allows a script to automatically disconnect SerialConnect, do something with the serial port, and then reconnect SerialConnect. This can be used for example to run a bootloader and update a firmware through the same serial port used for debugging, something that's not easily possible on other systems.
This commit is contained in:
parent
600c0527d5
commit
d9e931526c
@ -18,6 +18,49 @@
|
||||
#include "SerialWindow.h"
|
||||
|
||||
|
||||
static property_info sProperties[] = {
|
||||
{ "baudrate",
|
||||
{ B_GET_PROPERTY, B_SET_PROPERTY, 0 },
|
||||
{ B_DIRECT_SPECIFIER, B_DIRECT_SPECIFIER, 0 },
|
||||
"get or set the baudrate",
|
||||
0, { B_INT32_TYPE }
|
||||
},
|
||||
{ "bits",
|
||||
{ B_GET_PROPERTY, B_SET_PROPERTY, 0 },
|
||||
{ B_DIRECT_SPECIFIER, B_DIRECT_SPECIFIER, 0 },
|
||||
"get or set the number of data bits (7 or 8)",
|
||||
0, { B_INT32_TYPE }
|
||||
},
|
||||
{ "stopbits",
|
||||
{ B_GET_PROPERTY, B_SET_PROPERTY, 0 },
|
||||
{ B_DIRECT_SPECIFIER, B_DIRECT_SPECIFIER, 0 },
|
||||
"get or set the number of stop bits (1 or 2)",
|
||||
0, { B_INT32_TYPE }
|
||||
},
|
||||
{ "parity",
|
||||
{ B_GET_PROPERTY, B_SET_PROPERTY, 0 },
|
||||
{ B_DIRECT_SPECIFIER, B_DIRECT_SPECIFIER, 0 },
|
||||
"get or set the parity (none, even or odd)",
|
||||
0, { B_STRING_TYPE }
|
||||
},
|
||||
{ "flowcontrol",
|
||||
{ B_GET_PROPERTY, B_SET_PROPERTY, 0 },
|
||||
{ B_DIRECT_SPECIFIER, B_DIRECT_SPECIFIER, 0 },
|
||||
"get or set the flow control (hardware, software, both, or none)",
|
||||
0, { B_STRING_TYPE }
|
||||
},
|
||||
{ "port",
|
||||
{ B_GET_PROPERTY, B_SET_PROPERTY, B_DELETE_PROPERTY, 0 },
|
||||
{ B_DIRECT_SPECIFIER, 0 },
|
||||
"get or set the port device",
|
||||
0, { B_STRING_TYPE }
|
||||
},
|
||||
{ NULL }
|
||||
};
|
||||
|
||||
const BPropertyInfo SerialApp::kScriptingProperties(sProperties);
|
||||
|
||||
|
||||
SerialApp::SerialApp()
|
||||
: BApplication(SerialApp::kApplicationSignature)
|
||||
, fLogFile(NULL)
|
||||
@ -55,7 +98,7 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
} else {
|
||||
fSerialPort.Close();
|
||||
}
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case kMsgDataRead:
|
||||
{
|
||||
@ -68,13 +111,12 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
ssize_t length;
|
||||
message->FindData("data", B_RAW_TYPE, (const void**)&bytes,
|
||||
&length);
|
||||
if (fLogFile->Write(bytes, length) != length)
|
||||
{
|
||||
if (fLogFile->Write(bytes, length) != length) {
|
||||
// TODO error handling
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case kMsgDataWrite:
|
||||
{
|
||||
@ -82,11 +124,9 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
ssize_t size;
|
||||
|
||||
if (message->FindData("data", B_RAW_TYPE, (const void**)&bytes,
|
||||
&size) != B_OK)
|
||||
break;
|
||||
|
||||
fSerialPort.Write(bytes, size);
|
||||
break;
|
||||
&size) == B_OK)
|
||||
fSerialPort.Write(bytes, size);
|
||||
return;
|
||||
}
|
||||
case kMsgLogfile:
|
||||
{
|
||||
@ -104,7 +144,7 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
puts(strerror(error));
|
||||
} else
|
||||
debugger("Invalid BMessage received");
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case kMsgSettings:
|
||||
{
|
||||
@ -131,11 +171,134 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
fSerialPort.SetDataRate(rate);
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
BApplication::MessageReceived(message);
|
||||
}
|
||||
|
||||
// Handle scripting messages
|
||||
if (message->HasSpecifiers()) {
|
||||
BMessage specifier;
|
||||
int32 what;
|
||||
int32 index;
|
||||
const char* property;
|
||||
|
||||
BMessage reply(B_REPLY);
|
||||
BMessage settings(kMsgSettings);
|
||||
bool settingsChanged = false;
|
||||
|
||||
if (message->GetCurrentSpecifier(&index, &specifier, &what, &property)
|
||||
== B_OK) {
|
||||
switch (kScriptingProperties.FindMatch(message, index, &specifier,
|
||||
what, property)) {
|
||||
case 0: // baudrate
|
||||
if (message->what == B_GET_PROPERTY) {
|
||||
reply.AddInt32("result", fSerialPort.DataRate());
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
if (message->what == B_SET_PROPERTY) {
|
||||
int32 rate = message->FindInt32("data");
|
||||
settingsChanged = true;
|
||||
settings.AddInt32("baudrate", rate);
|
||||
}
|
||||
break;
|
||||
case 1: // data bits
|
||||
if (message->what == B_GET_PROPERTY) {
|
||||
reply.AddInt32("result", fSerialPort.DataBits() + 7);
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
if (message->what == B_SET_PROPERTY) {
|
||||
int32 bits = message->FindInt32("data");
|
||||
settingsChanged = true;
|
||||
settings.AddInt32("databits", bits - 7);
|
||||
}
|
||||
break;
|
||||
case 2: // stop bits
|
||||
if (message->what == B_GET_PROPERTY) {
|
||||
reply.AddInt32("result", fSerialPort.StopBits() + 1);
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
if (message->what == B_SET_PROPERTY) {
|
||||
int32 bits = message->FindInt32("data");
|
||||
settingsChanged = true;
|
||||
settings.AddInt32("stopbits", bits - 1);
|
||||
}
|
||||
break;
|
||||
case 3: // parity
|
||||
{
|
||||
static const char* strings[] = {"none", "odd", "even"};
|
||||
if (message->what == B_GET_PROPERTY) {
|
||||
reply.AddString("result",
|
||||
strings[fSerialPort.ParityMode()]);
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
if (message->what == B_SET_PROPERTY) {
|
||||
BString bits = message->FindString("data");
|
||||
int i;
|
||||
for (i = 0; i < 3; i++) {
|
||||
if (bits == strings[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 3) {
|
||||
settingsChanged = true;
|
||||
settings.AddInt32("parity", i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 4: // flow control
|
||||
{
|
||||
static const char* strings[] = {"none", "hardware",
|
||||
"software", "both"};
|
||||
if (message->what == B_GET_PROPERTY) {
|
||||
reply.AddString("result",
|
||||
strings[fSerialPort.FlowControl()]);
|
||||
message->SendReply(&reply);
|
||||
return;
|
||||
}
|
||||
if (message->what == B_SET_PROPERTY) {
|
||||
BString bits = message->FindString("data");
|
||||
int i;
|
||||
for (i = 0; i < 4; i++) {
|
||||
if (bits == strings[i])
|
||||
break;
|
||||
}
|
||||
|
||||
if (i < 4) {
|
||||
settingsChanged = true;
|
||||
settings.AddInt32("flowcontrol", i);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case 5: // port
|
||||
if (message->what == B_GET_PROPERTY) {
|
||||
reply.AddString("port", GetPort());
|
||||
message->SendReply(&reply);
|
||||
} else if (message->what == B_DELETE_PROPERTY
|
||||
|| message->what == B_SET_PROPERTY) {
|
||||
BString path = message->FindString("data");
|
||||
BMessage openMessage(kMsgOpenPort);
|
||||
openMessage.AddString("port name", path);
|
||||
PostMessage(&openMessage);
|
||||
fWindow->PostMessage(&openMessage);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (settingsChanged) {
|
||||
PostMessage(&settings);
|
||||
fWindow->PostMessage(&settings);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
BApplication::MessageReceived(message);
|
||||
}
|
||||
|
||||
|
||||
@ -229,3 +392,25 @@ int main(int argc, char** argv)
|
||||
SerialApp app;
|
||||
app.Run();
|
||||
}
|
||||
|
||||
|
||||
status_t
|
||||
SerialApp::GetSupportedSuites(BMessage* message)
|
||||
{
|
||||
message->AddString("suites", "suite/vnd.Haiku-SerialPort");
|
||||
message->AddFlat("messages", &kScriptingProperties);
|
||||
return BApplication::GetSupportedSuites(message);
|
||||
}
|
||||
|
||||
|
||||
BHandler*
|
||||
SerialApp::ResolveSpecifier(BMessage* message, int32 index,
|
||||
BMessage* specifier, int32 what, const char* property)
|
||||
{
|
||||
if (kScriptingProperties.FindMatch(message, index, specifier, what,
|
||||
property) >= 0)
|
||||
return this;
|
||||
|
||||
return BApplication::ResolveSpecifier(message, index, specifier, what,
|
||||
property);
|
||||
}
|
||||
|
@ -9,6 +9,7 @@
|
||||
|
||||
|
||||
#include <Application.h>
|
||||
#include <PropertyInfo.h>
|
||||
#include <SerialPort.h>
|
||||
#include <String.h>
|
||||
|
||||
@ -20,28 +21,33 @@ class SerialWindow;
|
||||
class SerialApp: public BApplication
|
||||
{
|
||||
public:
|
||||
SerialApp();
|
||||
~SerialApp();
|
||||
void ReadyToRun();
|
||||
void MessageReceived(BMessage* message);
|
||||
bool QuitRequested();
|
||||
SerialApp();
|
||||
~SerialApp();
|
||||
void ReadyToRun();
|
||||
void MessageReceived(BMessage* message);
|
||||
bool QuitRequested();
|
||||
|
||||
const BString& GetPort();
|
||||
status_t GetSupportedSuites(BMessage* message);
|
||||
BHandler* ResolveSpecifier(BMessage*, int32, BMessage*, int32,
|
||||
const char*);
|
||||
|
||||
const BString& GetPort();
|
||||
|
||||
private:
|
||||
void LoadSettings();
|
||||
void SaveSettings();
|
||||
|
||||
void LoadSettings();
|
||||
void SaveSettings();
|
||||
|
||||
private:
|
||||
BSerialPort fSerialPort;
|
||||
sem_id fSerialLock;
|
||||
SerialWindow* fWindow;
|
||||
BFile* fLogFile;
|
||||
BString fPortPath;
|
||||
BSerialPort fSerialPort;
|
||||
sem_id fSerialLock;
|
||||
SerialWindow* fWindow;
|
||||
BFile* fLogFile;
|
||||
BString fPortPath;
|
||||
|
||||
static status_t PollSerial(void*);
|
||||
static status_t PollSerial(void*);
|
||||
|
||||
static const char* kApplicationSignature;
|
||||
static const BPropertyInfo kScriptingProperties;
|
||||
static const char* kApplicationSignature;
|
||||
};
|
||||
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012, Adrien Destugues, pulkomandy@gmail.com
|
||||
* Copyright 2012-2014, Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||
* Distributed under the terms of the MIT licence.
|
||||
*/
|
||||
|
||||
@ -242,6 +242,7 @@ void SerialWindow::MenusBeginning()
|
||||
new BMessage(kMsgOpenPort), 'Z', B_OPTION_KEY);
|
||||
if (!connected)
|
||||
disconnect->SetEnabled(false);
|
||||
disconnect->SetTarget(be_app);
|
||||
fConnectionMenu->AddItem(disconnect);
|
||||
} else {
|
||||
BMenuItem* noDevices = new BMenuItem("<no serial port available>", NULL);
|
||||
@ -253,16 +254,8 @@ void SerialWindow::MenusBeginning()
|
||||
|
||||
void SerialWindow::MessageReceived(BMessage* message)
|
||||
{
|
||||
switch(message->what)
|
||||
switch (message->what)
|
||||
{
|
||||
case kMsgOpenPort:
|
||||
{
|
||||
BMenuItem* disconnectMenu;
|
||||
if (message->FindPointer("source", (void**)&disconnectMenu) == B_OK)
|
||||
disconnectMenu->SetMarked(false);
|
||||
be_app->PostMessage(new BMessage(*message));
|
||||
break;
|
||||
}
|
||||
case kMsgDataRead:
|
||||
{
|
||||
const char* bytes;
|
||||
@ -270,7 +263,7 @@ void SerialWindow::MessageReceived(BMessage* message)
|
||||
if (message->FindData("data", B_RAW_TYPE, (const void**)&bytes,
|
||||
&length) == B_OK)
|
||||
fTermView->PushBytes(bytes, length);
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case kMsgLogfile:
|
||||
{
|
||||
@ -281,7 +274,7 @@ void SerialWindow::MessageReceived(BMessage* message)
|
||||
fLogFilePanel->SetMessage(message);
|
||||
}
|
||||
fLogFilePanel->Show();
|
||||
break;
|
||||
return;
|
||||
}
|
||||
case kMsgSettings:
|
||||
{
|
||||
@ -348,9 +341,9 @@ void SerialWindow::MessageReceived(BMessage* message)
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
return;
|
||||
}
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
}
|
||||
|
||||
BWindow::MessageReceived(message);
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2012, Adrien Destugues, pulkomandy@gmail.com
|
||||
* Copyright 2012-2014, Adrien Destugues, pulkomandy@pulkomandy.tk
|
||||
* Distributed under the terms of the MIT licence.
|
||||
*/
|
||||
|
||||
@ -15,24 +15,25 @@ class TermView;
|
||||
class SerialWindow: public BWindow
|
||||
{
|
||||
public:
|
||||
SerialWindow();
|
||||
~SerialWindow();
|
||||
SerialWindow();
|
||||
~SerialWindow();
|
||||
|
||||
void MenusBeginning();
|
||||
void MessageReceived(BMessage* message);
|
||||
|
||||
void MenusBeginning();
|
||||
void MessageReceived(BMessage* message);
|
||||
|
||||
private:
|
||||
TermView* fTermView;
|
||||
TermView* fTermView;
|
||||
|
||||
BMenu* fConnectionMenu;
|
||||
BMenu* fDatabitsMenu;
|
||||
BMenu* fStopbitsMenu;
|
||||
BMenu* fParityMenu;
|
||||
BMenu* fFlowcontrolMenu;
|
||||
BMenu* fBaudrateMenu;
|
||||
BFilePanel* fLogFilePanel;
|
||||
BMenu* fConnectionMenu;
|
||||
BMenu* fDatabitsMenu;
|
||||
BMenu* fStopbitsMenu;
|
||||
BMenu* fParityMenu;
|
||||
BMenu* fFlowcontrolMenu;
|
||||
BMenu* fBaudrateMenu;
|
||||
BFilePanel* fLogFilePanel;
|
||||
|
||||
static const int kBaudrates[];
|
||||
static const int kBaudrateConstants[];
|
||||
static const char* kWindowTitle;
|
||||
static const int kBaudrates[];
|
||||
static const int kBaudrateConstants[];
|
||||
static const char* kWindowTitle;
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user