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 message->FindData("data", B_RAW_TYPE, (const void**)&bytes, &size); 88 89 if (bytes[0] == '\n') { 90 size = 2; 91 bytes = "\r\n"; 92 } 93 fSerialPort.Write(bytes, size); 94 break; 95 } 96 case kMsgLogfile: 97 { 98 entry_ref parent; 99 const char* filename; 100 101 if (message->FindRef("directory", &parent) == B_OK 102 && message->FindString("name", &filename) == B_OK) 103 { 104 delete fLogFile; 105 BDirectory directory(&parent); 106 fLogFile = new BFile(&directory, filename, 107 B_WRITE_ONLY | B_CREATE_FILE | B_OPEN_AT_END); 108 status_t error = fLogFile->InitCheck(); 109 if(error != B_OK) 110 { 111 puts(strerror(error)); 112 } 113 } else { 114 debugger("Invalid BMessage received"); 115 } 116 } 117 case kMsgSettings: 118 { 119 int32 baudrate; 120 stop_bits stopBits; 121 data_bits dataBits; 122 parity_mode parity; 123 uint32 flowcontrol; 124 125 if(message->FindInt32("databits", (int32*)&dataBits) == B_OK) 126 fSerialPort.SetDataBits(dataBits); 127 128 if(message->FindInt32("stopbits", (int32*)&stopBits) == B_OK) 129 fSerialPort.SetStopBits(stopBits); 130 131 if(message->FindInt32("parity", (int32*)&parity) == B_OK) 132 fSerialPort.SetParityMode(parity); 133 134 if(message->FindInt32("flowcontrol", (int32*)&flowcontrol) == B_OK) 135 fSerialPort.SetFlowControl(flowcontrol); 136 137 if(message->FindInt32("baudrate", &baudrate) == B_OK) { 138 data_rate rate = (data_rate)baudrate; 139 fSerialPort.SetDataRate(rate); 140 } 141 142 break; 143 } 144 default: 145 BApplication::MessageReceived(message); 146 } 147 } 148 149 150 bool SerialApp::QuitRequested() 151 { 152 if(BApplication::QuitRequested()) { 153 SaveSettings(); 154 return true; 155 } 156 return false; 157 } 158 159 160 const BString& SerialApp::GetPort() 161 { 162 return fPortPath; 163 } 164 165 166 void SerialApp::LoadSettings() 167 { 168 BPath path; 169 find_directory(B_USER_SETTINGS_DIRECTORY, &path); 170 path.Append("SerialConnect"); 171 172 BFile file(path.Path(), B_READ_ONLY); 173 BMessage message(kMsgSettings); 174 if(message.Unflatten(&file) != B_OK) 175 { 176 message.AddInt32("parity", fSerialPort.ParityMode()); 177 message.AddInt32("databits", fSerialPort.DataBits()); 178 message.AddInt32("stopbits", fSerialPort.StopBits()); 179 message.AddInt32("baudrate", fSerialPort.DataRate()); 180 message.AddInt32("flowcontrol", fSerialPort.FlowControl()); 181 } 182 183 be_app->PostMessage(&message); 184 fWindow->PostMessage(&message); 185 } 186 187 188 void SerialApp::SaveSettings() 189 { 190 BMessage message(kMsgSettings); 191 message.AddInt32("parity", fSerialPort.ParityMode()); 192 message.AddInt32("databits", fSerialPort.DataBits()); 193 message.AddInt32("stopbits", fSerialPort.StopBits()); 194 message.AddInt32("baudrate", fSerialPort.DataRate()); 195 message.AddInt32("flowcontrol", fSerialPort.FlowControl()); 196 197 BPath path; 198 find_directory(B_USER_SETTINGS_DIRECTORY, &path); 199 path.Append("SerialConnect"); 200 201 BFile file(path.Path(), B_WRITE_ONLY | B_CREATE_FILE); 202 message.Flatten(&file); 203 } 204 205 206 /* static */ 207 status_t SerialApp::PollSerial(void*) 208 { 209 SerialApp* application = (SerialApp*)be_app; 210 char buffer[256]; 211 212 for(;;) 213 { 214 ssize_t bytesRead; 215 216 bytesRead = application->fSerialPort.Read(buffer, sizeof(buffer)); 217 if (bytesRead == B_FILE_ERROR) 218 { 219 // Port is not open - wait for it and start over 220 acquire_sem(application->fSerialLock); 221 } else if (bytesRead > 0) { 222 // We read something, forward it to the app for handling 223 BMessage* serialData = new BMessage(kMsgDataRead); 224 serialData->AddData("data", B_RAW_TYPE, buffer, bytesRead); 225 be_app_messenger.SendMessage(serialData); 226 } 227 } 228 229 // Should not reach this line anyway... 230 return B_OK; 231 } 232 233 const char* SerialApp::kApplicationSignature 234 = "application/x-vnd.haiku.SerialConnect"; 235 236 237 int main(int argc, char** argv) 238 { 239 SerialApp app; 240 app.Run(); 241 } 242