xref: /haiku/src/apps/serialconnect/SerialWindow.cpp (revision 49d7857e32a5c34fe63a11e46a41a774aa1b2728)
1 /*
2  * Copyright 2012, Adrien Destugues, pulkomandy@gmail.com
3  * Distributed under the terms of the MIT licence.
4  */
5 
6 
7 #include "SerialWindow.h"
8 
9 #include <stdio.h>
10 
11 #include <FilePanel.h>
12 #include <GroupLayout.h>
13 #include <Menu.h>
14 #include <MenuBar.h>
15 #include <MenuItem.h>
16 #include <SerialPort.h>
17 
18 #include "SerialApp.h"
19 #include "TermView.h"
20 
21 
22 SerialWindow::SerialWindow()
23 	: BWindow(BRect(100, 100, 400, 400), SerialWindow::kWindowTitle,
24 		B_DOCUMENT_WINDOW, B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS)
25 	, fLogFilePanel(NULL)
26 {
27 	SetLayout(new BGroupLayout(B_VERTICAL, 0.0f));
28 
29 	BMenuBar* menuBar = new BMenuBar("menuBar");
30 	fTermView = new TermView();
31 
32 	AddChild(menuBar);
33 	AddChild(fTermView);
34 
35 	fConnectionMenu = new BMenu("Connection");
36 	BMenu* fileMenu = new BMenu("File");
37 	BMenu* settingsMenu = new BMenu("Settings");
38 
39 	fConnectionMenu->SetRadioMode(true);
40 
41 	menuBar->AddItem(fConnectionMenu);
42 	menuBar->AddItem(fileMenu);
43 	menuBar->AddItem(settingsMenu);
44 
45 	// TODO edit menu - what's in it ?
46 	//BMenu* editMenu = new BMenu("Edit");
47 	//menuBar->AddItem(editMenu);
48 
49 	BMenuItem* logFile = new BMenuItem("Log to file" B_UTF8_ELLIPSIS,
50 		new BMessage(kMsgLogfile));
51 	fileMenu->AddItem(logFile);
52 	BMenuItem* xmodemSend = new BMenuItem("X/Y/ZModem send" B_UTF8_ELLIPSIS,
53 		NULL);
54 	fileMenu->AddItem(xmodemSend);
55 	BMenuItem* xmodemReceive = new BMenuItem(
56 		"X/Y/Zmodem receive" B_UTF8_ELLIPSIS, NULL);
57 	fileMenu->AddItem(xmodemReceive);
58 
59 	// Configuring all this by menus may be a bit unhandy. Make a setting
60 	// window instead ?
61 	BMenu* baudRate = new BMenu("Baud rate");
62 	baudRate->SetRadioMode(true);
63 	settingsMenu->AddItem(baudRate);
64 
65 	BMenu* parity = new BMenu("Parity");
66 	parity->SetRadioMode(true);
67 	settingsMenu->AddItem(parity);
68 
69 	BMenu* stopBits = new BMenu("Stop bits");
70 	stopBits->SetRadioMode(true);
71 	settingsMenu->AddItem(stopBits);
72 
73 	BMenu* flowControl = new BMenu("Flow control");
74 	flowControl->SetRadioMode(true);
75 	settingsMenu->AddItem(flowControl);
76 
77 	BMenu* dataBits = new BMenu("Data bits");
78 	dataBits->SetRadioMode(true);
79 	settingsMenu->AddItem(dataBits);
80 
81 
82 	BMessage* message = new BMessage(kMsgSettings);
83 	message->AddInt32("parity", B_NO_PARITY);
84 	BMenuItem* parityNone = new BMenuItem("None", message);
85 
86 	message = new BMessage(kMsgSettings);
87 	message->AddInt32("parity", B_ODD_PARITY);
88 	BMenuItem* parityOdd = new BMenuItem("Odd", message);
89 
90 	message = new BMessage(kMsgSettings);
91 	message->AddInt32("parity", B_EVEN_PARITY);
92 	BMenuItem* parityEven = new BMenuItem("Even", message);
93 	parityNone->SetMarked(true);
94 
95 	parity->AddItem(parityNone);
96 	parity->AddItem(parityOdd);
97 	parity->AddItem(parityEven);
98 	parity->SetTargetForItems(be_app);
99 
100 	message = new BMessage(kMsgSettings);
101 	message->AddInt32("databits", B_DATA_BITS_7);
102 	BMenuItem* data7 = new BMenuItem("7", message);
103 
104 	message = new BMessage(kMsgSettings);
105 	message->AddInt32("databits", B_DATA_BITS_8);
106 	BMenuItem* data8 = new BMenuItem("8", message);
107 	data8->SetMarked(true);
108 
109 	dataBits->AddItem(data7);
110 	dataBits->AddItem(data8);
111 	dataBits->SetTargetForItems(be_app);
112 
113 	message = new BMessage(kMsgSettings);
114 	message->AddInt32("stopbits", B_STOP_BITS_1);
115 	BMenuItem* stop1 = new BMenuItem("1", NULL);
116 
117 	message = new BMessage(kMsgSettings);
118 	message->AddInt32("stopbits", B_STOP_BITS_2);
119 	BMenuItem* stop2 = new BMenuItem("2", NULL);
120 	stop1->SetMarked(true);
121 
122 	stopBits->AddItem(stop1);
123 	stopBits->AddItem(stop2);
124 	stopBits->SetTargetForItems(be_app);
125 
126 	static const int baudrates[] = { 50, 75, 110, 134, 150, 200, 300, 600,
127 		1200, 1800, 2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200,
128 		230400
129 	};
130 
131 	// Loop backwards to add fastest rates at top of menu
132 	for (int i = sizeof(baudrates) / sizeof(char*); --i >= 0;)
133 	{
134 		message = new BMessage(kMsgSettings);
135 		message->AddInt32("baudrate", baudrates[i]);
136 
137 		char buffer[7];
138 		sprintf(buffer,"%d", baudrates[i]);
139 		BMenuItem* item = new BMenuItem(buffer, message);
140 
141 		if (baudrates[i] == 19200)
142 			item->SetMarked(true);
143 
144 		baudRate->AddItem(item);
145 	}
146 
147 	baudRate->SetTargetForItems(be_app);
148 
149 	message = new BMessage(kMsgSettings);
150 	message->AddInt32("flowcontrol", B_HARDWARE_CONTROL);
151 	BMenuItem* hardware = new BMenuItem("Hardware", message);
152 	hardware->SetMarked(true);
153 
154 	message = new BMessage(kMsgSettings);
155 	message->AddInt32("flowcontrol", B_SOFTWARE_CONTROL);
156 	BMenuItem* software = new BMenuItem("Software", message);
157 
158 	message = new BMessage(kMsgSettings);
159 	message->AddInt32("flowcontrol", B_HARDWARE_CONTROL | B_SOFTWARE_CONTROL);
160 	BMenuItem* both = new BMenuItem("Both", message);
161 
162 	message = new BMessage(kMsgSettings);
163 	message->AddInt32("flowcontrol", 0);
164 	BMenuItem* noFlow = new BMenuItem("None", message);
165 
166 	flowControl->AddItem(hardware);
167 	flowControl->AddItem(software);
168 	flowControl->AddItem(both);
169 	flowControl->AddItem(noFlow);
170 	flowControl->SetTargetForItems(be_app);
171 
172 	CenterOnScreen();
173 }
174 
175 
176 
177 SerialWindow::~SerialWindow()
178 {
179 	delete fLogFilePanel;
180 }
181 
182 
183 void SerialWindow::MenusBeginning()
184 {
185 	// remove all items from the menu
186 	while(fConnectionMenu->RemoveItem(0L));
187 
188 	// fill it with the (updated) serial port list
189 	BSerialPort serialPort;
190 	int deviceCount = serialPort.CountDevices();
191 
192 	for(int i = 0; i < deviceCount; i++)
193 	{
194 		char buffer[256];
195 		serialPort.GetDeviceName(i, buffer, 256);
196 
197 		BMessage* message = new BMessage(kMsgOpenPort);
198 		message->AddString("port name", buffer);
199 		BMenuItem* portItem = new BMenuItem(buffer, message);
200 		portItem->SetTarget(be_app);
201 
202 		fConnectionMenu->AddItem(portItem);
203 	}
204 
205 	if (deviceCount > 0) {
206 		fConnectionMenu->AddSeparatorItem();
207 
208 		BMenuItem* disconnect = new BMenuItem("Disconnect",
209 			new BMessage(kMsgOpenPort), 'Z', B_OPTION_KEY);
210 		fConnectionMenu->AddItem(disconnect);
211 	} else {
212 		BMenuItem* noDevices = new BMenuItem("<no serial port available>", NULL);
213 		noDevices->SetEnabled(false);
214 		fConnectionMenu->AddItem(noDevices);
215 	}
216 }
217 
218 void SerialWindow::MessageReceived(BMessage* message)
219 {
220 	switch(message->what)
221 	{
222 		case kMsgOpenPort:
223 		{
224 			BMenuItem* disconnectMenu;
225 			if(message->FindPointer("source", (void**)&disconnectMenu) == B_OK)
226 				disconnectMenu->SetMarked(false);
227 			be_app->PostMessage(new BMessage(*message));
228 			break;
229 		}
230 		case kMsgDataRead:
231 		{
232 			const char* bytes;
233 			ssize_t length;
234 			message->FindData("data", B_RAW_TYPE, (const void**)&bytes, &length);
235 			fTermView->PushBytes(bytes, length);
236 			break;
237 		}
238 		case kMsgLogfile:
239 		{
240 			// Let's lazy init the file panel
241 			if(fLogFilePanel == NULL) {
242 				fLogFilePanel = new BFilePanel(B_SAVE_PANEL, &be_app_messenger,
243 					NULL, B_FILE_NODE, false);
244 				fLogFilePanel->SetMessage(message);
245 			}
246 			fLogFilePanel->Show();
247 			break;
248 		}
249 		default:
250 			BWindow::MessageReceived(message);
251 	}
252 }
253 
254 
255 const char* SerialWindow::kWindowTitle = "SerialConnect";
256