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