rs_232 2.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Gemfile +3 -0
- data/LICENSE.txt +22 -0
- data/README.md +64 -0
- data/Rakefile +47 -0
- data/bin/env.rb +9 -0
- data/cucumber.yml +24 -0
- data/ext/rs_232/constants.c +51 -0
- data/ext/rs_232/constants.h +98 -0
- data/ext/rs_232/extconf.rb +102 -0
- data/ext/rs_232/initializer.c +399 -0
- data/ext/rs_232/initializer.h +54 -0
- data/ext/rs_232/posix/port.c +429 -0
- data/ext/rs_232/posix/port.h +53 -0
- data/ext/rs_232/structs.h +62 -0
- data/ext/rs_232/windows/port.c +358 -0
- data/ext/rs_232/windows/port.h +53 -0
- data/features/config/config.yml +2 -0
- data/features/connection.feature +8 -0
- data/features/step_definitions/connection_steps.rb +33 -0
- data/features/support/adapter/dev.rb +131 -0
- data/features/support/adapter/generic.rb +64 -0
- data/features/support/adapter/rs_logger.rb +36 -0
- data/features/support/adapter.rb +5 -0
- data/features/support/after.rb +5 -0
- data/features/support/env.rb +100 -0
- data/gem_tasks/cov.rake +5 -0
- data/gem_tasks/cucumber.rake +23 -0
- data/gem_tasks/doc.rake +12 -0
- data/gem_tasks/environment.rake +7 -0
- data/gem_tasks/rspec.rake +6 -0
- data/lib/rs_232/version.rb +8 -0
- data/lib/rs_232.rb +145 -0
- data/rs_232.gemspec +40 -0
- data/spec/simplecov_setup.rb +15 -0
- data/spec/spec_helper.rb +15 -0
- data/spec/support/fixtures.rb +23 -0
- metadata +198 -0
| @@ -0,0 +1,358 @@ | |
| 1 | 
            +
            /*
         | 
| 2 | 
            +
             * Copyright (c) 2013, Ingenico Inc.
         | 
| 3 | 
            +
             *
         | 
| 4 | 
            +
             * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
         | 
| 5 | 
            +
             * provided that the above copyright notice and this permission notice appear in all copies.
         | 
| 6 | 
            +
             *
         | 
| 7 | 
            +
             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
         | 
| 8 | 
            +
             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
         | 
| 9 | 
            +
             * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
         | 
| 10 | 
            +
             * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
         | 
| 11 | 
            +
             * PERFORMANCE OF THIS SOFTWARE.
         | 
| 12 | 
            +
             *
         | 
| 13 | 
            +
             **/
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            #include "port.h"
         | 
| 16 | 
            +
             | 
| 17 | 
            +
             | 
| 18 | 
            +
            VALUE setDtrIO(VALUE self, VALUE rb_int)
         | 
| 19 | 
            +
            {
         | 
| 20 | 
            +
                {
         | 
| 21 | 
            +
                    Check_Type(rb_int, T_FIXNUM);
         | 
| 22 | 
            +
                }
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                int boolean = FIX2INT(rb_int);
         | 
| 25 | 
            +
             | 
| 26 | 
            +
                PortDescriptor *port = NULL;
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                return INT2FIX( EscapeCommFunction(port->fd, boolean == 1 ? SETDTR : CLRDTR) );
         | 
| 31 | 
            +
            }
         | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
| 34 | 
            +
            VALUE setRtsIO(VALUE self, VALUE rb_int)
         | 
| 35 | 
            +
            {
         | 
| 36 | 
            +
                {
         | 
| 37 | 
            +
                    Check_Type(rb_int, T_FIXNUM);
         | 
| 38 | 
            +
                }
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                int boolean = FIX2INT(rb_int);
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                PortDescriptor *port = NULL;
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                return INT2FIX( EscapeCommFunction(port->fd, boolean == 1 ? SETRTS : CLRRTS) );
         | 
| 47 | 
            +
            }
         | 
| 48 | 
            +
             | 
| 49 | 
            +
             | 
| 50 | 
            +
            VALUE lineStatusIO(VALUE self)
         | 
