Make SerialConnect more complete
* Mark the current connected device, or disable "Disconnect" menu when there is no connection. * Save and restore serial port settings * Improve drawing code: make sure the border around the termview is repainted, and do not leave a 1px space between lines unpainted.
This commit is contained in:
@@ -12,6 +12,8 @@
|
||||
#include <Directory.h>
|
||||
#include <Entry.h>
|
||||
#include <File.h>
|
||||
#include <FindDirectory.h>
|
||||
#include <Path.h>
|
||||
|
||||
#include "SerialWindow.h"
|
||||
|
||||
@@ -37,6 +39,7 @@ SerialApp::~SerialApp()
|
||||
|
||||
void SerialApp::ReadyToRun()
|
||||
{
|
||||
LoadSettings();
|
||||
fWindow->Show();
|
||||
}
|
||||
|
||||
@@ -47,10 +50,9 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
{
|
||||
case kMsgOpenPort:
|
||||
{
|
||||
const char* portName;
|
||||
if(message->FindString("port name", &portName) == B_OK)
|
||||
if(message->FindString("port name", &fPortPath) == B_OK)
|
||||
{
|
||||
fSerialPort.Open(portName);
|
||||
fSerialPort.Open(fPortPath);
|
||||
release_sem(fSerialLock);
|
||||
} else {
|
||||
fSerialPort.Close();
|
||||
@@ -207,6 +209,62 @@ void SerialApp::MessageReceived(BMessage* message)
|
||||
}
|
||||
|
||||
|
||||
bool SerialApp::QuitRequested()
|
||||
{
|
||||
if(BApplication::QuitRequested()) {
|
||||
SaveSettings();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
const BString& SerialApp::GetPort()
|
||||
{
|
||||
return fPortPath;
|
||||
}
|
||||
|
||||
|
||||
void SerialApp::LoadSettings()
|
||||
{
|
||||
BPath path;
|
||||
find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
path.Append("SerialConnect");
|
||||
|
||||
BFile file(path.Path(), B_READ_ONLY);
|
||||
BMessage message(kMsgSettings);
|
||||
if(message.Unflatten(&file) != B_OK)
|
||||
{
|
||||
message.AddInt32("parity", fSerialPort.ParityMode());
|
||||
message.AddInt32("databits", fSerialPort.DataBits());
|
||||
message.AddInt32("stopbits", fSerialPort.StopBits());
|
||||
message.AddInt32("baudrate", fSerialPort.DataRate());
|
||||
message.AddInt32("flowcontrol", fSerialPort.FlowControl());
|
||||
}
|
||||
|
||||
be_app->PostMessage(&message);
|
||||
fWindow->PostMessage(&message);
|
||||
}
|
||||
|
||||
|
||||
void SerialApp::SaveSettings()
|
||||
{
|
||||
BMessage message(kMsgSettings);
|
||||
message.AddInt32("parity", fSerialPort.ParityMode());
|
||||
message.AddInt32("databits", fSerialPort.DataBits());
|
||||
message.AddInt32("stopbits", fSerialPort.StopBits());
|
||||
message.AddInt32("baudrate", fSerialPort.DataRate());
|
||||
message.AddInt32("flowcontrol", fSerialPort.FlowControl());
|
||||
|
||||
BPath path;
|
||||
find_directory(B_USER_SETTINGS_DIRECTORY, &path);
|
||||
path.Append("SerialConnect");
|
||||
|
||||
BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE);
|
||||
message.Flatten(&file);
|
||||
}
|
||||
|
||||
|
||||
/* static */
|
||||
status_t SerialApp::PollSerial(void*)
|
||||
{
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
|
||||
#include <Application.h>
|
||||
#include <SerialPort.h>
|
||||
#include <String.h>
|
||||
|
||||
|
||||
class BFile;
|
||||
@@ -23,12 +24,20 @@ class SerialApp: public BApplication
|
||||
~SerialApp();
|
||||
void ReadyToRun();
|
||||
void MessageReceived(BMessage* message);
|
||||
bool QuitRequested();
|
||||
|
||||
const BString& GetPort();
|
||||
|
||||
private:
|
||||
void LoadSettings();
|
||||
void SaveSettings();
|
||||
|
||||
private:
|
||||
BSerialPort fSerialPort;
|
||||
sem_id fSerialLock;
|
||||
SerialWindow* fWindow;
|
||||
BFile* fLogFile;
|
||||
BString fPortPath;
|
||||
|
||||
static status_t PollSerial(void*);
|
||||
|
||||
|
||||
@@ -19,6 +19,14 @@
|
||||
#include "TermView.h"
|
||||
|
||||
|
||||
const int SerialWindow::kBaudrates[] = { 50, 75, 110, 134, 150, 200, 300, 600,
|
||||
1200, 1800, 2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200, 230400
|
||||
};
|
||||
|
||||
|
||||
const char* SerialWindow::kWindowTitle = "SerialConnect";
|
||||
|
||||
|
||||
SerialWindow::SerialWindow()
|
||||
: BWindow(BRect(100, 100, 400, 400), SerialWindow::kWindowTitle,
|
||||
B_DOCUMENT_WINDOW, B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS)
|
||||
@@ -49,34 +57,37 @@ SerialWindow::SerialWindow()
|
||||
BMenuItem* logFile = new BMenuItem("Log to file" B_UTF8_ELLIPSIS,
|
||||
new BMessage(kMsgLogfile));
|
||||
fileMenu->AddItem(logFile);
|
||||
#if 0
|
||||
// TODO implement these
|
||||
BMenuItem* xmodemSend = new BMenuItem("X/Y/ZModem send" B_UTF8_ELLIPSIS,
|
||||
NULL);
|
||||
fileMenu->AddItem(xmodemSend);
|
||||
BMenuItem* xmodemReceive = new BMenuItem(
|
||||
"X/Y/Zmodem receive" B_UTF8_ELLIPSIS, NULL);
|
||||
fileMenu->AddItem(xmodemReceive);
|
||||
#endif
|
||||
|
||||
// Configuring all this by menus may be a bit unhandy. Make a setting
|
||||
// window instead ?
|
||||
BMenu* baudRate = new BMenu("Baud rate");
|
||||
baudRate->SetRadioMode(true);
|
||||
settingsMenu->AddItem(baudRate);
|
||||
fBaudrateMenu = new BMenu("Baud rate");
|
||||
fBaudrateMenu->SetRadioMode(true);
|
||||
settingsMenu->AddItem(fBaudrateMenu);
|
||||
|
||||
BMenu* parity = new BMenu("Parity");
|
||||
parity->SetRadioMode(true);
|
||||
settingsMenu->AddItem(parity);
|
||||
fParityMenu = new BMenu("Parity");
|
||||
fParityMenu->SetRadioMode(true);
|
||||
settingsMenu->AddItem(fParityMenu);
|
||||
|
||||
BMenu* stopBits = new BMenu("Stop bits");
|
||||
stopBits->SetRadioMode(true);
|
||||
settingsMenu->AddItem(stopBits);
|
||||
fStopbitsMenu = new BMenu("Stop bits");
|
||||
fStopbitsMenu->SetRadioMode(true);
|
||||
settingsMenu->AddItem(fStopbitsMenu);
|
||||
|
||||
BMenu* flowControl = new BMenu("Flow control");
|
||||
flowControl->SetRadioMode(true);
|
||||
settingsMenu->AddItem(flowControl);
|
||||
fFlowcontrolMenu = new BMenu("Flow control");
|
||||
fFlowcontrolMenu->SetRadioMode(true);
|
||||
settingsMenu->AddItem(fFlowcontrolMenu);
|
||||
|
||||
BMenu* dataBits = new BMenu("Data bits");
|
||||
dataBits->SetRadioMode(true);
|
||||
settingsMenu->AddItem(dataBits);
|
||||
fDatabitsMenu = new BMenu("Data bits");
|
||||
fDatabitsMenu->SetRadioMode(true);
|
||||
settingsMenu->AddItem(fDatabitsMenu);
|
||||
|
||||
|
||||
BMessage* message = new BMessage(kMsgSettings);
|
||||
@@ -90,12 +101,11 @@ SerialWindow::SerialWindow()
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("parity", B_EVEN_PARITY);
|
||||
BMenuItem* parityEven = new BMenuItem("Even", message);
|
||||
parityNone->SetMarked(true);
|
||||
|
||||
parity->AddItem(parityNone);
|
||||
parity->AddItem(parityOdd);
|
||||
parity->AddItem(parityEven);
|
||||
parity->SetTargetForItems(be_app);
|
||||
fParityMenu->AddItem(parityNone);
|
||||
fParityMenu->AddItem(parityOdd);
|
||||
fParityMenu->AddItem(parityEven);
|
||||
fParityMenu->SetTargetForItems(be_app);
|
||||
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("databits", B_DATA_BITS_7);
|
||||
@@ -104,52 +114,41 @@ SerialWindow::SerialWindow()
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("databits", B_DATA_BITS_8);
|
||||
BMenuItem* data8 = new BMenuItem("8", message);
|
||||
data8->SetMarked(true);
|
||||
|
||||
dataBits->AddItem(data7);
|
||||
dataBits->AddItem(data8);
|
||||
dataBits->SetTargetForItems(be_app);
|
||||
fDatabitsMenu->AddItem(data7);
|
||||
fDatabitsMenu->AddItem(data8);
|
||||
fDatabitsMenu->SetTargetForItems(be_app);
|
||||
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("stopbits", B_STOP_BITS_1);
|
||||
BMenuItem* stop1 = new BMenuItem("1", NULL);
|
||||
BMenuItem* stop1 = new BMenuItem("1", message);
|
||||
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("stopbits", B_STOP_BITS_2);
|
||||
BMenuItem* stop2 = new BMenuItem("2", NULL);
|
||||
stop1->SetMarked(true);
|
||||
BMenuItem* stop2 = new BMenuItem("2", message);
|
||||
|
||||
stopBits->AddItem(stop1);
|
||||
stopBits->AddItem(stop2);
|
||||
stopBits->SetTargetForItems(be_app);
|
||||
|
||||
static const int baudrates[] = { 50, 75, 110, 134, 150, 200, 300, 600,
|
||||
1200, 1800, 2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200,
|
||||
230400
|
||||
};
|
||||
fStopbitsMenu->AddItem(stop1);
|
||||
fStopbitsMenu->AddItem(stop2);
|
||||
fStopbitsMenu->SetTargetForItems(be_app);
|
||||
|
||||
// Loop backwards to add fastest rates at top of menu
|
||||
for (int i = sizeof(baudrates) / sizeof(char*); --i >= 0;)
|
||||
for (int i = sizeof(kBaudrates) / sizeof(char*); --i >= 0;)
|
||||
{
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("baudrate", baudrates[i]);
|
||||
message->AddInt32("baudrate", kBaudrates[i]);
|
||||
|
||||
char buffer[7];
|
||||
sprintf(buffer,"%d", baudrates[i]);
|
||||
sprintf(buffer,"%d", kBaudrates[i]);
|
||||
BMenuItem* item = new BMenuItem(buffer, message);
|
||||
|
||||
if (baudrates[i] == 19200)
|
||||
item->SetMarked(true);
|
||||
|
||||
baudRate->AddItem(item);
|
||||
fBaudrateMenu->AddItem(item);
|
||||
}
|
||||
|
||||
baudRate->SetTargetForItems(be_app);
|
||||
fBaudrateMenu->SetTargetForItems(be_app);
|
||||
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("flowcontrol", B_HARDWARE_CONTROL);
|
||||
BMenuItem* hardware = new BMenuItem("Hardware", message);
|
||||
hardware->SetMarked(true);
|
||||
|
||||
message = new BMessage(kMsgSettings);
|
||||
message->AddInt32("flowcontrol", B_SOFTWARE_CONTROL);
|
||||
@@ -163,11 +162,11 @@ SerialWindow::SerialWindow()
|
||||
message->AddInt32("flowcontrol", 0);
|
||||
BMenuItem* noFlow = new BMenuItem("None", message);
|
||||
|
||||
flowControl->AddItem(hardware);
|
||||
flowControl->AddItem(software);
|
||||
flowControl->AddItem(both);
|
||||
flowControl->AddItem(noFlow);
|
||||
flowControl->SetTargetForItems(be_app);
|
||||
fFlowcontrolMenu->AddItem(hardware);
|
||||
fFlowcontrolMenu->AddItem(software);
|
||||
fFlowcontrolMenu->AddItem(both);
|
||||
fFlowcontrolMenu->AddItem(noFlow);
|
||||
fFlowcontrolMenu->SetTargetForItems(be_app);
|
||||
|
||||
CenterOnScreen();
|
||||
}
|
||||
@@ -188,6 +187,7 @@ void SerialWindow::MenusBeginning()
|
||||
// fill it with the (updated) serial port list
|
||||
BSerialPort serialPort;
|
||||
int deviceCount = serialPort.CountDevices();
|
||||
bool connected = false;
|
||||
|
||||
for(int i = 0; i < deviceCount; i++)
|
||||
{
|
||||
@@ -199,6 +199,13 @@ void SerialWindow::MenusBeginning()
|
||||
BMenuItem* portItem = new BMenuItem(buffer, message);
|
||||
portItem->SetTarget(be_app);
|
||||
|
||||
const BString& connectedPort = ((SerialApp*)be_app)->GetPort();
|
||||
|
||||
if(connectedPort == buffer) {
|
||||
connected = true;
|
||||
portItem->SetMarked(true);
|
||||
}
|
||||
|
||||
fConnectionMenu->AddItem(portItem);
|
||||
}
|
||||
|
||||
@@ -207,6 +214,8 @@ void SerialWindow::MenusBeginning()
|
||||
|
||||
BMenuItem* disconnect = new BMenuItem("Disconnect",
|
||||
new BMessage(kMsgOpenPort), 'Z', B_OPTION_KEY);
|
||||
if(!connected)
|
||||
disconnect->SetEnabled(false);
|
||||
fConnectionMenu->AddItem(disconnect);
|
||||
} else {
|
||||
BMenuItem* noDevices = new BMenuItem("<no serial port available>", NULL);
|
||||
@@ -246,10 +255,82 @@ void SerialWindow::MessageReceived(BMessage* message)
|
||||
fLogFilePanel->Show();
|
||||
break;
|
||||
}
|
||||
case kMsgSettings:
|
||||
{
|
||||
int32 baudrate;
|
||||
stop_bits stopBits;
|
||||
data_bits dataBits;
|
||||
parity_mode parity;
|
||||
uint32 flowcontrol;
|
||||
|
||||
if(message->FindInt32("databits", (int32*)&dataBits) == B_OK)
|
||||
{
|
||||
for(int i = 0; i < fDatabitsMenu->CountItems(); i++)
|
||||
{
|
||||
BMenuItem* item = fDatabitsMenu->ItemAt(i);
|
||||
int32 code;
|
||||
item->Message()->FindInt32("databits", &code);
|
||||
|
||||
if(code == dataBits)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(message->FindInt32("stopbits", (int32*)&stopBits) == B_OK)
|
||||
{
|
||||
for(int i = 0; i < fStopbitsMenu->CountItems(); i++)
|
||||
{
|
||||
BMenuItem* item = fStopbitsMenu->ItemAt(i);
|
||||
int32 code;
|
||||
item->Message()->FindInt32("stopbits", &code);
|
||||
|
||||
if(code == stopBits)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(message->FindInt32("parity", (int32*)&parity) == B_OK)
|
||||
{
|
||||
for(int i = 0; i < fParityMenu->CountItems(); i++)
|
||||
{
|
||||
BMenuItem* item = fParityMenu->ItemAt(i);
|
||||
int32 code;
|
||||
item->Message()->FindInt32("parity", &code);
|
||||
|
||||
if(code == parity)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(message->FindInt32("flowcontrol", (int32*)&flowcontrol) == B_OK)
|
||||
{
|
||||
for(int i = 0; i < fFlowcontrolMenu->CountItems(); i++)
|
||||
{
|
||||
BMenuItem* item = fFlowcontrolMenu->ItemAt(i);
|
||||
int32 code;
|
||||
item->Message()->FindInt32("flowcontrol", &code);
|
||||
|
||||
if(code == (int32)flowcontrol)
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
if(message->FindInt32("baudrate", &baudrate) == B_OK)
|
||||
{
|
||||
for(int i = 0; i < fBaudrateMenu->CountItems(); i++)
|
||||
{
|
||||
BMenuItem* item = fBaudrateMenu->ItemAt(i);
|
||||
int32 code;
|
||||
item->Message()->FindInt32("baudrate", &code);
|
||||
|
||||
if(code == kBaudrates[baudrate])
|
||||
item->SetMarked(true);
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
default:
|
||||
BWindow::MessageReceived(message);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
const char* SerialWindow::kWindowTitle = "SerialConnect";
|
||||
|
||||
@@ -23,7 +23,13 @@ class SerialWindow: public BWindow
|
||||
private:
|
||||
TermView* fTermView;
|
||||
BMenu* fConnectionMenu;
|
||||
BMenu* fDatabitsMenu;
|
||||
BMenu* fStopbitsMenu;
|
||||
BMenu* fParityMenu;
|
||||
BMenu* fFlowcontrolMenu;
|
||||
BMenu* fBaudrateMenu;
|
||||
BFilePanel* fLogFilePanel;
|
||||
|
||||
static const int kBaudrates[];
|
||||
static const char* kWindowTitle;
|
||||
};
|
||||
|
||||
@@ -19,19 +19,19 @@ TermView::TermView()
|
||||
:
|
||||
BView("TermView", B_WILL_DRAW | B_FRAME_EVENTS)
|
||||
{
|
||||
SetFont(be_fixed_font);
|
||||
|
||||
font_height height;
|
||||
GetFontHeight(&height);
|
||||
fFontHeight = height.ascent + height.descent + height.leading;
|
||||
fFontWidth = be_fixed_font->StringWidth("X");
|
||||
fTerm = vterm_new(kDefaultHeight, kDefaultWidth);
|
||||
|
||||
vterm_parser_set_utf8(fTerm, 1);
|
||||
|
||||
fTermScreen = vterm_obtain_screen(fTerm);
|
||||
vterm_screen_set_callbacks(fTermScreen, &sScreenCallbacks, this);
|
||||
vterm_screen_reset(fTermScreen, 1);
|
||||
|
||||
SetFont(be_fixed_font);
|
||||
vterm_parser_set_utf8(fTerm, 1);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,52 +61,60 @@ void TermView::Draw(BRect updateRect)
|
||||
for (pos.row = updatedChars.start_row; pos.row <= updatedChars.end_row;
|
||||
pos.row++) {
|
||||
float x = updatedChars.start_col * fFontWidth + kBorderSpacing;
|
||||
float y = pos.row * fFontHeight + height.ascent + kBorderSpacing;
|
||||
float y = pos.row * fFontHeight + height.ascent + kBorderSpacing + 1;
|
||||
MovePenTo(x, y);
|
||||
|
||||
for (pos.col = updatedChars.start_col;
|
||||
pos.col <= updatedChars.end_col;) {
|
||||
VTermScreenCell cell;
|
||||
|
||||
if (pos.col < 0 || pos.row < 0 || pos.col >= availableCols
|
||||
|| pos.row >= availableRows) {
|
||||
|
||||
// All cells outside the used terminal area are drawn with the
|
||||
// same background color as the top-left one.
|
||||
VTermPos firstPos;
|
||||
firstPos.row = 0;
|
||||
firstPos.col = 0;
|
||||
vterm_screen_get_cell(fTermScreen, firstPos, &cell);
|
||||
cell.chars[0] = 0;
|
||||
cell.width = 1;
|
||||
} else
|
||||
vterm_screen_get_cell(fTermScreen, pos, &cell);
|
||||
|
||||
rgb_color foreground, background;
|
||||
foreground.red = cell.fg.red;
|
||||
foreground.green = cell.fg.green;
|
||||
foreground.blue = cell.fg.blue;
|
||||
background.red = cell.bg.red;
|
||||
background.green = cell.bg.green;
|
||||
background.blue = cell.bg.blue;
|
||||
|
||||
if(cell.attrs.reverse) {
|
||||
SetLowColor(foreground);
|
||||
SetViewColor(foreground);
|
||||
SetHighColor(background);
|
||||
} else {
|
||||
SetLowColor(background);
|
||||
SetViewColor(background);
|
||||
SetHighColor(foreground);
|
||||
}
|
||||
|
||||
BPoint penLocation = PenLocation();
|
||||
FillRect(BRect(penLocation.x, penLocation.y - height.ascent,
|
||||
penLocation.x + cell.width * fFontWidth, penLocation.y + 1),
|
||||
B_SOLID_LOW);
|
||||
|
||||
if (cell.chars[0] == 0) {
|
||||
DrawString(" ");
|
||||
pos.col ++;
|
||||
} else {
|
||||
VTermScreenCell cell;
|
||||
vterm_screen_get_cell(fTermScreen, pos, &cell);
|
||||
|
||||
rgb_color foreground, background;
|
||||
foreground.red = cell.fg.red;
|
||||
foreground.green = cell.fg.green;
|
||||
foreground.blue = cell.fg.blue;
|
||||
background.red = cell.bg.red;
|
||||
background.green = cell.bg.green;
|
||||
background.blue = cell.bg.blue;
|
||||
|
||||
if(cell.attrs.reverse) {
|
||||
SetLowColor(foreground);
|
||||
SetViewColor(foreground);
|
||||
SetHighColor(background);
|
||||
} else {
|
||||
SetLowColor(background);
|
||||
SetViewColor(background);
|
||||
SetHighColor(foreground);
|
||||
}
|
||||
|
||||
BPoint penLocation = PenLocation();
|
||||
FillRect(BRect(penLocation.x, penLocation.y - height.ascent,
|
||||
penLocation.x + cell.width * fFontWidth, penLocation.y), B_SOLID_LOW);
|
||||
|
||||
if (cell.chars[0] == 0) {
|
||||
DrawString(" ");
|
||||
pos.col ++;
|
||||
} else {
|
||||
char buffer[VTERM_MAX_CHARS_PER_CELL];
|
||||
wcstombs(buffer, (wchar_t*)cell.chars,
|
||||
char buffer[VTERM_MAX_CHARS_PER_CELL];
|
||||
wcstombs(buffer, (wchar_t*)cell.chars,
|
||||
VTERM_MAX_CHARS_PER_CELL);
|
||||
|
||||
DrawString(buffer);
|
||||
pos.col += cell.width;
|
||||
}
|
||||
DrawString(buffer);
|
||||
pos.col += cell.width;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -116,7 +124,7 @@ void TermView::Draw(BRect updateRect)
|
||||
void TermView::FrameResized(float width, float height)
|
||||
{
|
||||
VTermRect newSize = PixelsToGlyphs(BRect(0, 0, width - 2 * kBorderSpacing,
|
||||
height - 2 * kBorderSpacing));
|
||||
height - 2 * kBorderSpacing));
|
||||
vterm_set_size(fTerm, newSize.end_row, newSize.end_col);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user