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