| 51 | 
            +
            {
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                PortDescriptor *port = NULL;
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 56 | 
            +
             | 
| 57 | 
            +
                unsigned long Status = 0, Temp = 0;
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                GetCommModemStatus(port->fd, &Temp);
         | 
| 60 | 
            +
             | 
| 61 | 
            +
                if (Temp & MS_CTS_ON) Status |= LS_CTS;
         | 
| 62 | 
            +
                if (Temp & MS_DSR_ON) Status |= LS_DSR;
         | 
| 63 | 
            +
                if (Temp & MS_RING_ON) Status |= LS_RI;
         | 
| 64 | 
            +
                if (Temp & MS_RLSD_ON) Status |= LS_DCD;
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                return LONG2FIX(Status);
         | 
| 67 | 
            +
            }
         | 
| 68 | 
            +
             | 
| 69 | 
            +
             | 
| 70 | 
            +
            static void platformInitIO(PortDescriptor *port)
         | 
| 71 | 
            +
            {
         | 
| 72 | 
            +
                port->fd     = INVALID_HANDLE_VALUE;
         | 
| 73 | 
            +
                port->status = 1;
         | 
| 74 | 
            +
            }
         | 
| 75 | 
            +
             | 
| 76 | 
            +
             | 
| 77 | 
            +
            void updateSettings(PortDescriptor *port)
         | 
| 78 | 
            +
            {
         | 
| 79 | 
            +
             | 
| 80 | 
            +
                if (port->status != 0)
         | 
| 81 | 
            +
                    rb_raise(rb_eException, "Can not set due to comport is not open, status: %d\n", port->status);
         | 
| 82 | 
            +
             | 
| 83 | 
            +
             | 
| 84 | 
            +
                if (port->toBeUpdated & T_BaudRate)
         | 
| 85 | 
            +
                    port->commConfig.dcb.BaudRate = port->settings.BaudRate;
         | 
| 86 | 
            +
             | 
| 87 | 
            +
             | 
| 88 | 
            +
                if (port->toBeUpdated & T_Parity)
         | 
| 89 | 
            +
                {
         | 
| 90 | 
            +
                    port->commConfig.dcb.Parity  = (BYTE) port->settings.Parity;
         | 
| 91 | 
            +
                    port->commConfig.dcb.fParity = (port->settings.Parity == PAR_NONE) ? 0 : 1;
         | 
| 92 | 
            +
                }
         | 
| 93 | 
            +
             | 
| 94 | 
            +
             | 
| 95 | 
            +
                if (port->toBeUpdated & T_DataBits)
         | 
| 96 | 
            +
                {
         | 
| 97 | 
            +
                    port->commConfig.dcb.ByteSize = (BYTE) port->settings.DataBits;
         | 
| 98 | 
            +
                }
         | 
| 99 | 
            +
             | 
| 100 | 
            +
             | 
| 101 | 
            +
                if (port->toBeUpdated & T_StopBits)
         | 
| 102 | 
            +
                {
         | 
| 103 | 
            +
                    switch (port->settings.StopBits)
         | 
| 104 | 
            +
                    {
         | 
| 105 | 
            +
                        case STOP_1:
         | 
| 106 | 
            +
                            port->commConfig.dcb.StopBits = ONESTOPBIT;
         | 
| 107 | 
            +
                            break;
         | 
| 108 | 
            +
                        case STOP_2:
         | 
| 109 | 
            +
                            port->commConfig.dcb.StopBits = TWOSTOPBITS;
         | 
| 110 | 
            +
                            break;
         | 
| 111 | 
            +
                    }
         | 
| 112 | 
            +
                }
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                if (port->toBeUpdated & T_Flow)
         | 
| 115 | 
            +
                {
         | 
| 116 | 
            +
                    switch (port->settings.FlowControl)
         | 
| 117 | 
            +
                    {
         | 
| 118 | 
            +
                        case FLOW_OFF:
         | 
| 119 | 
            +
                            port->commConfig.dcb.fOutxCtsFlow = 0;
         | 
| 120 | 
            +
                            port->commConfig.dcb.fRtsControl  = RTS_CONTROL_DISABLE;
         | 
| 121 | 
            +
                            port->commConfig.dcb.fInX         = 0;
         | 
| 122 | 
            +
                            port->commConfig.dcb.fOutX        = 0;
         | 
| 123 | 
            +
                            break;
         | 
| 124 | 
            +
                        case FLOW_XONXOFF:
         | 
| 125 | 
            +
                            port->commConfig.dcb.fOutxCtsFlow = 0;
         | 
| 126 | 
            +
                            port->commConfig.dcb.fRtsControl  = RTS_CONTROL_DISABLE;
         | 
| 127 | 
            +
                            port->commConfig.dcb.fInX         = 1;
         | 
| 128 | 
            +
                            port->commConfig.dcb.fOutX        = 1;
         | 
| 129 | 
            +
                            break;
         | 
| 130 | 
            +
                        case FLOW_HARDWARE:
         | 
| 131 | 
            +
                            port->commConfig.dcb.fOutxCtsFlow = 1;
         | 
| 132 | 
            +
                            port->commConfig.dcb.fRtsControl  = RTS_CONTROL_HANDSHAKE;
         | 
| 133 | 
            +
                            port->commConfig.dcb.fInX         = 0;
         | 
| 134 | 
            +
                            port->commConfig.dcb.fOutX        = 0;
         | 
| 135 | 
            +
                            break;
         | 
| 136 | 
            +
                    }
         | 
| 137 | 
            +
                }
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                if (port->toBeUpdated & T_TimeOut)
         | 
| 140 | 
            +
                {
         | 
| 141 | 
            +
                    int millisec                             = port->settings.Timeout_Millisec;
         | 
| 142 | 
            +
             | 
| 143 | 
            +
                    if (millisec == -1)
         | 
| 144 | 
            +
                    {
         | 
| 145 | 
            +
                        port->commTimeouts.ReadIntervalTimeout      = MAXDWORD;
         | 
| 146 | 
            +
                        port->commTimeouts.ReadTotalTimeoutConstant = 0;
         | 
| 147 | 
            +
                    } else
         | 
| 148 | 
            +
                    {
         | 
| 149 | 
            +
                        port->commTimeouts.ReadIntervalTimeout      = MAXDWORD;
         | 
| 150 | 
            +
                        port->commTimeouts.ReadTotalTimeoutConstant = millisec;
         | 
| 151 | 
            +
                    }
         | 
| 152 | 
            +
                    port->commTimeouts.ReadTotalTimeoutMultiplier  = 0;
         | 
| 153 | 
            +
                    port->commTimeouts.WriteTotalTimeoutMultiplier = millisec;
         | 
| 154 | 
            +
                    port->commTimeouts.WriteTotalTimeoutConstant   = 0;
         | 
| 155 | 
            +
                }
         | 
| 156 | 
            +
             | 
| 157 | 
            +
             | 
| 158 | 
            +
                if (port->toBeUpdated & T_SettingsDone)
         | 
| 159 | 
            +
                    SetCommConfig(port->fd, &port->commConfig, sizeof(COMMCONFIG));
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                if ((port->toBeUpdated & T_TimeOut))
         | 
| 162 | 
            +
                    SetCommTimeouts(port->fd, &port->commTimeouts);
         | 
| 163 | 
            +
             | 
| 164 | 
            +
                port->toBeUpdated = 0;
         | 
| 165 | 
            +
            }
         | 
