]> git.mxchange.org Git - flightgear.git/blob - src/Network/generic.cxx
043ce2457b942e808c8dd603bc86ec6514beef9d
[flightgear.git] / src / Network / generic.cxx
1 // generic.cxx -- generic protocal class
2 //
3 // Written by Curtis Olson, started November 1999.
4 //
5 // Copyright (C) 1999  Curtis L. Olson - curt@flightgear.org
6 //
7 // This program is free software; you can redistribute it and/or
8 // modify it under the terms of the GNU General Public License as
9 // published by the Free Software Foundation; either version 2 of the
10 // License, or (at your option) any later version.
11 //
12 // This program is distributed in the hope that it will be useful, but
13 // WITHOUT ANY WARRANTY; without even the implied warranty of
14 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 // General Public License for more details.
16 //
17 // You should have received a copy of the GNU General Public License
18 // along with this program; if not, write to the Free Software
19 // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 //
21 // $Id$
22
23
24 #include <string.h>             // strstr()
25 #include <stdlib.h>             // strtod(), atoi()
26
27 #include <simgear/debug/logstream.hxx>
28 #include <simgear/io/iochannel.hxx>
29 #include <simgear/structure/exception.hxx>
30 #include <simgear/misc/sg_path.hxx>
31 #include <simgear/props/props.hxx>
32 #include <simgear/props/props_io.hxx>
33
34 #include <Main/globals.hxx>
35 #include <Main/fg_props.hxx>
36
37 #include "generic.hxx"
38
39
40
41 FGGeneric::FGGeneric(string& config) {
42
43     string file = config+".xml";
44
45     SGPath path( globals->get_fg_root() );
46     path.append("Protocol");
47     path.append(file.c_str());
48     SG_LOG(SG_GENERAL, SG_INFO, "Reading communication protocol from "
49                                 << path.str());
50
51     SGPropertyNode root;
52     try {
53         readProperties(path.str(), &root);
54      } catch (const sg_exception &e) {
55         SG_LOG(SG_GENERAL, SG_ALERT,
56          "Unable to load the protocol configuration file");
57          return;
58     }
59
60     SGPropertyNode *output = root.getNode("generic/output");
61     read_config(output, _out_message);
62
63     SGPropertyNode *input = root.getNode("generic/input");
64     read_config(input, _in_message);
65 }
66
67 FGGeneric::~FGGeneric() {
68     _out_message.clear();
69 }
70
71
72 // generate the message
73 bool FGGeneric::gen_message() {
74
75     string generic_sentence;
76     char tmp[255];
77
78     double val;
79
80     for (unsigned int i = 0; i < _out_message.size(); i++) {
81
82         if (i > 0)
83            generic_sentence += var_separator;
84
85         switch (_out_message[i].type) {
86         case FG_INT:
87             val = _out_message[i].offset +
88                     _out_message[i].prop->getIntValue() * _out_message[i].factor;
89             snprintf(tmp, 255, _out_message[i].format.c_str(), (int)val);
90             break;
91
92         case FG_BOOL:
93             snprintf(tmp, 255, _out_message[i].format.c_str(),
94                                _out_message[i].prop->getBoolValue());
95             break;
96
97         case FG_DOUBLE:
98             val = _out_message[i].offset +
99                        _out_message[i].prop->getDoubleValue() * _out_message[i].factor;
100             snprintf(tmp, 255, _out_message[i].format.c_str(), val);
101             break;
102
103         default: // SG_STRING
104              snprintf(tmp, 255, _out_message[i].format.c_str(),
105                                _out_message[i].prop->getStringValue());
106         }
107
108         generic_sentence += tmp;
109     }
110
111     /* After each lot of variables has been added, put the line separator
112      * char/string
113      */
114     generic_sentence += line_separator;
115  
116             
117     length =  generic_sentence.length();
118     strncpy( buf, generic_sentence.c_str(), length );
119
120     return true;
121 }
122
123 bool FGGeneric::parse_message() {
124     char *p2, *p1 = buf;
125     double val;
126     int i = 0;
127
128     while (p1 && strcmp(p1, line_separator.c_str())) {
129
130         p2 = strstr(p1, var_separator.c_str());
131         if (p2)
132             *(p2++) = 0;
133
134         switch (_out_message[i].type) {
135         case FG_INT:
136             val = _out_message[i].offset + atoi(p1) * _out_message[i].factor;
137             _out_message[i].prop->setIntValue(val);
138             break;
139
140         case FG_BOOL:
141             _out_message[i].prop->setIntValue( atoi(p1) );
142             break;
143
144         case FG_DOUBLE:
145             val = _out_message[i].offset + strtod(p1, 0) * _out_message[i].factor;
146             _out_message[i].prop->setIntValue(val);
147             break;
148
149         default: // SG_STRING
150              _out_message[i].prop->setStringValue(p1);
151         }
152
153         p1 = p2;
154         i++;
155     }
156     
157     return true;
158 }
159
160
161
162 // open hailing frequencies
163 bool FGGeneric::open() {
164     if ( is_enabled() ) {
165         SG_LOG( SG_IO, SG_ALERT, "This shouldn't happen, but the channel " 
166                 << "is already in use, ignoring" );
167         return false;
168     }
169
170     SGIOChannel *io = get_io_channel();
171
172     if ( ! io->open( get_direction() ) ) {
173         SG_LOG( SG_IO, SG_ALERT, "Error opening channel communication layer." );
174         return false;
175     }
176
177     set_enabled( true );
178
179     return true;
180 }
181
182
183 // process work for this port
184 bool FGGeneric::process() {
185     SGIOChannel *io = get_io_channel();
186
187     if ( get_direction() == SG_IO_OUT ) {
188         gen_message();
189         if ( ! io->write( buf, length ) ) {
190             SG_LOG( SG_IO, SG_WARN, "Error writing data." );
191             return false;
192         }
193     } else if ( get_direction() == SG_IO_IN ) {
194         if ( (length = io->readline( buf, FG_MAX_MSG_SIZE )) > 0 ) {
195             parse_message();
196         } else {
197             SG_LOG( SG_IO, SG_ALERT, "Error reading data." );
198             return false;
199         }
200     }
201
202     return true;
203 }
204
205
206 // close the channel
207 bool FGGeneric::close() {
208     SGIOChannel *io = get_io_channel();
209
210     set_enabled( false );
211
212     if ( ! io->close() ) {
213         return false;
214     }
215
216     return true;
217 }
218
219
220 void
221 FGGeneric::read_config(SGPropertyNode *root, vector<_serial_prot> &msg)
222 {
223         /* These variables specified in the $FG_ROOT/data/Protocol/xxx.xml
224          * file for each format
225          *
226          * var_sep_string  = the string/charachter to place between variables
227          * line_sep_string = the string/charachter to place at the end of each
228          *                   lot of variables
229          */
230     var_sep_string = root->getStringValue("var_separator");
231     line_sep_string = root->getStringValue("line_separator");
232
233         if ( var_sep_string == "newline" )
234                 var_separator = '\n';
235         else if ( var_sep_string == "tab" )
236                 var_separator = '\t';
237         else if ( var_sep_string == "space" )
238                 var_separator = ' ';
239         else if ( var_sep_string == "formfeed" )
240                 var_separator = '\f';
241         else if ( var_sep_string == "carriagereturn" )
242                 var_sep_string = '\r';
243         else if ( var_sep_string == "verticaltab" )
244                 var_separator = '\v';
245         else
246                 var_separator = var_sep_string;
247
248         if ( line_sep_string == "newline" )
249                 line_separator = '\n';
250         else if ( line_sep_string == "tab" )
251                 line_separator = '\t';
252         else if ( line_sep_string == "space" )
253                 line_separator = ' ';
254         else if ( line_sep_string == "formfeed" )
255                 line_separator = '\f';
256         else if ( line_sep_string == "carriagereturn" )
257                 line_separator = '\r';
258         else if ( line_sep_string == "verticaltab" )
259                 line_separator = '\v';
260         else
261                 line_separator = line_sep_string;
262
263
264     vector<SGPropertyNode_ptr> chunks = root->getChildren("chunk");
265     for (unsigned int i = 0; i < chunks.size(); i++) {
266
267         _serial_prot chunk;
268
269      // chunk.name = chunks[i]->getStringValue("name");
270         chunk.format = chunks[i]->getStringValue("format", "%f");
271         chunk.offset = chunks[i]->getDoubleValue("offset");
272         chunk.factor = chunks[i]->getDoubleValue("offset", 1.0);
273
274         string node = chunks[i]->getStringValue("node");
275         chunk.prop = fgGetNode(node.c_str(), true);
276
277         string type = chunks[i]->getStringValue("type");
278         if (type == "bool")
279             chunk.type = FG_BOOL;
280         else if (type == "float")
281             chunk.type = FG_DOUBLE;
282         else if (type == "string")
283             chunk.type = FG_STRING;
284         else
285             chunk.type = FG_INT;
286
287         msg.push_back(chunk);
288
289     }
290
291 }
292