1 /* 2 * Copyright 2012, Adrien Destugues, pulkomandy@gmail.com 3 * Distributed under the terms of the MIT licence. 4 */ 5 6 7 #include "SerialApp.h" 8 9 #include <stdio.h> 10 #include <string.h> 11 12 #include <Directory.h> 13 #include <Entry.h> 14 #include <File.h> 15 #include <FindDirectory.h> 16 #include <Path.h> 17 18 #include "SerialWindow.h" 19 20 21 SerialApp::SerialApp() 22 : BApplication(SerialApp::kApplicationSignature) 23 , fLogFile(NULL) 24 { 25 fWindow = new SerialWindow(); 26 27 fSerialLock = create_sem(0, "Serial port lock"); 28 thread_id id = spawn_thread(PollSerial, "Serial port poller", 29 B_LOW_PRIORITY, this); 30 resume_thread(id); 31 } 32 33 34 SerialApp::~SerialApp() 35 { 36 delete fLogFile; 37 } 38 39 40 void SerialApp::ReadyToRun() 41 { 42 LoadSettings(); 43 fWindow->Show(); 44 } 45 46 47 void SerialApp::MessageReceived(BMessage* message) 48 { 49 switch(message->what) 50 { 51 case kMsgOpenPort: 52 { 53 if(message->FindString("port name", &fPortPath) == B_OK) 54 { 55 fSerialPort.Open(fPortPath); 56 release_sem(fSerialLock); 57 } else { 58 fSerialPort.Close(); 59 } 60 break; 61 } 62 case kMsgDataRead: 63 { 64 // forward the message to the window, which will display the 65 // incoming data 66 fWindow->PostMessage(message); 67 68 if (fLogFile) 69 { 70 const char* bytes; 71 ssize_t length; 72 message->FindData("data", B_RAW_TYPE, (const void**)&bytes, 73 &length); 74 if(fLogFile->Write(bytes, length) != length) 75 { 76 // TODO error handling 77 } 78 } 79 80 break; 81 } 82 case kMsgDataWrite: 83 { 84 const char* bytes; 85 ssize_t size; 86 87 if (message->FindData("data", B_RAW_TYPE, (const void**)&bytes, 88 &size) != B_OK) 89 break; 90 91 if (bytes[0] == '\n') { 92 size = 2; 93 bytes = "\r\n"; 94 } 95 fSerialPort.Write(bytes, size); 96 break; 97 } 98 case kMsgLogfile: 99 { 100 entry_ref parent; 101 const char* filename; 102 103 if (message->FindRef("directory", &parent) == B_OK 104 && message->FindString("name", &filename) == B_OK) 105 { 106 delete fLogFile; 107 BDirectory directory(&parent); 108 fLogFile = new BFile(&directory, filename, 109 B_WRITE_ONLY | B_CREATE_FILE | B_OPEN_AT_END); 110 status_t error = fLogFile->InitCheck(); 111 if(error != B_OK) 112 { 113 puts(strerror(error)); 114 } 115 } else { 116 debugger("Invalid BMessage received"); 117 } 118 break; 119 } 120 case kMsgSettings: 121 { 122 int32 baudrate; 123 stop_bits stopBits; 124 data_bits dataBits; 125 parity_mode parity; 126 uint32 flowcontrol; 127 128 if(message->FindInt32("databits", (int32*)&dataBits) == B_OK) 129 fSerialPort.SetDataBits(dataBits); 130 131 if(message->FindInt32("stopbits", (int32*)&stopBits) == B_OK) 132 fSerialPort.SetStopBits(stopBits); 133 134 if(message->FindInt32("parity", (int32*)&parity) == B_OK) 135 fSerialPort.SetParityMode(parity); 136 137 if(message->FindInt32("flowcontrol", (int32*)&flowcontrol) == B_OK) 138 fSerialPort.SetFlowControl(flowcontrol); 139 140 if(message->FindInt32("baudrate", &baudrate) == B_OK) { 141 data_rate rate = (data_rate)baudrate; 142 fSerialPort.SetDataRate(rate); 143 } 144 145 break; 146 } 147 default: 148 BApplication::MessageReceived(message); 149 } 150 } 151 152 153 bool SerialApp::QuitRequested() 154 { 155 if(BApplication::QuitRequested()) { 156 SaveSettings(); 157 return true; 158 } 159 return false; 160 } 161 162 163 const BString& SerialApp::GetPort() 164 { 165 return fPortPath; 166 } 167 168 169 void SerialApp::LoadSettings() 170 { 171 BPath path; 172 find_directory(B_USER_SETTINGS_DIRECTORY, &path); 173 path.Append("SerialConnect"); 174 175 BFile file(path.Path(), B_READ_ONLY); 176 BMessage message(kMsgSettings); 177 if(message.Unflatten(&file) != B_OK) 178 { 179 message.AddInt32("parity", fSerialPort.ParityMode()); 180 message.AddInt32("databits", fSerialPort.DataBits()); 181 message.AddInt32("stopbits", fSerialPort.StopBits()); 182 message.AddInt32("baudrate", fSerialPort.DataRate()); 183 message.AddInt32("flowcontrol", fSerialPort.FlowControl()); 184 } 185 186 be_app->PostMessage(&message); 187 fWindow->PostMessage(&message); 188 } 189 190 191 void SerialApp::SaveSettings() 192 { 193 BMessage message(kMsgSettings); 194 message.AddInt32("parity", fSerialPort.ParityMode()); 195 message.AddInt32("databits", fSerialPort.DataBits()); 196 message.AddInt32("stopbits", fSerialPort.StopBits()); 197 message.AddInt32("baudrate", fSerialPort.DataRate()); 198 message.AddInt32("flowcontrol", fSerialPort.FlowControl()); 199 200 BPath path; 201 find_directory(B_USER_SETTINGS_DIRECTORY, &path); 202 path.Append("SerialConnect"); 203 204 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); 205 message.Flatten(&file); 206 } 207 208 209 /* static */ 210 status_t SerialApp::PollSerial(void*) 211 { 212 SerialApp* application = (SerialApp*)be_app; 213 char buffer[256]; 214 215 for(;;) 216 { 217 ssize_t bytesRead; 218 219 bytesRead = application->fSerialPort.Read(buffer, sizeof(buffer)); 220 if (bytesRead == B_FILE_ERROR) 221 { 222 // Port is not open - wait for it and start over 223 acquire_sem(application->fSerialLock); 224 } else if (bytesRead > 0) { 225 // We read something, forward it to the app for handling 226 BMessage* serialData = new BMessage(kMsgDataRead); 227 serialData->AddData("data", B_RAW_TYPE, buffer, bytesRead); 228 be_app_messenger.SendMessage(serialData); 229 } 230 } 231 232 // Should not reach this line anyway... 233 return B_OK; 234 } 235 236 const char* SerialApp::kApplicationSignature 237 = "application/x-vnd.haiku.SerialConnect"; 238 239 240 int main(int argc, char** argv) 241 { 242 SerialApp app; 243 app.Run(); 244 } 245