xref: /haiku/src/apps/serialconnect/SerialWindow.cpp (revision 2b76973fa2401f7a5edf68e6470f3d3210cbcff3)
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 const int SerialWindow::kBaudrates[] = { 50, 75, 110, 134, 150, 200, 300, 600,
23 	1200, 1800, 2400, 4800, 9600, 19200, 31250, 38400, 57600, 115200, 230400
24 };
25 
26 
27 const char* SerialWindow::kWindowTitle = "SerialConnect";
28 
29 
30 SerialWindow::SerialWindow()
31 	: BWindow(BRect(100, 100, 400, 400), SerialWindow::kWindowTitle,
32 		B_DOCUMENT_WINDOW, B_QUIT_ON_WINDOW_CLOSE | B_AUTO_UPDATE_SIZE_LIMITS)
33 	, fLogFilePanel(NULL)
34 {
35 	SetLayout(new BGroupLayout(B_VERTICAL, 0.0f));
36 
37 	BMenuBar* menuBar = new BMenuBar("menuBar");
38 	fTermView = new TermView();
39 
40 	AddChild(menuBar);
41 	AddChild(fTermView);
42 
43 	fConnectionMenu = new BMenu("Connection");
44 	BMenu* fileMenu = new BMenu("File");
45 	BMenu* settingsMenu = new BMenu("Settings");
46 
47 	fConnectionMenu->SetRadioMode(true);
48 
49 	menuBar->AddItem(fConnectionMenu);
50 	menuBar->AddItem(fileMenu);
51 	menuBar->AddItem(settingsMenu);
52 
53 	// TODO edit menu - what's in it ?
54 	//BMenu* editMenu = new BMenu("Edit");
55 	//menuBar->AddItem(editMenu);
56 
57 	BMenuItem* logFile = new BMenuItem("Log to file" B_UTF8_ELLIPSIS,
58 		new BMessage(kMsgLogfile));
59 	fileMenu->AddItem(logFile);
60 #if 0
61 	// TODO implement these
62 	BMenuItem* xmodemSend = new BMenuItem("X/Y/ZModem send" B_UTF8_ELLIPSIS,
63 		NULL);
64 	fileMenu->AddItem(xmodemSend);
65 	BMenuItem* xmodemReceive = new BMenuItem(
66 		"X/Y/Zmodem receive" B_UTF8_ELLIPSIS, NULL);
67 	fileMenu->AddItem(xmodemReceive);
68 #endif
69 
70 	// Configuring all this by menus may be a bit unhandy. Make a setting
71 	// window instead ?
72 	fBaudrateMenu = new BMenu("Baud rate");
73 	fBaudrateMenu->SetRadioMode(true);
74 	settingsMenu->AddItem(fBaudrateMenu);
75 
76 	fParityMenu = new BMenu("Parity");
77 	fParityMenu->SetRadioMode(true);
78 	settingsMenu->AddItem(fParityMenu);
79 
80 	fStopbitsMenu = new BMenu("Stop bits");
81 	fStopbitsMenu->SetRadioMode(true);
82 	settingsMenu->AddItem(fStopbitsMenu);
83 
84 	fFlowcontrolMenu = new BMenu("Flow control");
85 	fFlowcontrolMenu->SetRadioMode(true);
86 	settingsMenu->AddItem(fFlowcontrolMenu);
87 
88 	fDatabitsMenu = new BMenu("Data bits");
89 	fDatabitsMenu->SetRadioMode(true);
90 	settingsMenu->AddItem(fDatabitsMenu);
91 
92 
93 	BMessage* message = new BMessage(kMsgSettings);
94 	message->AddInt32("parity", B_NO_PARITY);
95 	BMenuItem* parityNone = new BMenuItem("None", message);
96 
97 	message = new BMessage(kMsgSettings);
98 	message->AddInt32("parity", B_ODD_PARITY);
99 	BMenuItem* parityOdd = new BMenuItem("Odd", message);
100 
101 	message = new BMessage(kMsgSettings);
102 	message->AddInt32("parity", B_EVEN_PARITY);
103 	BMenuItem* parityEven = new BMenuItem("Even", message);
104 
105 	fParityMenu->AddItem(parityNone);
106 	fParityMenu->AddItem(parityOdd);
107 	fParityMenu->AddItem(parityEven);
108 	fParityMenu->SetTargetForItems(be_app);
109 
110 	message = new BMessage(kMsgSettings);
111 	message->AddInt32("databits", B_DATA_BITS_7);
112 	BMenuItem* data7 = new BMenuItem("7", message);
113 
114 	message = new BMessage(kMsgSettings);
115 	message->AddInt32("databits", B_DATA_BITS_8);
116 	BMenuItem* data8 = new BMenuItem("8", message);
117 
118 	fDatabitsMenu->AddItem(data7);
119 	fDatabitsMenu->AddItem(data8);
120 	fDatabitsMenu->SetTargetForItems(be_app);
121 
122 	message = new BMessage(kMsgSettings);
123 	message->AddInt32("stopbits", B_STOP_BITS_1);
124 	BMenuItem* stop1 = new BMenuItem("1", message);
125 
126 	message = new BMessage(kMsgSettings);
127 	message->AddInt32("stopbits", B_STOP_BITS_2);
128 	BMenuItem* stop2 = new BMenuItem("2", message);
129 
130 	fStopbitsMenu->AddItem(stop1);
131 	fStopbitsMenu->AddItem(stop2);
132 	fStopbitsMenu->SetTargetForItems(be_app);
133 
134 	// Loop backwards to add fastest rates at top of menu
135 	for (int i = sizeof(kBaudrates) / sizeof(char*); --i >= 0;)
136 	{
137 		message = new BMessage(kMsgSettings);
138 		message->AddInt32("baudrate", kBaudrates[i]);
139 
140 		char buffer[7];
141 		sprintf(buffer,"%d", kBaudrates[i]);
142 		BMenuItem* item = new BMenuItem(buffer, message);
143 
144 		fBaudrateMenu->AddItem(item);
145 	}
146 
147 	fBaudrateMenu->SetTargetForItems(be_app);
148 
149 	message = new BMessage(kMsgSettings);
150 	message->AddInt32("flowcontrol", B_HARDWARE_CONTROL);
151 	BMenuItem* hardware = new BMenuItem("Hardware", message);
152 
153 	message = new BMessage(kMsgSettings);
154 	message->AddInt32("flowcontrol", B_SOFTWARE_CONTROL);
155 	BMenuItem* software = new BMenuItem("Software", message);
156 
157 	message = new BMessage(kMsgSettings);
158 	message->AddInt32("flowcontrol", B_HARDWARE_CONTROL | B_SOFTWARE_CONTROL);
159 	BMenuItem* both = new BMenuItem("Both", message);
160 
161 	message = new BMessage(kMsgSettings);
162 	message->AddInt32("flowcontrol", 0);
163 	BMenuItem* noFlow = new BMenuItem("None", message);
164 
165 	fFlowcontrolMenu->AddItem(hardware);
166 	fFlowcontrolMenu->AddItem(software);
167 	fFlowcontrolMenu->AddItem(both);
168 	fFlowcontrolMenu->AddItem(noFlow);
169 	fFlowcontrolMenu->SetTargetForItems(be_app);
170 
171 	CenterOnScreen();
172 }
173 
174 
175 
176 SerialWindow::~SerialWindow()
177 {
178 	delete fLogFilePanel;
179 }
180 
181 
182 void SerialWindow::MenusBeginning()
183 {
184 	// remove all items from the menu
185 	while(fConnectionMenu->RemoveItem(0L));
186 
187 	// fill it with the (updated) serial port list
188 	BSerialPort serialPort;
189 	int deviceCount = serialPort.CountDevices();
190 	bool connected = false;
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 		const BString& connectedPort = ((SerialApp*)be_app)->GetPort();
203 
204 		if(connectedPort == buffer) {
205 			connected = true;
206 			portItem->SetMarked(true);
207 		}
208 
209 		fConnectionMenu->AddItem(portItem);
210 	}
211 
212 	if (deviceCount > 0) {
213 		fConnectionMenu->AddSeparatorItem();
214 
215 		BMenuItem* disconnect = new BMenuItem("Disconnect",
216 			new BMessage(kMsgOpenPort), 'Z', B_OPTION_KEY);
217 		if(!connected)
218 			disconnect->SetEnabled(false);
219 		fConnectionMenu->AddItem(disconnect);
220 	} else {
221 		BMenuItem* noDevices = new BMenuItem("<no serial port available>", NULL);
222 		noDevices->SetEnabled(false);
223 		fConnectionMenu->AddItem(noDevices);
224 	}
225 }
226 
227 void SerialWindow::MessageReceived(BMessage* message)
228 {
229 	switch(message->what)
230 	{
231 		case kMsgOpenPort:
232 		{
233 			BMenuItem* disconnectMenu;
234 			if(message->FindPointer("source", (void**)&disconnectMenu) == B_OK)
235 				disconnectMenu->SetMarked(false);
236 			be_app->PostMessage(new BMessage(*message));
237 			break;
238 		}
239 		case kMsgDataRead:
240 		{
241 			const char* bytes;
242 			ssize_t length;
243 			message->FindData("data", B_RAW_TYPE, (const void**)&bytes, &length);
244 			fTermView->PushBytes(bytes, length);
245 			break;
246 		}
247 		case kMsgLogfile:
248 		{
249 			// Let's lazy init the file panel
250 			if(fLogFilePanel == NULL) {
251 				fLogFilePanel = new BFilePanel(B_SAVE_PANEL, &be_app_messenger,
252 					NULL, B_FILE_NODE, false);
253 				fLogFilePanel->SetMessage(message);
254 			}
255 			fLogFilePanel->Show();
256 			break;
257 		}
258 		case kMsgSettings:
259 		{
260 			int32 baudrate;
261 			stop_bits stopBits;
262 			data_bits dataBits;
263 			parity_mode parity;
264 			uint32 flowcontrol;
265 
266 			if(message->FindInt32("databits", (int32*)&dataBits) == B_OK)
267 			{
268 				for(int i = 0; i < fDatabitsMenu->CountItems(); i++)
269 				{
270 					BMenuItem* item = fDatabitsMenu->ItemAt(i);
271 					int32 code;
272 					item->Message()->FindInt32("databits", &code);
273 
274 					if(code == dataBits)
275 						item->SetMarked(true);
276 				}
277 			}
278 
279 			if(message->FindInt32("stopbits", (int32*)&stopBits) == B_OK)
280 			{
281 				for(int i = 0; i < fStopbitsMenu->CountItems(); i++)
282 				{
283 					BMenuItem* item = fStopbitsMenu->ItemAt(i);
284 					int32 code;
285 					item->Message()->FindInt32("stopbits", &code);
286 
287 					if(code == stopBits)
288 						item->SetMarked(true);
289 				}
290 			}
291 
292 			if(message->FindInt32("parity", (int32*)&parity) == B_OK)
293 			{
294 				for(int i = 0; i < fParityMenu->CountItems(); i++)
295 				{
296 					BMenuItem* item = fParityMenu->ItemAt(i);
297 					int32 code;
298 					item->Message()->FindInt32("parity", &code);
299 
300 					if(code == parity)
301 						item->SetMarked(true);
302 				}
303 			}
304 
305 			if(message->FindInt32("flowcontrol", (int32*)&flowcontrol) == B_OK)
306 			{
307 				for(int i = 0; i < fFlowcontrolMenu->CountItems(); i++)
308 				{
309 					BMenuItem* item = fFlowcontrolMenu->ItemAt(i);
310 					int32 code;
311 					item->Message()->FindInt32("flowcontrol", &code);
312 
313 					if(code == (int32)flowcontrol)
314 						item->SetMarked(true);
315 				}
316 			}
317 
318 			if(message->FindInt32("baudrate", &baudrate) == B_OK)
319 			{
320 				for(int i = 0; i < fBaudrateMenu->CountItems(); i++)
321 				{
322 					BMenuItem* item = fBaudrateMenu->ItemAt(i);
323 					int32 code;
324 					item->Message()->FindInt32("baudrate", &code);
325 
326 					if(code == kBaudrates[baudrate])
327 						item->SetMarked(true);
328 				}
329 			}
330 
331 			break;
332 		}
333 		default:
334 			BWindow::MessageReceived(message);
335 	}
336 }
337