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