xref: /haiku/src/apps/serialconnect/SerialApp.cpp (revision 90ae2e54f6ccaca73c011a2aa4cdd660417108ad)
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 
16 #include "SerialWindow.h"
17 
18 
19 SerialApp::SerialApp()
20 	: BApplication(SerialApp::kApplicationSignature)
21 	, fLogFile(NULL)
22 {
23 	fWindow = new SerialWindow();
24 
25 	fSerialLock = create_sem(0, "Serial port lock");
26 	thread_id id = spawn_thread(PollSerial, "Serial port poller",
27 		B_LOW_PRIORITY, this);
28 	resume_thread(id);
29 }
30 
31 
32 SerialApp::~SerialApp()
33 {
34 	delete fLogFile;
35 }
36 
37 
38 void SerialApp::ReadyToRun()
39 {
40 	fWindow->Show();
41 }
42 
43 
44 void SerialApp::MessageReceived(BMessage* message)
45 {
46 	switch(message->what)
47 	{
48 		case kMsgOpenPort:
49 		{
50 			const char* portName;
51 			if(message->FindString("port name", &portName) == B_OK)
52 			{
53 				fSerialPort.Open(portName);
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 			{
68 				const char* bytes;
69 				ssize_t length;
70 				message->FindData("data", B_RAW_TYPE, (const void**)&bytes,
71 					&length);
72 				if(fLogFile->Write(bytes, length) != length)
73 				{
74 					// TODO error handling
75 				}
76 			}
77 
78 			break;
79 		}
80 		case kMsgDataWrite:
81 		{
82 			const char* bytes;
83 			ssize_t size;
84 
85 			message->FindData("data", B_RAW_TYPE, (const void**)&bytes, &size);
86 
87 			if (bytes[0] == '\n') {
88 				size = 2;
89 				bytes = "\r\n";
90 			}
91 			fSerialPort.Write(bytes, size);
92 			break;
93 		}
94 		case kMsgLogfile:
95 		{
96 			entry_ref parent;
97 			const char* filename;
98 
99 			if (message->FindRef("directory", &parent) == B_OK
100 				&& message->FindString("name", &filename) == B_OK)
101 			{
102 				delete fLogFile;
103 				BDirectory directory(&parent);
104 				fLogFile = new BFile(&directory, filename,
105 					B_WRITE_ONLY | B_CREATE_FILE | B_OPEN_AT_END);
106 				status_t error = fLogFile->InitCheck();
107 				if(error != B_OK)
108 				{
109 					puts(strerror(error));
110 				}
111 			} else {
112 				debugger("Invalid BMessage received");
113 			}
114 		}
115 		case kMsgSettings:
116 		{
117 			int32 baudrate;
118 			stop_bits stopBits;
119 			data_bits dataBits;
120 			parity_mode parity;
121 			uint32 flowcontrol;
122 
123 			if(message->FindInt32("databits", (int32*)&dataBits) == B_OK)
124 				fSerialPort.SetDataBits(dataBits);
125 
126 			if(message->FindInt32("stopbits", (int32*)&stopBits) == B_OK)
127 				fSerialPort.SetStopBits(stopBits);
128 
129 			if(message->FindInt32("parity", (int32*)&parity) == B_OK)
130 				fSerialPort.SetParityMode(parity);
131 
132 			if(message->FindInt32("flowcontrol", (int32*)&flowcontrol) == B_OK)
133 				fSerialPort.SetFlowControl(flowcontrol);
134 
135 			if(message->FindInt32("baudrate", &baudrate) == B_OK) {
136 				data_rate rate;
137 				switch(baudrate) {
138 					case 50:
139 						rate = B_50_BPS;
140 						break;
141 					case 75:
142 						rate = B_75_BPS;
143 						break;
144 					case 110:
145 						rate = B_110_BPS;
146 						break;
147 					case 134:
148 						rate = B_134_BPS;
149 						break;
150 					case 150:
151 						rate = B_150_BPS;
152 						break;
153 					case 200:
154 						rate = B_200_BPS;
155 						break;
156 					case 300:
157 						rate = B_300_BPS;
158 						break;
159 					case 600:
160 						rate = B_600_BPS;
161 						break;
162 					case 1200:
163 						rate = B_1200_BPS;
164 						break;
165 					case 1800:
166 						rate = B_1800_BPS;
167 						break;
168 					case 2400:
169 						rate = B_2400_BPS;
170 						break;
171 					case 4800:
172 						rate = B_4800_BPS;
173 						break;
174 					case 9600:
175 						rate = B_9600_BPS;
176 						break;
177 					case 19200:
178 						rate = B_19200_BPS;
179 						break;
180 					case 31250:
181 						rate = B_31250_BPS;
182 						break;
183 					case 38400:
184 						rate = B_38400_BPS;
185 						break;
186 					case 57600:
187 						rate = B_57600_BPS;
188 						break;
189 					case 115200:
190 						rate = B_115200_BPS;
191 						break;
192 					case 230400:
193 						rate = B_230400_BPS;
194 						break;
195 					default:
196 						rate = B_0_BPS;
197 						break;
198 				}
199 				fSerialPort.SetDataRate(rate);
200 			}
201 
202 			break;
203 		}
204 		default:
205 			BApplication::MessageReceived(message);
206 	}
207 }
208 
209 
210 /* static */
211 status_t SerialApp::PollSerial(void*)
212 {
213 	SerialApp* application = (SerialApp*)be_app;
214 	char buffer[256];
215 
216 	for(;;)
217 	{
218 		ssize_t bytesRead;
219 
220 		bytesRead = application->fSerialPort.Read(buffer, 256);
221 		if (bytesRead == B_FILE_ERROR)
222 		{
223 			// Port is not open - wait for it and start over
224 			acquire_sem(application->fSerialLock);
225 		} else if (bytesRead > 0) {
226 			// We read something, forward it to the app for handling
227 			BMessage* serialData = new BMessage(kMsgDataRead);
228 			serialData->AddData("data", B_RAW_TYPE, buffer, bytesRead);
229 			be_app_messenger.SendMessage(serialData);
230 		}
231 	}
232 
233 	// Should not reach this line anyway...
234 	return B_OK;
235 }
236 
237 const char* SerialApp::kApplicationSignature
238 	= "application/x-vnd.haiku.SerialConnect";
239 
240 
241 int main(int argc, char** argv)
242 {
243 	SerialApp app;
244 	app.Run();
245 }
246