added buffer to serial device output dropping frames on serial output if buffer gets too full (more than 10 frames) added support for high baudrates
Stefan Schuermans

Stefan Schuermans commited on 2011-12-27 08:02:03
Showing 4 changed files, with 106 additions and 8 deletions.

... ...
@@ -3,6 +3,7 @@
3 3
    Copyleft GNU public license - http://www.gnu.org/copyleft/gpl.html
4 4
    a blinkenarea.org project */
5 5
 
6
+#include <errno.h>
6 7
 #include <fcntl.h>
7 8
 #include <sys/stat.h>
8 9
 #include <sys/types.h>
... ...
@@ -70,8 +71,51 @@ bool Device::setSerCfg(const SerCfg& serCfg)
70 71
     case    9600: tio.c_cflag |=    B9600; break;
71 72
     case   19200: tio.c_cflag |=   B19200; break;
72 73
     case   38400: tio.c_cflag |=   B38400; break;
74
+#ifdef B57600
73 75
     case   57600: tio.c_cflag |=   B57600; break;
76
+#endif
77
+#ifdef B115200
74 78
     case  115200: tio.c_cflag |=  B115200; break;
79
+#endif
80
+#ifdef B230400
81
+    case  230400: tio.c_cflag |=  B230400; break;
82
+#endif
83
+#ifdef B460800
84
+    case  460800: tio.c_cflag |=  B460800; break;
85
+#endif
86
+#ifdef B500000
87
+    case  500000: tio.c_cflag |=  B500000; break;
88
+#endif
89
+#ifdef B576000
90
+    case  576000: tio.c_cflag |=  B576000; break;
91
+#endif
92
+#ifdef B921600
93
+    case  921600: tio.c_cflag |=  B921600; break;
94
+#endif
95
+#ifdef B1000000
96
+    case 1000000: tio.c_cflag |= B1000000; break;
97
+#endif
98
+#ifdef B1152000
99
+    case 1152000: tio.c_cflag |= B1152000; break;
100
+#endif
101
+#ifdef B1500000
102
+    case 1500000: tio.c_cflag |= B1500000; break;
103
+#endif
104
+#ifdef B2000000
105
+    case 2000000: tio.c_cflag |= B2000000; break;
106
+#endif
107
+#ifdef B2500000
108
+    case 2500000: tio.c_cflag |= B2500000; break;
109
+#endif
110
+#ifdef B3000000
111
+    case 3000000: tio.c_cflag |= B3000000; break;
112
+#endif
113
+#ifdef B3500000
114
+    case 3500000: tio.c_cflag |= B3500000; break;
115
+#endif
116
+#ifdef B4000000
117
+    case 4000000: tio.c_cflag |= B4000000; break;
118
+#endif
75 119
     default: return false; // invalid setting
76 120
   }
77 121
   switch (serCfg.m_data) {
... ...
@@ -100,16 +144,36 @@ bool Device::setSerCfg(const SerCfg& serCfg)
100 144
 /**
101 145
  * @brief write data to device
102 146
  * @param[in] data data to write
103
- * @return if the data could be written
147
+ * @param[out] len number of byte written to device
148
+ * @return if some (or zero) data could be written,
149
+ *         i.e. if the device is still operational
104 150
  */
105
-bool Device::write(const std::string &data)
151
+bool Device::write(const std::string &data, std::string::size_type &len)
106 152
 {
107 153
   // exit if not initialized
108 154
   if (m_fd == -1)
109 155
     return false;
110 156
 
111 157
   // write data
112
-  return ::write(m_fd, data.c_str(), data.size()) == (ssize_t)data.size();
158
+  ssize_t res = ::write(m_fd, data.c_str(), data.size());
159
+  // write failed
160
+  if (res < 0) {
161
+    // real error
162
+    if (errno != EAGAIN && errno != EWOULDBLOCK) {
163
+      len = 0;
164
+      return false; // report error
165
+    }
166
+    // device busy (e.g. serial device buffer full)
167
+    else {
168
+      len = 0;
169
+      return true; // do not report error, device is still working
170
+    }
171
+  }
172
+  // write succeeded
173
+  else {
174
+    len = res;
175
+    return true; // success
176
+  }
113 177
 }
114 178
 
115 179
 } // namespace Blinker
... ...
@@ -46,9 +46,11 @@ public:
46 46
   /**
47 47
    * @brief write data to device
48 48
    * @param[in] data data to write
49
-   * @return if the data could be written
49
+   * @param[out] len number of byte written to device
50
+   * @return if some (or zero) data could be written,
51
+   *         i.e. if the device is still operational
50 52
    */
51
-  bool write(const std::string &data);
53
+bool write(const std::string &data, std::string::size_type &len);
52 54
 
53 55
 }; // class Device
54 56
 
... ...
@@ -136,6 +136,9 @@ void Output::closeDevice()
136 136
     m_pDevice = NULL;
137 137
   }
138 138
 
139
+  // clear buffered data
140
+  m_buffer.clear();
141
+
139 142
   // request time callback in one second (for trying to re-open device)
140 143
   m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + Time(1));
141 144
 }
... ...
@@ -167,12 +170,34 @@ void Output::outputFrame()
167 170
   data.assign(buf, len);
168 171
 
169 172
   // output data to device
170
-  if (!m_pDevice->write(data))
171
-    closeDevice(); // error -> close device
173
+  outputFrameData(data);
172 174
 
173
-  // request time callback in one second (for outputting current frame again)
175
+  /* request time callback in one second
176
+     (for outputting current frame again or reopening device) */
174 177
   m_mgrs.m_callMgr.requestTimeCall(this, Time::now() + Time(1));
175 178
 }
176 179
 
180
+/**
181
+ * @brief output frame data to device
182
+ * @param[in] data data of one frame to output to device
183
+ */
184
+void Output::outputFrameData(const std::string &data)
185
+{
186
+  // no device -> leave
187
+  if (!m_pDevice)
188
+    return;
189
+
190
+  // add data to buffer (if current buffer contains less than 10 frames)
191
+  if (m_buffer.size() < data.size() * 10)
192
+    m_buffer += data;
193
+
194
+  // write (at least some) data to device
195
+  std::string::size_type len;
196
+  if (!m_pDevice->write(m_buffer, len))
197
+    closeDevice(); // error -> close device
198
+  else
199
+    m_buffer = m_buffer.substr(len); // done -> remove written data from buffer
200
+}
201
+
177 202
 } // namespace Blinker
178 203
 
... ...
@@ -75,12 +75,19 @@ protected:
75 75
   /// output current frame to device
76 76
   void outputFrame();
77 77
 
78
+  /**
79
+   * @brief output frame data to device
80
+   * @param[in] data data of one frame to output to device
81
+   */
82
+  void outputFrameData(const std::string &data);
83
+
78 84
 protected:
79 85
   InStreamFile m_fileInStream; ///< input stream name file
80 86
   ProtocolFile m_fileProtocol; ///< protocol file
81 87
   NameFile     m_fileDevice;   ///< name file containing name of device
82 88
   SerCfgFile   m_fileSerCfg;   ///< serial port configuration file
83 89
   Device       *m_pDevice;     ///< device to output to
90
+  std::string  m_buffer;       ///< buffered data still to be output to device
84 91
 }; // class Output
85 92
 
86 93
 } // namespace Blinker
87 94