| 166 | 
            +
             | 
| 167 | 
            +
             | 
| 168 | 
            +
            static int queryStatusIO(VALUE self)
         | 
| 169 | 
            +
            {
         | 
| 170 | 
            +
                PortDescriptor *port = NULL;
         | 
| 171 | 
            +
             | 
| 172 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                return port->status;
         | 
| 175 | 
            +
            }
         | 
| 176 | 
            +
             | 
| 177 | 
            +
             | 
| 178 | 
            +
            VALUE isClosedIO(VALUE self)
         | 
| 179 | 
            +
            {
         | 
| 180 | 
            +
                return queryStatusIO(self) != 0 ? Qtrue : Qfalse;
         | 
| 181 | 
            +
            }
         | 
| 182 | 
            +
             | 
| 183 | 
            +
             | 
| 184 | 
            +
            VALUE flushIO(VALUE self)
         | 
| 185 | 
            +
            {
         | 
| 186 | 
            +
                PortDescriptor *port = NULL;
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                return (INT2FIX(FlushFileBuffers(port->fd)));
         | 
| 191 | 
            +
            }
         | 
| 192 | 
            +
             | 
| 193 | 
            +
             | 
| 194 | 
            +
            VALUE bytesAvailableIO(VALUE self)
         | 
| 195 | 
            +
            {
         | 
| 196 | 
            +
                PortDescriptor *port = NULL;
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                DWORD   Errors;
         | 
| 201 | 
            +
                COMSTAT Status;
         | 
| 202 | 
            +
                if (ClearCommError(port->fd, &Errors, &Status))
         | 
| 203 | 
            +
                {
         | 
| 204 | 
            +
                    return INT2FIX(Status.cbInQue);
         | 
| 205 | 
            +
                }
         | 
| 206 | 
            +
                return INT2FIX(0);
         | 
| 207 | 
            +
            }
         | 
| 208 | 
            +
             | 
| 209 | 
            +
             | 
| 210 | 
            +
            VALUE openIO(VALUE self)
         | 
| 211 | 
            +
            {
         | 
| 212 | 
            +
             | 
| 213 | 
            +
                PortDescriptor *port = NULL;
         | 
| 214 | 
            +
             | 
| 215 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                if (port->status == 0)
         | 
| 218 | 
            +
                    return INT2FIX(port->status);
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                DWORD conf_length = sizeof(COMMCONFIG);
         | 
| 221 | 
            +
                port->commConfig.dwSize = conf_length;
         | 
| 222 | 
            +
                DWORD threading = 0;
         | 
| 223 | 
            +
             | 
| 224 | 
            +
                port->fd = CreateFileA(port->settings.ComPort,
         | 
| 225 | 
            +
                        GENERIC_READ | GENERIC_WRITE,
         | 
| 226 | 
            +
                        0,
         | 
| 227 | 
            +
                        NULL,
         | 
| 228 | 
            +
                        OPEN_EXISTING,
         | 
| 229 | 
            +
                        threading,
         | 
| 230 | 
            +
                        NULL);
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                if (port->fd == INVALID_HANDLE_VALUE)
         | 
| 233 | 
            +
                {
         | 
| 234 | 
            +
             | 
| 235 | 
            +
                    port->status = 1;
         | 
| 236 | 
            +
                    rb_raise(rb_eException, "Unable to open comport: %s\n", port->settings.ComPort);
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                } else
         | 
| 239 | 
            +
                {
         | 
| 240 | 
            +
             | 
| 241 | 
            +
                    port->status = 0;
         | 
| 242 | 
            +
                    rb_iv_set(self, "@open", INT2FIX(port->status));
         | 
| 243 | 
            +
             | 
| 244 | 
            +
                    GetCommConfig(port->fd, &port->commConfig, &conf_length);
         | 
| 245 | 
            +
                    GetCommState(port->fd, &(port->commConfig.dcb));
         | 
| 246 | 
            +
             | 
| 247 | 
            +
                    port->commConfig.dcb.fBinary       = 1;
         | 
| 248 | 
            +
                    port->commConfig.dcb.fInX          = 0;
         | 
| 249 | 
            +
                    port->commConfig.dcb.fOutX         = 0;
         | 
| 250 | 
            +
                    port->commConfig.dcb.fAbortOnError = 0;
         | 
| 251 | 
            +
                    port->commConfig.dcb.fNull         = 0;
         | 
| 252 | 
            +
             | 
| 253 | 
            +
                    port->commConfig.dcb.fDtrControl = 1;
         | 
| 254 | 
            +
             | 
| 255 | 
            +
                    port->toBeUpdated = T_ALL;
         | 
| 256 | 
            +
             | 
| 257 | 
            +
                    setSettings(self);
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                }
         | 
| 260 | 
            +
             | 
| 261 | 
            +
                return INT2FIX(port->status);
         | 
| 262 | 
            +
            }
         | 
| 263 | 
            +
             | 
| 264 | 
            +
             | 
| 265 | 
            +
            VALUE writeIO(VALUE self, VALUE message)
         | 
| 266 | 
            +
            {
         | 
| 267 | 
            +
             | 
| 268 | 
            +
                int recv;
         | 
| 269 | 
            +
                int len;
         | 
| 270 | 
            +
                PortDescriptor *port = NULL;
         | 
| 271 | 
            +
             | 
| 272 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 273 | 
            +
             | 
| 274 | 
            +
                Check_Type(message, T_STRING);
         | 
| 275 | 
            +
             | 
| 276 | 
            +
                len = RSTRING_LEN(message);
         | 
| 277 | 
            +
                char cStr[len];
         | 
| 278 | 
            +
                strcpy(cStr, RSTRING_PTR(message));
         | 
| 279 | 
            +
             | 
| 280 | 
            +
                if (!WriteFile(port->fd, cStr, len, (LPDWORD)((void *) &recv), NULL))
         | 
| 281 | 
            +
                {
         | 
| 282 | 
            +
                    rb_raise(rb_eIOError, "IO: writing of the %d bytes has been failed", len);
         | 
| 283 | 
            +
                }
         | 
| 284 | 
            +
             | 
| 285 | 
            +
                return (INT2FIX(recv));
         | 
| 286 | 
            +
             | 
| 287 | 
            +
            }
         | 
| 288 | 
            +
             | 
| 289 | 
            +
             | 
| 290 | 
            +
            VALUE readIO(VALUE self, VALUE rb_int)
         | 
| 291 | 
            +
            {
         | 
| 292 | 
            +
             | 
| 293 | 
            +
                {
         | 
| 294 | 
            +
                    Check_Type(rb_int, T_FIXNUM);
         | 
| 295 | 
            +
                }
         | 
| 296 | 
            +
             | 
| 297 | 
            +
                PortDescriptor *port = NULL;
         | 
| 298 | 
            +
             | 
| 299 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 300 | 
            +
             | 
| 301 | 
            +
                int n;
         | 
| 302 | 
            +
                int len = FIX2INT(rb_int);
         | 
| 303 | 
            +
                char buf[len];
         | 
| 304 | 
            +
             | 
| 305 | 
            +
                ReadFile(port->fd, &buf, len, (LPDWORD)((void *) &n), NULL);
         | 
| 306 | 
            +
             | 
| 307 | 
            +
                if (n > 0)
         | 
| 308 | 
            +
                  return rb_str_new(buf, n);
         | 
| 309 | 
            +
             | 
| 310 | 
            +
                return Qnil;
         | 
| 311 | 
            +
            }
         | 
| 312 | 
            +
             | 
| 313 | 
            +
             | 
| 314 | 
            +
            VALUE closeIO(VALUE self)
         | 
| 315 | 
            +
            {
         | 
| 316 | 
            +
             | 
| 317 | 
            +
                PortDescriptor *port = NULL;
         | 
| 318 | 
            +
             | 
| 319 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 320 | 
            +
             | 
| 321 | 
            +
                flushIO(self);
         | 
| 322 | 
            +
                port->status = CloseHandle(port->fd);
         | 
| 323 | 
            +
                port->fd     = INVALID_HANDLE_VALUE;
         | 
| 324 | 
            +
             | 
| 325 | 
            +
                rb_iv_set(self, "@open", INT2FIX(port->status));
         | 
| 326 | 
            +
             | 
| 327 | 
            +
                return INT2FIX(port->status);
         | 
| 328 | 
            +
             | 
| 329 | 
            +
            }
         | 
| 330 | 
            +
             | 
| 331 | 
            +
             | 
| 332 | 
            +
            VALUE initializeStruct(VALUE self, VALUE portName)
         | 
| 333 | 
            +
            {
         | 
| 334 | 
            +
             | 
| 335 | 
            +
                {
         | 
| 336 | 
            +
                    Check_Type(portName, T_STRING);
         | 
| 337 | 
            +
                }
         | 
| 338 | 
            +
             | 
| 339 | 
            +
                PortDescriptor *port = NULL;
         | 
| 340 | 
            +
             | 
| 341 | 
            +
                Data_Get_Struct(self, PortDescriptor, port);
         | 
| 342 | 
            +
             | 
| 343 | 
            +
                port->settings.BaudRate         = BAUD115200;
         | 
| 344 | 
            +
                port->settings.Parity           = PAR_NONE;
         | 
| 345 | 
            +
                port->settings.FlowControl      = FLOW_OFF;
         | 
| 346 | 
            +
                port->settings.DataBits         = DATA_8;
         | 
| 347 | 
            +
                port->settings.StopBits         = STOP_1;
         | 
| 348 | 
            +
                port->settings.Timeout_Millisec = 0;
         | 
| 349 | 
            +
             | 
| 350 | 
            +
                snprintf(port->settings.ComPort, sizeof(port->settings.ComPort) - 1, WIN_PATTERN, RSTRING_PTR(portName));
         | 
| 351 | 
            +
             | 
| 352 | 
            +
                platformInitIO(port);
         | 
| 353 | 
            +
             | 
| 354 | 
            +
                rb_iv_set(self, "@port", portName);
         | 
| 355 | 
            +
             | 
| 356 | 
            +
                return self;
         | 
| 357 | 
            +
            }
         | 
| 358 | 
            +
             | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            /*
         | 
| 2 | 
            +
             * Copyright (c) 2013, Ingenico Inc.
         | 
| 3 | 
            +
             *
         | 
| 4 | 
            +
             * Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted,
         | 
| 5 | 
            +
             * provided that the above copyright notice and this permission notice appear in all copies.
         | 
| 6 | 
            +
             *
         | 
| 7 | 
            +
             * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL
         | 
| 8 | 
            +
             * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
         | 
| 9 | 
            +
             * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
         | 
| 10 | 
            +
             * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
         | 
| 11 | 
            +
             * PERFORMANCE OF THIS SOFTWARE.
         | 
| 12 | 
            +
             *
         | 
| 13 | 
            +
             **/
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            #ifndef rs_232_port_h____FILEEXTENSION___
         | 
| 16 | 
            +
            #define rs_232_port_h____FILEEXTENSION___
         | 
| 17 | 
            +
             | 
| 18 | 
            +
            #   include <ruby.h>
         | 
| 19 | 
            +
            #   include <ruby/io.h>
         | 
| 20 | 
            +
            #   include <windows.h>
         | 
| 21 | 
            +
            #   include <fcntl.h>
         | 
| 22 | 
            +
            #   include <io.h>
         | 
| 23 | 
            +
            #   include <stdio.h>
         | 
| 24 | 
            +
            #   include <string.h>
         | 
| 25 | 
            +
            #   include "structs.h"
         | 
| 26 | 
            +
             | 
| 27 | 
            +
            #define WIN_PATTERN "\\\\.\\%s"
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            void setBaudRate(VALUE, VALUE);
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            VALUE getBaudRate(VALUE);
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            void setParity(VALUE, VALUE);
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            VALUE getParity(VALUE);
         | 
| 36 | 
            +
             | 
| 37 | 
            +
            void setDataBits(VALUE, VALUE);
         | 
| 38 | 
            +
             | 
| 39 | 
            +
            VALUE getDataBits(VALUE);
         | 
| 40 | 
            +
             | 
| 41 | 
            +
            void setStopBits(VALUE, VALUE);
         | 
| 42 | 
            +
             | 
| 43 | 
            +
            VALUE getStopBits(VALUE);
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            void setFlowControl(VALUE, VALUE);
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            VALUE getFlowControl(VALUE);
         | 
| 48 | 
            +
             | 
| 49 | 
            +
            void setTimeout(VALUE, VALUE);
         | 
| 50 | 
            +
             | 
| 51 | 
            +
            void setSettings(VALUE);
         | 
| 52 | 
            +
             | 
| 53 | 
            +
            #endif
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            When /^connection instance "(should|should not)" be available$/ do |matcher|
         | 
| 2 | 
            +
             | 
| 3 | 
            +
              action = matcher == 'should' ? :should : :should_not
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              if respond_to? :should
         | 
| 6 | 
            +
                adapter.open?.send(action, be_true)
         | 
| 7 | 
            +
              else
         | 
| 8 | 
            +
                assert_equal(adapter.open?, action == :should)
         | 
| 9 | 
            +
              end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
            Given /^I "(open|close)" connection$/ do |action|
         | 
| 14 | 
            +
             | 
| 15 | 
            +
              adapter.send(action)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              if action == 'close'
         | 
| 18 | 
            +
                if respond_to? :should
         | 
| 19 | 
            +
                  adapter.open?.should be_false
         | 
| 20 | 
            +
                else
         | 
| 21 | 
            +
                  assert_equal(connection.open?, false)
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              else
         | 
| 24 | 
            +
                if respond_to? :should
         | 
| 25 | 
            +
                  adapter.open?.should be_true
         | 
| 26 | 
            +
                else
         | 
| 27 | 
            +
                  assert_equal(connection.open?, true)
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
              end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
             | 
| @@ -0,0 +1,131 @@ | |
| 1 | 
            +
            class Adapter::Dev < Adapter::Generic
         | 
| 2 | 
            +
              attr_reader :interface
         | 
| 3 | 
            +
              include CommPort
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              # == constructor with default params
         | 
| 6 | 
            +
              #  by default port will be configured with:
         | 
| 7 | 
            +
              #
         | 
| 8 | 
            +
              #  @baud_rate = 115200  # BAUD_115200
         | 
| 9 | 
            +
              #  @data_bits = 8       # DATA_BITS_8
         | 
| 10 | 
            +
              #  @parity = 0          # PAR_NONE
         | 
| 11 | 
            +
              #  @stop_bits = 1       # STOP_1
         | 
| 12 | 
            +
              #  @flow_control = 0    # FLOW_OFF
         | 
| 13 | 
            +
              #
         | 
| 14 | 
            +
              #
         | 
| 15 | 
            +
              def initialize(port, &block)
         | 
| 16 | 
            +
                @interface ||= Rs232.new(port)
         | 
| 17 | 
            +
                connect
         | 
| 18 | 
            +
                $stdout.puts "*** Rs232 instance has been initialized. Build v#{CommPort::VERSION}"
         | 
| 19 | 
            +
                super(&block)
         | 
| 20 | 
            +
              end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              # Open and configure interface
         | 
| 23 | 
            +
              #
         | 
| 24 | 
            +
              # @return [Bool]
         | 
| 25 | 
            +
              #
         | 
| 26 | 
            +
              def connect
         | 
| 27 | 
            +
                @interface.open
         | 
| 28 | 
            +
                # custom configuration should be there if required
         | 
| 29 | 
            +
                # @interface.baud_rate    = BAUD_115200
         | 
| 30 | 
            +
                # @interface.data_bits    = DATA_BITS_8
         | 
| 31 | 
            +
                # @interface.parity       = PAR_NONE
         | 
| 32 | 
            +
                # @interface.stop_bits    = STOP_1
         | 
| 33 | 
            +
                # @interface.flow_control = FLOW_OFF
         | 
| 34 | 
            +
                @open = open?
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              # == Write function implementation
         | 
| 38 | 
            +
              #
         | 
| 39 | 
            +
              # @param [String] bytes
         | 
| 40 | 
            +
              # @return [Int]
         | 
| 41 | 
            +
              #
         | 
| 42 | 
            +
              def write(bytes)
         | 
| 43 | 
            +
                @interface.write(bytes)
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              # == Closing interface and freeing structures
         | 
| 47 | 
            +
              #
         | 
| 48 | 
            +
              #  @return  [Bool]
         | 
| 49 | 
            +
              #
         | 
| 50 | 
            +
              def close
         | 
| 51 | 
            +
                @interface.flush
         | 
| 52 | 
            +
                @interface.close
         | 
| 53 | 
            +
                @open = open?
         | 
| 54 | 
            +
                !open?
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
             | 
| 57 | 
            +
              # == Flashing buffer function
         | 
| 58 | 
            +
              #
         | 
| 59 | 
            +
              def flush
         | 
| 60 | 
            +
                @interface.flush
         | 
| 61 | 
            +
              end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
              # @return [Bool]
         | 
| 64 | 
            +
              #
         | 
| 65 | 
            +
              def open?
         | 
| 66 | 
            +
                @interface && !@interface.closed?
         | 
| 67 | 
            +
              end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
              # == read() implementation example
         | 
| 70 | 
            +
              #
         | 
| 71 | 
            +
              # @param +count+ [Int]
         | 
| 72 | 
            +
              # @param +blocking+ [Bool]
         | 
| 73 | 
            +
              #
         | 
| 74 | 
            +
              # @return [String]
         | 
| 75 | 
            +
              #
         | 
| 76 | 
            +
              # === Alternative implementation:
         | 
| 77 | 
            +
              # @usage:
         | 
| 78 | 
            +
              #
         | 
| 79 | 
            +
              #  +timeout+ = blocking_value ? 15000 : 0
         | 
| 80 | 
            +
              #  +@interface.timeout+ = +timeout+
         | 
| 81 | 
            +
              #  +@interface.read( +count+ )+
         | 
| 82 | 
            +
              #
         | 
| 83 | 
            +
              def read(count, blocking = false)
         | 
| 84 | 
            +
                array       = []
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                bytes_count = (count == -1) ? @interface.available? : count
         | 
| 87 | 
            +
             | 
| 88 | 
            +
                if blocking
         | 
| 89 | 
            +
                  bytes = read_io_until(count, count)
         | 
| 90 | 
            +
                  array.push bytes if bytes
         | 
| 91 | 
            +
                else
         | 
| 92 | 
            +
                  bytes_count.times do
         | 
| 93 | 
            +
                    byte = @interface.read(1)
         | 
| 94 | 
            +
                    array.push byte if byte
         | 
| 95 | 
            +
                  end
         | 
| 96 | 
            +
                end
         | 
| 97 | 
            +
                array.empty? ? nil : array.join
         | 
| 98 | 
            +
              end
         | 
| 99 | 
            +
             | 
| 100 | 
            +
              private
         | 
| 101 | 
            +
             | 
| 102 | 
            +
              # == simulate blocking function
         | 
| 103 | 
            +
              #
         | 
| 104 | 
            +
              # @param +count+ [Int]
         | 
| 105 | 
            +
              # @param +up_to+ [Int]
         | 
| 106 | 
            +
              #
         | 
| 107 | 
            +
              # no direct ruby usage
         | 
| 108 | 
            +
              #
         | 
| 109 | 
            +
              def block_io_until(count, up_to)
         | 
| 110 | 
            +
                while @interface.available? < count && up_to > 0
         | 
| 111 | 
            +
                  up_to -= 1
         | 
| 112 | 
            +
                end
         | 
| 113 | 
            +
                up_to > 0
         | 
| 114 | 
            +
              end
         | 
| 115 | 
            +
             | 
| 116 | 
            +
              # == simulate blocking function
         | 
| 117 | 
            +
              #
         | 
| 118 | 
            +
              # @param +count+ [Int]
         | 
| 119 | 
            +
              # @param +up_to+ [Int]
         | 
| 120 | 
            +
              #
         | 
| 121 | 
            +
              # no direct ruby usage
         | 
| 122 | 
            +
              #
         | 
| 123 | 
            +
              def read_io_until(count, up_to)
         | 
| 124 | 
            +
                until block_io_until(count, up_to)
         | 
| 125 | 
            +
                  sleep 0.001
         | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
                read(count)
         | 
| 128 | 
            +
              end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
            end
         | 
| 131 | 
            +
             | 
| @@ -0,0 +1,64 @@ | |
| 1 | 
            +
            require 'monitor'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Adapter
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              class Generic
         | 
| 6 | 
            +
                include MonitorMixin
         | 
| 7 | 
            +
                include RsLogger
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                attr_accessor :event
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                def initialize(*args, &block)
         | 
| 12 | 
            +
                  Thread.abort_on_exception = true
         | 
| 13 | 
            +
                  unless instance_variables.include?(:@rxd)
         | 
| 14 | 
            +
                    @rxd = true
         | 
| 15 | 
            +
                  end
         | 
| 16 | 
            +
                  @event = block
         | 
| 17 | 
            +
                  super(*args)
         | 
| 18 | 
            +
                  run
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def reading_allowed?
         | 
| 22 | 
            +
                  @rxd
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def defer_reading
         | 
| 26 | 
            +
                  @rxd = false
         | 
| 27 | 
            +
                  !reading_allowed?
         | 
| 28 | 
            +
                end
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                def allow_reading
         | 
| 31 | 
            +
                  @rxd = true
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def rx(int, blocking = false)
         | 
| 35 | 
            +
                  byte = read(int, blocking)
         | 
| 36 | 
            +
                  if byte
         | 
| 37 | 
            +
                    logger.debug "RX [#{byte.length}]: #{byte.inspect}"
         | 
| 38 | 
            +
                  end
         | 
| 39 | 
            +
                  byte
         | 
| 40 | 
            +
                end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                def tx(bytes)
         | 
| 43 | 
            +
                  int = write(bytes)
         | 
| 44 | 
            +
                  logger.debug "TX [#{int}]: #{bytes.inspect}"
         | 
| 45 | 
            +
                  int
         | 
| 46 | 
            +
                end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                def restart_rx_thread
         | 
| 49 | 
            +
                  allow_reading
         | 
| 50 | 
            +
                  run
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
             | 
| 53 | 
            +
                def run
         | 
| 54 | 
            +
                  Thread.new do
         | 
| 55 | 
            +
                    loop do
         | 
| 56 | 
            +
                      rx(1, false) if reading_allowed?
         | 
| 57 | 
            +
                      sleep(0.005)
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                  end
         | 
| 60 | 
            +
                end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
              end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
            end
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            require "logger"
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Adapter::RsLogger
         | 
| 4 | 
            +
             | 
| 5 | 
            +
              class LogFormatter < ::Logger::Formatter
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def call(severity, time, progname, msg)
         | 
| 8 | 
            +
                  "#{format_datetime(time)}[TID:#{$$}] [Rs232::#{severity}]: #{msg}\n"
         | 
| 9 | 
            +
                end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
             | 
| 12 | 
            +
                private
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def format_datetime(time)
         | 
| 15 | 
            +
                  if @datetime_format.nil?
         | 
| 16 | 
            +
                    time.strftime("%Y-%m-%d %H:%M:%S.") << "%06d " % time.usec
         | 
| 17 | 
            +
                  else
         | 
| 18 | 
            +
                    time.strftime(@datetime_format)
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
             | 
| 24 | 
            +
              def logger
         | 
| 25 | 
            +
                @logger ||= begin
         | 
| 26 | 
            +
                  logger = ::Logger.new( ENV["LOG"]||$stdout )
         | 
| 27 | 
            +
                  logger.level = ENV["DEBUG"].to_i
         | 
| 28 | 
            +
                  logger.formatter= LogFormatter.new
         | 
| 29 | 
            +
                  logger
         | 
| 30 | 
            +
                end
         | 
| 31 | 
            +
              end
         | 
| 32 | 
            +
              
         | 
| 33 | 
            +
              module_function :logger
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
             |