nmea 0.3 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ %%{
2
+ machine NMEA;
3
+
4
+ wpt_to = ((any - ',') @add_char)* comma %{
5
+ if(*current_string) wpt_to = current_string;
6
+ current_s = current_string;
7
+ *current_s = 0;
8
+ };
9
+
10
+ wpt_from = ((any - '*') @add_char)* %{
11
+ if(*current_string) wpt_from = current_string;
12
+ current_s = current_string;
13
+ *current_s = 0;
14
+ };
15
+
16
+ action read_bod {
17
+ handler.bod(true_course, magnetic_course, wpt_to, wpt_from);
18
+ }
19
+
20
+ bod = '$GPBOD,' true_course magnetic_course wpt_to wpt_from checksum;
21
+ }%%
@@ -0,0 +1,12 @@
1
+ %%{
2
+ machine NMEA;
3
+ gps_quality = ([012345678] @{gps_quality = (GGA_FIX)(fc-'0');}) comma;
4
+ active_satellite_count = (bcd comma @{active_satellite_count = bcd; }) | comma;
5
+ altitude = (number comma alpha @{altitude_units = fc;} comma @{altitude = current_float; current_float = 0;}) | comma alpha comma;
6
+ geoidal_height = (number comma alpha @{geoidal_height_units = fc;} comma @{geoidal_height = current_float; current_float = 0;}) | comma comma;
7
+ dgps_data = (number comma @{dgps_data_age = current_float; current_float = 0; } | comma) b4cd @{dgps_station_id = bcd;};
8
+ action read_gga {
9
+ handler.gga(utc, latitude, longitude, gps_quality, active_satellite_count, gsa_hdop, altitude, geoidal_height, dgps_data_age, dgps_station_id);
10
+ }
11
+ gga = "$GPGGA," utc_time latitude longitude gps_quality active_satellite_count gsa_hdop altitude geoidal_height dgps_data checksum;
12
+ }%%
@@ -0,0 +1,8 @@
1
+ %%{
2
+ machine NMEA;
3
+ gll_state = 'A' | 'V';
4
+ action read_gll {
5
+ handler.gll(utc, latitude, longitude);
6
+ }
7
+ gll = "$GPGLL," latitude longitude utc_time gll_state checksum;
8
+ }%%
@@ -0,0 +1,14 @@
1
+ %%{
2
+ machine NMEA;
3
+ gsa_mode = ('M' @{gsa_automatic = false;} | 'A' @{gsa_automatic = true; }) comma;
4
+ gsa_mode_detailed = (('1' | '2' | '3' ) @{gsa_mode = GSA_MODE(fc-'0');})comma @{gsa_prn_index = 0;};
5
+ gsa_prn = (integer comma | zlen comma) @{if(current_digit) {gsa_prns[gsa_prn_index] = current_digit;} gsa_prn_index++; current_digit = 0; };
6
+ action read_gsa {
7
+ handler.gsa(gsa_automatic, gsa_mode, gsa_prns, gsa_pdop, gsa_hdop, gsa_vdop);
8
+ gsa_prn_index = 0;
9
+ }
10
+ gsa_pdop = (number comma @{ gsa_pdop = current_float; current_float = 0;}) | comma;
11
+ gsa_hdop = (number comma @{ gsa_hdop = current_float; current_float = 0;}) | comma;
12
+ gsa_vdop = (number @{ gsa_vdop = current_float; current_float = 0;})?;
13
+ gsa = "$GPGSA," gsa_mode gsa_mode_detailed gsa_prn{12} gsa_pdop gsa_hdop gsa_vdop checksum;
14
+ }%%
@@ -0,0 +1,41 @@
1
+ %%{
2
+ machine NMEA;
3
+
4
+ total_gsv_number = integer comma @{total_gsv_number = current_digit; current_digit = 0;};
5
+
6
+ action allocate_gsv {
7
+ current_gsv_number = current_digit;
8
+ current_digit = 0;
9
+ }
10
+ message_number = integer comma @allocate_gsv;
11
+ total_satellites = integer comma @{total_satellites = current_digit; current_digit = 0;};
12
+
13
+
14
+ sv_prn_number = integer comma @{satellite_number = current_digit; current_digit = 0; };
15
+ elevation = integer comma @{elevation = current_digit; current_digit = 0;};
16
+ azimuth = integer comma @{azimuth = current_digit; current_digit = 0; };
17
+ snr_db = bcd? @{snr_db = bcd;};
18
+ action append_gsv {
19
+ SatelliteInfo satellite;
20
+ satellite.number = satellite_number;
21
+ satellite.elevation = elevation;
22
+ satellite.azimuth = azimuth;
23
+ satellite.signal_level = snr_db;
24
+ snr_db.nil = true;
25
+ satellites.push_back(satellite);
26
+ }
27
+ sv_info = sv_prn_number elevation azimuth snr_db;
28
+
29
+ action read_gsv {
30
+ GSV_FLAG flag = GSV_CONTINUE;
31
+ if(current_gsv_number == 1) {
32
+ flag = GSV_START;
33
+ } else if(current_gsv_number == total_gsv_number) {
34
+ flag = GSV_END;
35
+ }
36
+ handler.gsv(flag, satellites);
37
+ satellites.empty();
38
+ }
39
+ gsv = "$GPGSV," total_gsv_number message_number total_satellites (sv_info comma %append_gsv)* (sv_info %append_gsv) checksum;
40
+ }%%
41
+
@@ -0,0 +1,108 @@
1
+ #ifndef _NMEA_H_
2
+ #define _NMEA_H_
3
+
4
+ #include <stdio.h>
5
+ #include <string.h>
6
+ #include <stdlib.h>
7
+ #include <time.h>
8
+ #include <math.h>
9
+ #include <stdarg.h>
10
+ #include <vector>
11
+ #include <string>
12
+ #include <exception>
13
+
14
+
15
+ namespace NMEA {
16
+ class Error {
17
+ public:
18
+ char buf[BUFSIZ];
19
+ Error(const char* msg) {
20
+ strncpy(buf, msg, BUFSIZ);
21
+ }
22
+ };
23
+ class ParseError : public Error {
24
+ public:
25
+ ParseError(const char* msg) : Error(msg) {}
26
+ };
27
+ class DataError : public Error {
28
+ public:
29
+ DataError(const char* msg) : Error(msg) {}
30
+ };
31
+
32
+ template<typename type>
33
+ struct Value {
34
+ type value;
35
+ bool nil;
36
+ Value() {
37
+ nil = true;
38
+ }
39
+ Value<type>& operator=(const type& rhs) {
40
+ nil = false;
41
+ value = rhs;
42
+ return *this;
43
+ }
44
+ Value<type>& operator=(const Value<type>& rhs) {
45
+ nil = rhs.nil;
46
+ if(!nil) {
47
+ value = rhs.value;
48
+ }
49
+ return *this;
50
+ }
51
+ };
52
+
53
+ struct AngleValue {
54
+ int degrees;
55
+ double minutes;
56
+ };
57
+
58
+ struct Time {
59
+ int year;
60
+ int month;
61
+ int day;
62
+ int hour;
63
+ int minute;
64
+ int second;
65
+ int usec;
66
+ Time() { flush(); }
67
+ void flush() { year = month = day = hour = minute = second = usec = 0; }
68
+ };
69
+
70
+ typedef Value<AngleValue> Angle;
71
+ typedef Value<double> Double;
72
+ typedef Value<bool> Bool;
73
+ typedef Value<int> Int;
74
+
75
+ struct SatelliteInfo {
76
+ Int number;
77
+ Int elevation;
78
+ Int azimuth;
79
+ Int signal_level;
80
+ };
81
+
82
+ typedef std::vector<SatelliteInfo> satellite_list;
83
+ typedef Int satellite_numbers[12];
84
+
85
+ enum GSV_FLAG {GSV_START, GSV_CONTINUE, GSV_END};
86
+ enum GSA_MODE {GSA_NO_FIX = 1, GSA_2D, GSA_3D};
87
+ enum GGA_FIX {GGA_INVALID, GGA_GPS, GGA_DGPS, GGA_PPS, GGA_RTK, GGA_FLOATRTK, GGA_ESTIMATED, GGA_MANUAL, GGA_SIMULATION};
88
+ enum VTG_MODE {VTG_DEFAULT, VTG_AUTONOMUS, VTG_DIFFERENTIAL, VTG_ESTIMATED, VTG_INVALID};
89
+
90
+ class Handler {
91
+ public:
92
+ virtual void rmc(Time& time, Angle& latitude, Angle& longitude, Double& speed, Double& course, Double& magnetic_variation) = 0;
93
+ virtual void gsv(GSV_FLAG flag, satellite_list& satellites) = 0;
94
+ virtual void gsa(bool mode_automatic, GSA_MODE mode, satellite_numbers& satellites, Double& pdop, Double& hdop, Double& vdop) = 0;
95
+ virtual void gga(Time& time, Angle& latitude, Angle& longitude,
96
+ GGA_FIX gps_quality, Int& active_satellite_count, Double& hdop,
97
+ Double& altitude, Double& geoidal_height, Double& dgps_data_age, Int& dgps_station_id) = 0;
98
+ virtual void psrftxt(std::string& key, std::string& value) = 0;
99
+ virtual void vtg(Double& true_course, Double& magnetic_course, Double& knot_speed, Double& kmph_speed, VTG_MODE mode) = 0;
100
+ virtual void gll(Time& time, Angle& latitude, Angle& longitude) = 0;
101
+ virtual void bod(Double& true_degrees, Double& magnetic_degrees, std::string& to, std::string& from) = 0;
102
+ virtual ~Handler() {};
103
+ };
104
+
105
+ bool scan(char *p, Handler& handler) throw (Error);
106
+ }
107
+
108
+ #endif /* _NMEA_H_ */
@@ -0,0 +1,155 @@
1
+ #include "nmea.hpp"
2
+ namespace NMEA {
3
+
4
+ %%{
5
+ machine NMEA;
6
+
7
+ newline = ('\r\n' | '\n' | '\r');
8
+ comma = ",";
9
+ nmea_char = [a-zA-Z0-9,_.*$: \t\-];
10
+
11
+ action add_digit {
12
+ current_float = 0;
13
+ current_digit = current_digit*10 + (fc - '0');
14
+ }
15
+ action switch_to_float {
16
+ current_frac = 10;
17
+ current_float = current_digit;
18
+ current_digit = 0;
19
+ }
20
+ action add_digit_after_comma {
21
+ current_float += (fc - '0')*1.0 / current_frac;
22
+ current_frac *= 10;
23
+ }
24
+ bcd = digit @{bcd = 10*(fc - '0');} digit @{bcd += fc - '0';};
25
+ b3cd = bcd digit @{bcd = bcd*10 + (fc - '0');};
26
+ b4cd = b3cd digit @{bcd = bcd*10 + (fc - '0');};
27
+ integer = (digit @add_digit)+ ;
28
+ number = ('-' %{sign = -1;}|zlen) integer ("." @switch_to_float) (digit @add_digit_after_comma)+ %{current_float = current_float*sign; sign = 1;};
29
+ action add_char {
30
+ *current_s = fc;
31
+ current_s++;
32
+ *current_s = 0;
33
+ }
34
+ string = space* <: (nmea_char @add_char)*;
35
+ key_string = space* <: ((nmea_char - [:]) @add_char)+;
36
+
37
+ utc_time = bcd @{ utc.hour = bcd; } bcd @{ utc.minute = bcd;} bcd @{ utc.second = bcd;} ("." integer %{ utc.usec = current_digit; current_digit = 0;})? comma;
38
+ utc_date = bcd @{ utc.day = bcd; } bcd @{ utc.month = bcd;} bcd @{ utc.year = bcd > 70 ? 1900+bcd : 2000+bcd;};
39
+
40
+ action set_degrees {
41
+ current_degrees = bcd;
42
+ bcd = 0;
43
+ }
44
+
45
+ northing = "N" | "S" @{current_degrees *= -1;};
46
+ action set_latitude {
47
+ latitude.nil = false;
48
+ latitude.value.degrees = current_degrees;
49
+ latitude.value.minutes = current_float;
50
+ current_float = 0;
51
+ current_degrees = 0;
52
+ }
53
+ latitude = (bcd @set_degrees number comma northing @set_latitude | comma) comma;
54
+
55
+ easting = "E" | "W" @{current_degrees *= -1;};
56
+ action set_longitude {
57
+ longitude.nil = false;
58
+ longitude.value.degrees = current_degrees;
59
+ longitude.value.minutes = current_float;
60
+ current_degrees = 0;
61
+ current_float = 0;
62
+ }
63
+ longitude = (b3cd @set_degrees number comma easting @set_longitude| comma) comma;
64
+
65
+ action sentence_begin {
66
+ sentence_begin = p+1;
67
+ }
68
+ action check_sum {
69
+ checksum[1] = fc;
70
+ unsigned char sum = 0, *ptr;
71
+ for(ptr = (unsigned char *)sentence_begin; ptr != (unsigned char*)sentence_end; ptr++) {
72
+ sum ^= *ptr;
73
+ }
74
+ unsigned int sum_provided;
75
+ sscanf(checksum, "%x", &sum_provided);
76
+ if(sum_provided != sum) {
77
+ char buf[BUFSIZ];
78
+ snprintf(buf, BUFSIZ, "Checksum didn't match: provided is %d, calculated is %d", sum_provided, sum);
79
+ throw DataError(buf);
80
+ }
81
+ }
82
+ checksum = '*' @{sentence_end = p; } alnum @{checksum[0] = fc;} alnum @check_sum;
83
+
84
+ include "rmc.rl";
85
+ include "gsv.rl";
86
+ include "gsa.rl";
87
+ include "gga.rl";
88
+ include "psrftxt.rl";
89
+ include "vtg.rl";
90
+ include "gll.rl";
91
+ include "bod.rl";
92
+
93
+ sentence = zlen %sentence_begin rmc %read_rmc | gsv %read_gsv | gsa %read_gsa | gga %read_gga | psrftxt %read_psrftxt | vtg %read_vtg | gll %read_gll | bod %read_bod;
94
+ // | zda %read_zda;
95
+ main := sentence newline;
96
+ }%%
97
+
98
+
99
+ %% write data nofinal;
100
+
101
+ bool scan(char *p, Handler& handler) throw (Error) {
102
+ char *pe;
103
+ int cs;
104
+
105
+ int sign = 1;
106
+ int current_digit = 0, current_frac = 0;
107
+ double current_float = 0;
108
+ int current_degrees = 0;
109
+ int bcd = 0;
110
+ Time utc;
111
+ Angle latitude, longitude;
112
+
113
+ char checksum[3];
114
+ checksum[2] = 0;
115
+ int sentence_len = strlen(p);
116
+ char current_string[sentence_len+1];
117
+ char *current_s = current_string;
118
+ char *sentence_begin = NULL, *sentence_end = NULL;
119
+
120
+ //RMC
121
+ bool rmc_valid = 0;
122
+ Double knot_speed, course, magnetic_variation;
123
+ //GSV
124
+ satellite_list satellites;
125
+ Int snr_db;
126
+ int total_gsv_number = 0, current_gsv_number = 0, total_satellites = 0, satellite_number = 0, elevation = 0, azimuth = 0;
127
+ //GSA
128
+ bool gsa_automatic;
129
+ GSA_MODE gsa_mode;
130
+ int gsa_prn_index = 0;
131
+ Double gsa_pdop, gsa_hdop, gsa_vdop;
132
+ satellite_numbers gsa_prns;
133
+ //GGA
134
+ GGA_FIX gps_quality;
135
+ Int dgps_station_id, active_satellite_count;
136
+ Double altitude, geoidal_height, dgps_data_age;
137
+ char altitude_units, geoidal_height_units;
138
+ //PSRFTXT
139
+ std::string psrf_key, psrf_value;
140
+ //VTG
141
+ Double true_course, magnetic_course, vtg_knot_speed, vtg_kmph_speed;
142
+ VTG_MODE vtg_mode = VTG_DEFAULT;
143
+ //BOD
144
+ std::string wpt_to, wpt_from;
145
+ %% write init;
146
+
147
+ pe = p + sentence_len;
148
+ %% write exec;
149
+ if(cs == NMEA_error) {
150
+ return false;
151
+ }
152
+ return true;
153
+ }
154
+ }
155
+
@@ -0,0 +1,18 @@
1
+ %%{
2
+ machine NMEA;
3
+ action add_key {
4
+ psrf_key = current_string;
5
+ current_s = current_string;
6
+ *current_s = 0;
7
+ }
8
+ psrf_key = key_string;
9
+ action add_value {
10
+ psrf_value = current_string;
11
+ current_s = current_string;
12
+ *current_s = 0;
13
+ }
14
+ action read_psrftxt {
15
+ handler.psrftxt(psrf_key, psrf_value);
16
+ }
17
+ psrftxt = "$PSRFTXT," ((psrf_key %add_key ':' string %add_value )| psrf_key %add_key);
18
+ }%%
@@ -0,0 +1,16 @@
1
+ %%{
2
+ machine NMEA;
3
+
4
+
5
+ rmc_state = ("A" @{rmc_valid = true;} | "V" @{rmc_valid = false;}) comma;
6
+ knot_speed = (number comma @{knot_speed = current_float; current_float = 0;}) | (zlen comma);
7
+ course = (number comma @{course = current_float; current_float = 0;}) | (zlen comma);
8
+ magnetic_variation = (integer comma easting %{ magnetic_variation = 1.0*current_digit; current_digit = 0; }) | (number %{current_degrees = 1;} comma easting %{ magnetic_variation = current_float*current_degrees; current_float = 0; }) | comma;
9
+
10
+ action read_rmc {
11
+ handler.rmc(utc, latitude, longitude, knot_speed, course, magnetic_variation);
12
+ }
13
+
14
+ rmc = "$GPRMC," utc_time rmc_state latitude longitude knot_speed course utc_date comma magnetic_variation any*;
15
+
16
+ }%%
@@ -0,0 +1,12 @@
1
+ %%{
2
+ machine NMEA;
3
+ true_course = (number %{true_course = current_float; current_float = 0;})? comma 'T' comma;
4
+ magnetic_course = (number %{magnetic_course = current_float; current_float = 0;})? comma 'M' comma;
5
+ vtg_knot_speed = (number %{vtg_knot_speed = current_float; current_float = 0;})? comma 'N' comma;
6
+ vtg_kmph_speed = (number %{vtg_kmph_speed = current_float; current_float = 0;})? comma 'K';
7
+ vtg_mode = (comma ('A' @{vtg_mode = VTG_AUTONOMUS;}| 'D' @{vtg_mode = VTG_DIFFERENTIAL;} | 'E' @{vtg_mode = VTG_ESTIMATED;} | 'N' @{vtg_mode = VTG_INVALID;}))?;
8
+ action read_vtg {
9
+ handler.vtg(true_course, magnetic_course, vtg_knot_speed, vtg_kmph_speed, vtg_mode);
10
+ }
11
+ vtg = "$GPVTG," true_course magnetic_course vtg_knot_speed vtg_kmph_speed vtg_mode checksum;
12
+ }%%
@@ -0,0 +1,7 @@
1
+ %%{
2
+ machine NMEA;
3
+ action read_zda {
4
+ handler.zda(utc_time, zda_day, zda_month, zda_year, local_time);
5
+ }
6
+ gsa = "$GPZDA," utc_time zda_day zda_month zda_year local_time;
7
+ }%%
@@ -0,0 +1,13 @@
1
+ require 'mkmf'
2
+
3
+ printf("checking for OS... ")
4
+ STDOUT.flush
5
+ os = /-([a-z]+)/.match(RUBY_PLATFORM)[1]
6
+ puts(os)
7
+ $CFLAGS += " -D#{os}"
8
+
9
+ if !(os == 'mswin' or os == 'bccwin')
10
+ exit(1) if not have_header("termios.h") or not have_header("unistd.h")
11
+ end
12
+
13
+ create_makefile("serialport")
@@ -0,0 +1,1319 @@
1
+ /* Ruby/SerialPort $Id: serialport.c,v 1.15 2003/02/13 19:55:48 moumar Exp $
2
+ * Guillaume Pierronnet <moumar@netcourrier.com>
3
+ * Alan Stern <stern@rowland.harvard.edu>
4
+ *
5
+ * This code is hereby licensed for public consumption under either the
6
+ * GNU GPL v2 or greater.
7
+ *
8
+ * You should have received a copy of the GNU General Public License
9
+ * along with this program; if not, write to the Free Software
10
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
11
+ *
12
+ * For documentation on serial programming, see the excellent:
13
+ * "Serial Programming Guide for POSIX Operating Systems"
14
+ * written Michael R. Sweet.
15
+ * http://www.easysw.com/~mike/serial/
16
+ */
17
+
18
+ #define VERSION "0.6"
19
+
20
+ #include <ruby.h> /* ruby inclusion */
21
+ #include <rubyio.h> /* ruby io inclusion */
22
+
23
+ struct modem_params {
24
+ int data_rate;
25
+ int data_bits;
26
+ int stop_bits;
27
+ int parity;
28
+ };
29
+
30
+ struct line_signals {
31
+ int rts;
32
+ int dtr;
33
+ int cts;
34
+ int dsr;
35
+ int dcd;
36
+ int ri;
37
+ };
38
+
39
+ VALUE cSerialPort; /* serial port class */
40
+
41
+ static VALUE sBaud, sDataBits, sStopBits, sParity; /* strings */
42
+ static VALUE sRts, sDtr, sCts, sDsr, sDcd, sRi;
43
+
44
+
45
+ #if defined(mswin) || defined(bccwin)
46
+
47
+
48
+ #include <stdio.h> /* Standard input/output definitions */
49
+ #include <io.h> /* Low-level I/O definitions */
50
+ #include <fcntl.h> /* File control definitions */
51
+ #include <windows.h> /* Windows standard function definitions */
52
+
53
+ #define NONE 0
54
+ #define HARD 1
55
+ #define SOFT 2
56
+
57
+ #define SPACE SPACEPARITY
58
+ #define MARK MARKPARITY
59
+ #define EVEN EVENPARITY
60
+ #define ODD ODDPARITY
61
+
62
+ static char sGetCommState[] = "GetCommState";
63
+ static char sSetCommState[] = "SetCommState";
64
+ static char sGetCommTimeouts[] = "GetCommTimeouts";
65
+ static char sSetCommTimeouts[] = "SetCommTimeouts";
66
+
67
+
68
+ static HANDLE sp_get_handle(obj)
69
+ VALUE obj;
70
+ {
71
+ OpenFile *fptr;
72
+
73
+ GetOpenFile(obj, fptr);
74
+ return (HANDLE) _get_osfhandle(fileno(fptr->f));
75
+ }
76
+
77
+ static VALUE sp_create(class, _port)
78
+ VALUE class, _port;
79
+ {
80
+ OpenFile *fp;
81
+ int fd;
82
+ HANDLE fh;
83
+ int num_port;
84
+ char *port;
85
+ char *ports[] = {
86
+ "COM1", "COM2", "COM3", "COM4",
87
+ "COM5", "COM6", "COM7", "COM8"
88
+ };
89
+ DCB dcb;
90
+
91
+ NEWOBJ(sp, struct RFile);
92
+ rb_secure(4);
93
+ OBJSETUP(sp, class, T_FILE);
94
+ MakeOpenFile(sp, fp);
95
+
96
+ switch(TYPE(_port)) {
97
+ case T_FIXNUM:
98
+ num_port = FIX2INT(_port);
99
+ if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))
100
+ rb_raise(rb_eArgError, "illegal port number");
101
+ port = ports[num_port];
102
+ break;
103
+
104
+ case T_STRING:
105
+ Check_SafeStr(_port);
106
+ port = RSTRING(_port)->ptr;
107
+ break;
108
+
109
+ default:
110
+ rb_raise(rb_eTypeError, "wrong argument type");
111
+ break;
112
+ }
113
+
114
+ fd = open(port, O_BINARY | O_RDWR);
115
+ if (fd == -1)
116
+ rb_sys_fail(port);
117
+ fh = (HANDLE) _get_osfhandle(fd);
118
+ if (SetupComm(fh, 1024, 1024) == 0) {
119
+ close(fd);
120
+ rb_raise(rb_eArgError, "not a serial port");
121
+ }
122
+
123
+ dcb.DCBlength = sizeof(dcb);
124
+ if (GetCommState(fh, &dcb) == 0) {
125
+ close(fd);
126
+ rb_sys_fail(sGetCommState);
127
+ }
128
+ dcb.fBinary = TRUE;
129
+ dcb.fParity = FALSE;
130
+ dcb.fOutxDsrFlow = FALSE;
131
+ dcb.fDtrControl = DTR_CONTROL_ENABLE;
132
+ dcb.fDsrSensitivity = FALSE;
133
+ dcb.fTXContinueOnXoff = FALSE;
134
+ dcb.fErrorChar = FALSE;
135
+ dcb.fNull = FALSE;
136
+ dcb.fAbortOnError = FALSE;
137
+ dcb.XonChar = 17;
138
+ dcb.XoffChar = 19;
139
+ if (SetCommState(fh, &dcb) == 0) {
140
+ close(fd);
141
+ rb_sys_fail(sSetCommState);
142
+ }
143
+
144
+ fp->f = rb_fdopen(fd, "rb+");
145
+ fp->mode = FMODE_READWRITE | FMODE_BINMODE | FMODE_SYNC;
146
+ return (VALUE) sp;
147
+ }
148
+
149
+ static VALUE sp_set_modem_params(argc, argv, self)
150
+ int argc;
151
+ VALUE *argv, self;
152
+ {
153
+ HANDLE fh;
154
+ DCB dcb;
155
+ VALUE _data_rate, _data_bits, _parity, _stop_bits;
156
+ int use_hash = 0;
157
+ int data_rate, data_bits, parity;
158
+
159
+ if (argc == 0)
160
+ return self;
161
+ if (argc == 1 && T_HASH == TYPE(argv[0])) {
162
+ use_hash = 1;
163
+ _data_rate = rb_hash_aref(argv[0], sBaud);
164
+ _data_bits = rb_hash_aref(argv[0], sDataBits);
165
+ _stop_bits = rb_hash_aref(argv[0], sStopBits);
166
+ _parity = rb_hash_aref(argv[0], sParity);
167
+ }
168
+
169
+ fh = sp_get_handle(self);
170
+ dcb.DCBlength = sizeof(dcb);
171
+ if (GetCommState(fh, &dcb) == 0)
172
+ rb_sys_fail(sGetCommState);
173
+
174
+ if (!use_hash)
175
+ _data_rate = argv[0];
176
+ if (NIL_P(_data_rate))
177
+ goto SkipDataRate;
178
+ Check_Type(_data_rate, T_FIXNUM);
179
+
180
+ data_rate = FIX2INT(_data_rate);
181
+ switch (data_rate) {
182
+ case 110:
183
+ case 300:
184
+ case 600:
185
+ case 1200:
186
+ case 2400:
187
+ case 4800:
188
+ case 9600:
189
+ case 14400:
190
+ case 19200:
191
+ case 38400:
192
+ case 56000:
193
+ case 57600:
194
+ case 115200:
195
+ case 128000:
196
+ case 256000:
197
+ dcb.BaudRate = data_rate;
198
+ break;
199
+
200
+ default:
201
+ rb_raise(rb_eArgError, "unknown baud rate");
202
+ break;
203
+ }
204
+ SkipDataRate:
205
+
206
+ if (!use_hash)
207
+ _data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
208
+ if (NIL_P(_data_bits))
209
+ goto SkipDataBits;
210
+ Check_Type(_data_bits, T_FIXNUM);
211
+
212
+ data_bits = FIX2INT(_data_bits);
213
+ if (4 <= data_bits && data_bits <= 8)
214
+ dcb.ByteSize = data_bits;
215
+ else
216
+ rb_raise(rb_eArgError, "unknown character size");
217
+ SkipDataBits:
218
+
219
+ if (!use_hash)
220
+ _stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
221
+ if (NIL_P(_stop_bits))
222
+ goto SkipStopBits;
223
+ Check_Type(_stop_bits, T_FIXNUM);
224
+
225
+ switch (FIX2INT(_stop_bits)) {
226
+ case 1:
227
+ dcb.StopBits = ONESTOPBIT;
228
+ break;
229
+ case 2:
230
+ dcb.StopBits = TWOSTOPBITS;
231
+ break;
232
+ default:
233
+ rb_raise(rb_eArgError, "unknown number of stop bits");
234
+ break;
235
+ }
236
+ SkipStopBits:
237
+
238
+ if (!use_hash)
239
+ _parity = (argc >= 4 ? argv[3] : (dcb.ByteSize == 8 ?
240
+ INT2FIX(NOPARITY) : INT2FIX(EVENPARITY)));
241
+ if (NIL_P(_parity))
242
+ goto SkipParity;
243
+ Check_Type(_parity, T_FIXNUM);
244
+
245
+ parity = FIX2INT(_parity);
246
+ switch (parity) {
247
+ case EVENPARITY:
248
+ case ODDPARITY:
249
+ case MARKPARITY:
250
+ case SPACEPARITY:
251
+ case NOPARITY:
252
+ dcb.Parity = parity;
253
+ break;
254
+
255
+ default:
256
+ rb_raise(rb_eArgError, "unknown parity");
257
+ break;
258
+ }
259
+ SkipParity:
260
+
261
+ if (SetCommState(fh, &dcb) == 0)
262
+ rb_sys_fail(sSetCommState);
263
+ return self;
264
+ }
265
+
266
+ static void get_modem_params(self, mp)
267
+ VALUE self;
268
+ struct modem_params *mp;
269
+ {
270
+ HANDLE fh;
271
+ DCB dcb;
272
+
273
+ fh = sp_get_handle(self);
274
+ dcb.DCBlength = sizeof(dcb);
275
+ if (GetCommState(fh, &dcb) == 0)
276
+ rb_sys_fail(sGetCommState);
277
+
278
+ mp->data_rate = dcb.BaudRate;
279
+ mp->data_bits = dcb.ByteSize;
280
+ mp->stop_bits = (dcb.StopBits == ONESTOPBIT ? 1 : 2);
281
+ mp->parity = dcb.Parity;
282
+ }
283
+
284
+ static VALUE sp_set_flow_control(self, val)
285
+ VALUE self, val;
286
+ {
287
+ HANDLE fh;
288
+ int flowc;
289
+ DCB dcb;
290
+
291
+ Check_Type(val, T_FIXNUM);
292
+
293
+ fh = sp_get_handle(self);
294
+ dcb.DCBlength = sizeof(dcb);
295
+ if (GetCommState(fh, &dcb) == 0)
296
+ rb_sys_fail(sGetCommState);
297
+
298
+ flowc = FIX2INT(val);
299
+ if (flowc & HARD) {
300
+ dcb.fRtsControl = RTS_CONTROL_HANDSHAKE;
301
+ dcb.fOutxCtsFlow = TRUE;
302
+ } else {
303
+ dcb.fRtsControl = RTS_CONTROL_ENABLE;
304
+ dcb.fOutxCtsFlow = FALSE;
305
+ }
306
+ if (flowc & SOFT)
307
+ dcb.fOutX = dcb.fInX = TRUE;
308
+ else
309
+ dcb.fOutX = dcb.fInX = FALSE;
310
+
311
+ if (SetCommState(fh, &dcb) == 0)
312
+ rb_sys_fail(sSetCommState);
313
+ return self;
314
+ }
315
+
316
+ static VALUE sp_get_flow_control(self)
317
+ VALUE self;
318
+ {
319
+ HANDLE fh;
320
+ int ret;
321
+ DCB dcb;
322
+
323
+ fh = sp_get_handle(self);
324
+ dcb.DCBlength = sizeof(dcb);
325
+ if (GetCommState(fh, &dcb) == 0)
326
+ rb_sys_fail(sGetCommState);
327
+
328
+ ret = 0;
329
+ if (dcb.fOutxCtsFlow)
330
+ ret += HARD;
331
+ if (dcb.fOutX)
332
+ ret += SOFT;
333
+
334
+ return INT2FIX(ret);
335
+ }
336
+
337
+ static VALUE sp_set_read_timeout(self, val)
338
+ VALUE self, val;
339
+ {
340
+ int timeout;
341
+ HANDLE fh;
342
+ COMMTIMEOUTS ctout;
343
+
344
+ Check_Type(val, T_FIXNUM);
345
+ timeout = FIX2INT(val);
346
+
347
+ fh = sp_get_handle(self);
348
+ if (GetCommTimeouts(fh, &ctout) == 0)
349
+ rb_sys_fail(sGetCommTimeouts);
350
+
351
+ if (timeout < 0) {
352
+ ctout.ReadIntervalTimeout = MAXDWORD;
353
+ ctout.ReadTotalTimeoutMultiplier = 0;
354
+ ctout.ReadTotalTimeoutConstant = 0;
355
+ } else if (timeout == 0) {
356
+ ctout.ReadIntervalTimeout = MAXDWORD;
357
+ ctout.ReadTotalTimeoutMultiplier = MAXDWORD;
358
+ ctout.ReadTotalTimeoutConstant = MAXDWORD - 1;
359
+ } else {
360
+ ctout.ReadIntervalTimeout = timeout;
361
+ ctout.ReadTotalTimeoutMultiplier = 0;
362
+ ctout.ReadTotalTimeoutConstant = timeout;
363
+ }
364
+
365
+ if (SetCommTimeouts(fh, &ctout) == 0)
366
+ rb_sys_fail(sSetCommTimeouts);
367
+ return self;
368
+ }
369
+
370
+ static VALUE sp_get_read_timeout(self)
371
+ VALUE self;
372
+ {
373
+ HANDLE fh;
374
+ COMMTIMEOUTS ctout;
375
+
376
+ fh = sp_get_handle(self);
377
+ if (GetCommTimeouts(fh, &ctout) == 0)
378
+ rb_sys_fail(sGetCommTimeouts);
379
+ switch (ctout.ReadTotalTimeoutConstant) {
380
+ case 0:
381
+ return INT2FIX(-1);
382
+ case MAXDWORD:
383
+ return INT2FIX(0);
384
+ }
385
+ return INT2FIX(ctout.ReadTotalTimeoutConstant);
386
+ }
387
+
388
+ static VALUE sp_set_write_timeout(self, val)
389
+ VALUE self, val;
390
+ {
391
+ int timeout;
392
+ HANDLE fh;
393
+ COMMTIMEOUTS ctout;
394
+
395
+ Check_Type(val, T_FIXNUM);
396
+ timeout = FIX2INT(val);
397
+
398
+ fh = sp_get_handle(self);
399
+ if (GetCommTimeouts(fh, &ctout) == 0)
400
+ rb_sys_fail(sGetCommTimeouts);
401
+
402
+ if (timeout <= 0) {
403
+ ctout.WriteTotalTimeoutMultiplier = 0;
404
+ ctout.WriteTotalTimeoutConstant = 0;
405
+ } else {
406
+ ctout.WriteTotalTimeoutMultiplier = timeout;
407
+ ctout.WriteTotalTimeoutConstant = 0;
408
+ }
409
+
410
+ if (SetCommTimeouts(fh, &ctout) == 0)
411
+ rb_sys_fail(sSetCommTimeouts);
412
+ return self;
413
+ }
414
+
415
+ static VALUE sp_get_write_timeout(self)
416
+ VALUE self;
417
+ {
418
+ HANDLE fh;
419
+ COMMTIMEOUTS ctout;
420
+
421
+ fh = sp_get_handle(self);
422
+ if (GetCommTimeouts(fh, &ctout) == 0)
423
+ rb_sys_fail(sGetCommTimeouts);
424
+ return INT2FIX(ctout.WriteTotalTimeoutMultiplier);
425
+ }
426
+
427
+ static void delay_ms(time)
428
+ int time;
429
+ {
430
+ HANDLE ev;
431
+
432
+ ev = CreateEvent(NULL, FALSE, FALSE, NULL);
433
+ if (!ev)
434
+ rb_sys_fail("CreateEvent");
435
+ if (WaitForSingleObject(ev, time) == WAIT_FAILED)
436
+ rb_sys_fail("WaitForSingleObject");
437
+ CloseHandle(ev);
438
+ }
439
+
440
+ static VALUE sp_break(self, time)
441
+ VALUE self, time;
442
+ {
443
+ HANDLE fh;
444
+
445
+ Check_Type(time, T_FIXNUM);
446
+
447
+ fh = sp_get_handle(self);
448
+ if (SetCommBreak(fh) == 0)
449
+ rb_sys_fail("SetCommBreak");
450
+ delay_ms(FIX2INT(time) * 100);
451
+ ClearCommBreak(fh);
452
+ return Qnil;
453
+ }
454
+
455
+ static void get_line_signals(obj, ls)
456
+ VALUE obj;
457
+ struct line_signals *ls;
458
+ {
459
+ HANDLE fh;
460
+ int status;
461
+
462
+ fh = sp_get_handle(obj);
463
+ if (GetCommModemStatus(fh, &status) == 0)
464
+ rb_sys_fail("GetCommModemStatus");
465
+
466
+ ls->cts = (status & MS_CTS_ON ? 1 : 0);
467
+ ls->dsr = (status & MS_DSR_ON ? 1 : 0);
468
+ ls->dcd = (status & MS_RLSD_ON ? 1 : 0);
469
+ ls->ri = (status & MS_RING_ON ? 1 : 0);
470
+ }
471
+
472
+ static VALUE set_signal(obj, val, sigoff, sigon)
473
+ VALUE obj,val;
474
+ int sigoff, sigon;
475
+ {
476
+ HANDLE fh;
477
+ int set, sig;
478
+
479
+ Check_Type(val, T_FIXNUM);
480
+ fh = sp_get_handle(obj);
481
+
482
+ set = FIX2INT(val);
483
+ if (set == 0)
484
+ sig = sigoff;
485
+ else if (set == 1)
486
+ sig = sigon;
487
+ else
488
+ rb_raise(rb_eArgError, "invalid value");
489
+
490
+ if (EscapeCommFunction(fh, sig) == 0)
491
+ rb_sys_fail("EscapeCommFunction");
492
+ return obj;
493
+ }
494
+
495
+ static VALUE sp_set_rts(self, val)
496
+ VALUE self, val;
497
+ {
498
+ return set_signal(self, val, CLRRTS, SETRTS);
499
+ }
500
+
501
+ static VALUE sp_set_dtr(self, val)
502
+ VALUE self, val;
503
+ {
504
+ return set_signal(self, val, CLRDTR, SETDTR);
505
+ }
506
+
507
+ static VALUE sp_get_rts(self)
508
+ VALUE self;
509
+ {
510
+ rb_notimplement();
511
+ return self;
512
+ }
513
+
514
+ static VALUE sp_get_dtr(self)
515
+ VALUE self;
516
+ {
517
+ rb_notimplement();
518
+ return self;
519
+ }
520
+
521
+
522
+ #else /* defined(mswin) || defined(bccwin) */
523
+
524
+
525
+ #include <stdio.h> /* Standard input/output definitions */
526
+ #include <unistd.h> /* UNIX standard function definitions */
527
+ #include <fcntl.h> /* File control definitions */
528
+ #include <errno.h> /* Error number definitions */
529
+ #include <termios.h> /* POSIX terminal control definitions */
530
+ #include <sys/ioctl.h>
531
+
532
+ #ifdef CRTSCTS
533
+ #define HAVE_FLOWCONTROL_HARD 1
534
+ #else
535
+ #undef HAVE_FLOWCONTROL_HARD
536
+ #endif
537
+
538
+ #define NONE 0
539
+ #define HARD 1
540
+ #define SOFT 2
541
+
542
+ #define SPACE 0
543
+ #define MARK 0
544
+ #define EVEN 1
545
+ #define ODD 2
546
+
547
+ static char sTcgetattr[] = "tcgetattr";
548
+ static char sTcsetattr[] = "tcsetattr";
549
+ static char sIoctl[] = "ioctl";
550
+
551
+
552
+ static int sp_get_fd(obj)
553
+ VALUE obj;
554
+ {
555
+ OpenFile *fptr;
556
+
557
+ GetOpenFile(obj, fptr);
558
+ return (fileno(fptr->f));
559
+ }
560
+
561
+ static VALUE sp_create(class, _port)
562
+ VALUE class, _port;
563
+ {
564
+ OpenFile *fp;
565
+ int fd;
566
+ int num_port;
567
+ char *port;
568
+ char *ports[] = {
569
+ #if defined(linux) || defined(cygwin)
570
+ "/dev/ttyS0", "/dev/ttyS1", "/dev/ttyS2", "/dev/ttyS3",
571
+ "/dev/ttyS4", "/dev/ttyS5", "/dev/ttyS6", "/dev/ttyS7"
572
+ #elif defined(freebsd) || defined(netbsd) || defined(openbsd)
573
+ "/dev/cuaa0", "/dev/cuaa1", "/dev/cuaa2", "/dev/cuaa3",
574
+ "/dev/cuaa4", "/dev/cuaa5", "/dev/cuaa6", "/dev/cuaa7"
575
+ #elif defined(solaris)
576
+ "/dev/ttya", "/dev/ttyb", "/dev/ttyc", "/dev/ttyd",
577
+ "/dev/ttye", "/dev/ttyf", "/dev/ttyg", "/dev/ttyh"
578
+ #elif defined(aix)
579
+ "/dev/tty0", "/dev/tty1", "/dev/tty2", "/dev/tty3",
580
+ "/dev/tty4", "/dev/tty5", "/dev/tty6", "/dev/tty7"
581
+ #elif defined(irix)
582
+ "/dev/ttyf1", "/dev/ttyf2", "/dev/ttyf3", "/dev/ttyf4",
583
+ "/dev/ttyf5", "/dev/ttyf6", "/dev/ttyf7", "/dev/ttyf8"
584
+ #endif
585
+ };
586
+ struct termios params;
587
+
588
+ NEWOBJ(sp, struct RFile);
589
+ rb_secure(4);
590
+ OBJSETUP(sp, class, T_FILE);
591
+ MakeOpenFile(sp, fp);
592
+
593
+ switch(TYPE(_port)) {
594
+ case T_FIXNUM:
595
+ num_port = FIX2INT(_port);
596
+ if (num_port < 0 || num_port > sizeof(ports) / sizeof(ports[0]))
597
+ rb_raise(rb_eArgError, "illegal port number");
598
+ port = ports[num_port];
599
+ break;
600
+
601
+ case T_STRING:
602
+ Check_SafeStr(_port);
603
+ port = RSTRING(_port)->ptr;
604
+ break;
605
+
606
+ default:
607
+ rb_raise(rb_eTypeError, "wrong argument type");
608
+ break;
609
+ }
610
+
611
+ fd = open(port, O_RDWR | O_NOCTTY | O_NDELAY);
612
+ if (fd == -1)
613
+ rb_sys_fail(port);
614
+ if (!isatty(fd)) {
615
+ close(fd);
616
+ rb_raise(rb_eArgError, "not a serial port");
617
+ }
618
+
619
+ /* enable blocking read */
620
+ fcntl(fd, F_SETFL, fcntl(fd, F_GETFL, 0) & ~O_NONBLOCK);
621
+
622
+ if (tcgetattr(fd, &params) == -1) {
623
+ close(fd);
624
+ rb_sys_fail(sTcgetattr);
625
+ }
626
+ params.c_oflag = 0;
627
+ params.c_lflag = 0;
628
+ params.c_iflag &= (IXON | IXOFF | IXANY);
629
+ params.c_cflag |= CLOCAL | CREAD;
630
+ params.c_cflag &= ~HUPCL;
631
+ if (tcsetattr(fd, TCSANOW, &params) == -1) {
632
+ close(fd);
633
+ rb_sys_fail(sTcsetattr);
634
+ }
635
+
636
+ fp->f = rb_fdopen(fd, "r+");
637
+ fp->mode = FMODE_READWRITE | FMODE_SYNC;
638
+ return (VALUE) sp;
639
+ }
640
+
641
+ static VALUE sp_set_modem_params(argc, argv, self)
642
+ int argc;
643
+ VALUE *argv, self;
644
+ {
645
+ int fd;
646
+ struct termios params;
647
+ VALUE _data_rate, _data_bits, _parity, _stop_bits;
648
+ int use_hash = 0;
649
+ int data_rate, data_bits;
650
+
651
+ if (argc == 0)
652
+ return self;
653
+ if (argc == 1 && T_HASH == TYPE(argv[0])) {
654
+ use_hash = 1;
655
+ _data_rate = rb_hash_aref(argv[0], sBaud);
656
+ _data_bits = rb_hash_aref(argv[0], sDataBits);
657
+ _stop_bits = rb_hash_aref(argv[0], sStopBits);
658
+ _parity = rb_hash_aref(argv[0], sParity);
659
+ }
660
+
661
+ fd = sp_get_fd(self);
662
+ if (tcgetattr(fd, &params) == -1)
663
+ rb_sys_fail(sTcgetattr);
664
+
665
+ if (!use_hash)
666
+ _data_rate = argv[0];
667
+ if (NIL_P(_data_rate))
668
+ goto SkipDataRate;
669
+ Check_Type(_data_rate, T_FIXNUM);
670
+
671
+ switch(FIX2INT(_data_rate)) {
672
+ case 50: data_rate = B50; break;
673
+ case 75: data_rate = B75; break;
674
+ case 110: data_rate = B110; break;
675
+ case 134: data_rate = B134; break;
676
+ case 150: data_rate = B150; break;
677
+ case 200: data_rate = B200; break;
678
+ case 300: data_rate = B300; break;
679
+ case 600: data_rate = B600; break;
680
+ case 1200: data_rate = B1200; break;
681
+ case 1800: data_rate = B1800; break;
682
+ case 2400: data_rate = B2400; break;
683
+ case 4800: data_rate = B4800; break;
684
+ case 9600: data_rate = B9600; break;
685
+ case 19200: data_rate = B19200; break;
686
+ case 38400: data_rate = B38400; break;
687
+ #ifdef B57600
688
+ case 57600: data_rate = B57600; break;
689
+ #endif
690
+ #ifdef B76800
691
+ case 76800: data_rate = B76800; break;
692
+ #endif
693
+ #ifdef B115200
694
+ case 115200: data_rate = B115200; break;
695
+ #endif
696
+ #ifdef B230400
697
+ case 230400: data_rate = B230400; break;
698
+ #endif
699
+
700
+ default:
701
+ rb_raise(rb_eArgError, "unknown baud rate");
702
+ break;
703
+ }
704
+ cfsetispeed(&params, data_rate);
705
+ cfsetospeed(&params, data_rate);
706
+ SkipDataRate:
707
+
708
+ if (!use_hash)
709
+ _data_bits = (argc >= 2 ? argv[1] : INT2FIX(8));
710
+ if (NIL_P(_data_bits))
711
+ goto SkipDataBits;
712
+ Check_Type(_data_bits, T_FIXNUM);
713
+
714
+ switch(FIX2INT(_data_bits)) {
715
+ case 5:
716
+ data_bits = CS5;
717
+ break;
718
+ case 6:
719
+ data_bits = CS6;
720
+ break;
721
+ case 7:
722
+ data_bits = CS7;
723
+ break;
724
+ case 8:
725
+ data_bits = CS8;
726
+ break;
727
+ default:
728
+ rb_raise(rb_eArgError, "unknown character size");
729
+ break;
730
+ }
731
+ params.c_cflag &= ~CSIZE;
732
+ params.c_cflag |= data_bits;
733
+ SkipDataBits:
734
+
735
+ if (!use_hash)
736
+ _stop_bits = (argc >= 3 ? argv[2] : INT2FIX(1));
737
+ if (NIL_P(_stop_bits))
738
+ goto SkipStopBits;
739
+ Check_Type(_stop_bits, T_FIXNUM);
740
+
741
+ switch(FIX2INT(_stop_bits)) {
742
+ case 1:
743
+ params.c_cflag &= ~CSTOPB;
744
+ break;
745
+ case 2:
746
+ params.c_cflag |= CSTOPB;
747
+ break;
748
+ default:
749
+ rb_raise(rb_eArgError, "unknown number of stop bits");
750
+ break;
751
+ }
752
+ SkipStopBits:
753
+
754
+ if (!use_hash)
755
+ _parity = (argc >= 4 ? argv[3] : ((params.c_cflag & CSIZE) == CS8 ?
756
+ INT2FIX(NONE) : INT2FIX(EVEN)));
757
+ if (NIL_P(_parity))
758
+ goto SkipParity;
759
+ Check_Type(_parity, T_FIXNUM);
760
+
761
+ switch(FIX2INT(_parity)) {
762
+ case EVEN:
763
+ params.c_cflag |= PARENB;
764
+ params.c_cflag &= ~PARODD;
765
+ break;
766
+
767
+ case ODD:
768
+ params.c_cflag |= PARENB;
769
+ params.c_cflag |= PARODD;
770
+ break;
771
+
772
+ case NONE:
773
+ params.c_cflag &= ~PARENB;
774
+ break;
775
+
776
+ default:
777
+ rb_raise(rb_eArgError, "unknown parity");
778
+ break;
779
+ }
780
+ SkipParity:
781
+
782
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
783
+ rb_sys_fail(sTcsetattr);
784
+ return self;
785
+ }
786
+
787
+ static void get_modem_params(self, mp)
788
+ VALUE self;
789
+ struct modem_params *mp;
790
+ {
791
+ int fd;
792
+ struct termios params;
793
+
794
+ fd = sp_get_fd(self);
795
+ if (tcgetattr(fd, &params) == -1)
796
+ rb_sys_fail(sTcgetattr);
797
+
798
+ switch (cfgetospeed(&params)) {
799
+ case B50: mp->data_rate = 50; break;
800
+ case B75: mp->data_rate = 75; break;
801
+ case B110: mp->data_rate = 110; break;
802
+ case B134: mp->data_rate = 134; break;
803
+ case B150: mp->data_rate = 150; break;
804
+ case B200: mp->data_rate = 200; break;
805
+ case B300: mp->data_rate = 300; break;
806
+ case B600: mp->data_rate = 600; break;
807
+ case B1200: mp->data_rate = 1200; break;
808
+ case B1800: mp->data_rate = 1800; break;
809
+ case B2400: mp->data_rate = 2400; break;
810
+ case B4800: mp->data_rate = 4800; break;
811
+ case B9600: mp->data_rate = 9600; break;
812
+ case B19200: mp->data_rate = 19200; break;
813
+ case B38400: mp->data_rate = 38400; break;
814
+ #ifdef B57600
815
+ case B57600: mp->data_rate = 57600; break;
816
+ #endif
817
+ #ifdef B76800
818
+ case B76800: mp->data_rate = 76800; break;
819
+ #endif
820
+ #ifdef B115200
821
+ case B115200: mp->data_rate = 115200; break;
822
+ #endif
823
+ #ifdef B230400
824
+ case B230400: mp->data_rate = 230400; break;
825
+ #endif
826
+ }
827
+
828
+ switch(params.c_cflag & CSIZE) {
829
+ case CS5:
830
+ mp->data_bits = 5;
831
+ break;
832
+ case CS6:
833
+ mp->data_bits = 6;
834
+ break;
835
+ case CS7:
836
+ mp->data_bits = 7;
837
+ break;
838
+ case CS8:
839
+ mp->data_bits = 8;
840
+ break;
841
+ default:
842
+ mp->data_bits = 0;
843
+ break;
844
+ }
845
+
846
+ mp->stop_bits = (params.c_cflag & CSTOPB ? 2 : 1);
847
+
848
+ if (!(params.c_cflag & PARENB))
849
+ mp->parity = NONE;
850
+ else if (params.c_cflag & PARODD)
851
+ mp->parity = ODD;
852
+ else
853
+ mp->parity = EVEN;
854
+ }
855
+
856
+ static VALUE sp_set_flow_control(self, val)
857
+ VALUE self, val;
858
+ {
859
+ int fd;
860
+ int flowc;
861
+ struct termios params;
862
+
863
+ Check_Type(val, T_FIXNUM);
864
+
865
+ fd = sp_get_fd(self);
866
+ if (tcgetattr(fd, &params) == -1)
867
+ rb_sys_fail(sTcgetattr);
868
+
869
+ flowc = FIX2INT(val);
870
+ if (flowc & HARD)
871
+ #ifdef HAVE_FLOWCONTROL_HARD
872
+ params.c_cflag |= CRTSCTS;
873
+ else
874
+ params.c_cflag &= ~CRTSCTS;
875
+ #else
876
+ rb_raise(rb_eIOError, "Hardware flow control not supported");
877
+ #endif
878
+ if (flowc & SOFT)
879
+ params.c_iflag |= (IXON | IXOFF | IXANY);
880
+ else
881
+ params.c_iflag &= ~(IXON | IXOFF | IXANY);
882
+
883
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
884
+ rb_sys_fail(sTcsetattr);
885
+ return self;
886
+ }
887
+
888
+ static VALUE sp_get_flow_control(self)
889
+ VALUE self;
890
+ {
891
+ int ret;
892
+ int fd;
893
+ struct termios params;
894
+
895
+ fd = sp_get_fd(self);
896
+ if (tcgetattr(fd, &params) == -1)
897
+ rb_sys_fail(sTcgetattr);
898
+
899
+ ret = 0;
900
+ #ifdef HAVE_FLOWCONTROL_HARD
901
+ if (params.c_cflag & CRTSCTS)
902
+ ret += HARD;
903
+ #endif
904
+ if (params.c_iflag & (IXON | IXOFF | IXANY))
905
+ ret += SOFT;
906
+
907
+ return INT2FIX(ret);
908
+ }
909
+
910
+ static VALUE sp_set_read_timeout(self, val)
911
+ VALUE self, val;
912
+ {
913
+ int timeout;
914
+ int fd;
915
+ struct termios params;
916
+
917
+ Check_Type(val, T_FIXNUM);
918
+ timeout = FIX2INT(val);
919
+
920
+ fd = sp_get_fd(self);
921
+ if (tcgetattr(fd, &params) == -1)
922
+ rb_sys_fail(sTcgetattr);
923
+
924
+ if (timeout < 0) {
925
+ params.c_cc[VTIME] = 0;
926
+ params.c_cc[VMIN] = 0;
927
+ } else if (timeout == 0) {
928
+ params.c_cc[VTIME] = 0;
929
+ params.c_cc[VMIN] = 1;
930
+ } else {
931
+ params.c_cc[VTIME] = (timeout + 50) / 100;
932
+ params.c_cc[VMIN] = 0;
933
+ }
934
+
935
+ if (tcsetattr(fd, TCSANOW, &params) == -1)
936
+ rb_sys_fail(sTcsetattr);
937
+ return self;
938
+ }
939
+
940
+ static VALUE sp_get_read_timeout(self)
941
+ VALUE self;
942
+ {
943
+ int fd;
944
+ struct termios params;
945
+
946
+ fd = sp_get_fd(self);
947
+ if (tcgetattr(fd, &params) == -1)
948
+ rb_sys_fail(sTcgetattr);
949
+ if (params.c_cc[VTIME] == 0 && params.c_cc[VMIN] == 0)
950
+ return INT2FIX(-1);
951
+ return INT2FIX(params.c_cc[VTIME] * 100);
952
+ }
953
+
954
+ static VALUE sp_set_write_timeout(self, val)
955
+ VALUE self, val;
956
+ {
957
+ rb_notimplement();
958
+ return self;
959
+ }
960
+
961
+ static VALUE sp_get_write_timeout(self)
962
+ VALUE self;
963
+ {
964
+ rb_notimplement();
965
+ return self;
966
+ }
967
+
968
+ static VALUE sp_break(self, time)
969
+ VALUE self, time;
970
+ {
971
+ int fd;
972
+
973
+ Check_Type(time, T_FIXNUM);
974
+
975
+ fd = sp_get_fd(self);
976
+ if (tcsendbreak(fd, FIX2INT(time) / 3) == -1)
977
+ rb_sys_fail("tcsendbreak");
978
+ return Qnil;
979
+ }
980
+
981
+ static void get_line_signals(obj, ls)
982
+ VALUE obj;
983
+ struct line_signals *ls;
984
+ {
985
+ int fd, status;
986
+
987
+ fd = sp_get_fd(obj);
988
+ if (ioctl(fd, TIOCMGET, &status) == -1)
989
+ rb_sys_fail(sIoctl);
990
+
991
+ ls->rts = (status & TIOCM_RTS ? 1 : 0);
992
+ ls->dtr = (status & TIOCM_DTR ? 1 : 0);
993
+ ls->cts = (status & TIOCM_CTS ? 1 : 0);
994
+ ls->dsr = (status & TIOCM_DSR ? 1 : 0);
995
+ ls->dcd = (status & TIOCM_CD ? 1 : 0);
996
+ ls->ri = (status & TIOCM_RI ? 1 : 0);
997
+ }
998
+
999
+ static VALUE set_signal(obj, val, sig)
1000
+ VALUE obj,val;
1001
+ int sig;
1002
+ {
1003
+ int status;
1004
+ int fd;
1005
+ int set;
1006
+
1007
+ Check_Type(val, T_FIXNUM);
1008
+ fd = sp_get_fd(obj);
1009
+ if (ioctl(fd, TIOCMGET, &status) == -1)
1010
+ rb_sys_fail(sIoctl);
1011
+
1012
+ set = FIX2INT(val);
1013
+ if (set == 0)
1014
+ status &= ~sig;
1015
+ else if (set == 1)
1016
+ status |= sig;
1017
+ else
1018
+ rb_raise(rb_eArgError, "invalid value");
1019
+
1020
+ if (ioctl(fd, TIOCMSET, &status) == -1)
1021
+ rb_sys_fail(sIoctl);
1022
+ return obj;
1023
+ }
1024
+
1025
+ static VALUE sp_set_rts(self, val)
1026
+ VALUE self, val;
1027
+ {
1028
+ return set_signal(self, val, TIOCM_RTS);
1029
+ }
1030
+
1031
+ static VALUE sp_set_dtr(self, val)
1032
+ VALUE self, val;
1033
+ {
1034
+ return set_signal(self, val, TIOCM_DTR);
1035
+ }
1036
+
1037
+ static VALUE sp_get_rts(self)
1038
+ VALUE self;
1039
+ {
1040
+ struct line_signals ls;
1041
+
1042
+ get_line_signals(self, &ls);
1043
+ return INT2FIX(ls.rts);
1044
+ }
1045
+
1046
+ static VALUE sp_get_dtr(self)
1047
+ VALUE self;
1048
+ {
1049
+ struct line_signals ls;
1050
+
1051
+ get_line_signals(self, &ls);
1052
+ return INT2FIX(ls.dtr);
1053
+ }
1054
+
1055
+
1056
+ #endif /* defined(mswin) || defined(bccwin) */
1057
+
1058
+
1059
+ static VALUE sp_set_data_rate(self, data_rate)
1060
+ VALUE self, data_rate;
1061
+ {
1062
+ VALUE argv[4];
1063
+
1064
+ argv[0] = data_rate;
1065
+ argv[1] = argv[2] = argv[3] = Qnil;
1066
+ return sp_set_modem_params(4, argv, self);
1067
+ }
1068
+
1069
+ static VALUE sp_set_data_bits(self, data_bits)
1070
+ VALUE self, data_bits;
1071
+ {
1072
+ VALUE argv[4];
1073
+
1074
+ argv[1] = data_bits;
1075
+ argv[0] = argv[2] = argv[3] = Qnil;
1076
+ return sp_set_modem_params(4, argv, self);
1077
+ }
1078
+
1079
+ static VALUE sp_set_stop_bits(self, stop_bits)
1080
+ VALUE self, stop_bits;
1081
+ {
1082
+ VALUE argv[4];
1083
+
1084
+ argv[2] = stop_bits;
1085
+ argv[0] = argv[1] = argv[3] = Qnil;
1086
+ return sp_set_modem_params(4, argv, self);
1087
+ }
1088
+
1089
+ static VALUE sp_set_parity(self, parity)
1090
+ VALUE self, parity;
1091
+ {
1092
+ VALUE argv[4];
1093
+
1094
+ argv[3] = parity;
1095
+ argv[0] = argv[1] = argv[2] = Qnil;
1096
+ return sp_set_modem_params(4, argv, self);
1097
+ }
1098
+
1099
+ static VALUE sp_get_data_rate(self)
1100
+ VALUE self;
1101
+ {
1102
+ struct modem_params mp;
1103
+
1104
+ get_modem_params(self, &mp);
1105
+ return INT2FIX(mp.data_rate);
1106
+ }
1107
+
1108
+ static VALUE sp_get_data_bits(self)
1109
+ VALUE self;
1110
+ {
1111
+ struct modem_params mp;
1112
+
1113
+ get_modem_params(self, &mp);
1114
+ return INT2FIX(mp.data_bits);
1115
+ }
1116
+
1117
+ static VALUE sp_get_stop_bits(self)
1118
+ VALUE self;
1119
+ {
1120
+ struct modem_params mp;
1121
+
1122
+ get_modem_params(self, &mp);
1123
+ return INT2FIX(mp.stop_bits);
1124
+ }
1125
+
1126
+ static VALUE sp_get_parity(self)
1127
+ VALUE self;
1128
+ {
1129
+ struct modem_params mp;
1130
+
1131
+ get_modem_params(self, &mp);
1132
+ return INT2FIX(mp.parity);
1133
+ }
1134
+
1135
+ static VALUE sp_get_modem_params(self)
1136
+ VALUE self;
1137
+ {
1138
+ struct modem_params mp;
1139
+ VALUE hash;
1140
+
1141
+ get_modem_params(self, &mp);
1142
+ hash = rb_hash_new();
1143
+ rb_hash_aset(hash, sBaud, INT2FIX(mp.data_rate));
1144
+ rb_hash_aset(hash, sDataBits, INT2FIX(mp.data_bits));
1145
+ rb_hash_aset(hash, sStopBits, INT2FIX(mp.stop_bits));
1146
+ rb_hash_aset(hash, sParity, INT2FIX(mp.parity));
1147
+ return hash;
1148
+ }
1149
+
1150
+ static VALUE sp_get_cts(self)
1151
+ VALUE self;
1152
+ {
1153
+ struct line_signals ls;
1154
+
1155
+ get_line_signals(self, &ls);
1156
+ return INT2FIX(ls.cts);
1157
+ }
1158
+
1159
+ static VALUE sp_get_dsr(self)
1160
+ VALUE self;
1161
+ {
1162
+ struct line_signals ls;
1163
+
1164
+ get_line_signals(self, &ls);
1165
+ return INT2FIX(ls.dsr);
1166
+ }
1167
+
1168
+ static VALUE sp_get_dcd(self)
1169
+ VALUE self;
1170
+ {
1171
+ struct line_signals ls;
1172
+
1173
+ get_line_signals(self, &ls);
1174
+ return INT2FIX(ls.dcd);
1175
+ }
1176
+
1177
+ static VALUE sp_get_ri(self)
1178
+ VALUE self;
1179
+ {
1180
+ struct line_signals ls;
1181
+
1182
+ get_line_signals(self, &ls);
1183
+ return INT2FIX(ls.ri);
1184
+ }
1185
+
1186
+ static VALUE
1187
+ sp_signals(self)
1188
+ VALUE self;
1189
+ {
1190
+ struct line_signals ls;
1191
+ VALUE hash;
1192
+
1193
+ get_line_signals(self, &ls);
1194
+ hash = rb_hash_new();
1195
+ #if !(defined(mswin) || defined(bccwin))
1196
+ rb_hash_aset(hash, sRts, INT2FIX(ls.rts));
1197
+ rb_hash_aset(hash, sDtr, INT2FIX(ls.dtr));
1198
+ #endif
1199
+ rb_hash_aset(hash, sCts, INT2FIX(ls.cts));
1200
+ rb_hash_aset(hash, sDsr, INT2FIX(ls.dsr));
1201
+ rb_hash_aset(hash, sDcd, INT2FIX(ls.dcd));
1202
+ rb_hash_aset(hash, sRi, INT2FIX(ls.ri));
1203
+ return hash;
1204
+ }
1205
+
1206
+ void Init_serialport() {
1207
+ VALUE code;
1208
+ VALUE lineno = INT2NUM(1);
1209
+ VALUE filename = rb_str_new2(__FILE__);
1210
+ VALUE argv[3] = {code, filename lineno};
1211
+
1212
+ sBaud = rb_str_new2("baud");
1213
+ sDataBits = rb_str_new2("data_bits");
1214
+ sStopBits = rb_str_new2("stop_bits");
1215
+ sParity = rb_str_new2("parity");
1216
+ sRts = rb_str_new2("rts");
1217
+ sDtr = rb_str_new2("dtr");
1218
+ sCts = rb_str_new2("cts");
1219
+ sDsr = rb_str_new2("dsr");
1220
+ sDcd = rb_str_new2("dcd");
1221
+ sRi = rb_str_new2("ri");
1222
+
1223
+ rb_gc_register_address(&sBaud);
1224
+ rb_gc_register_address(&sDataBits);
1225
+ rb_gc_register_address(&sStopBits);
1226
+ rb_gc_register_address(&sParity);
1227
+ rb_gc_register_address(&sRts);
1228
+ rb_gc_register_address(&sDtr);
1229
+ rb_gc_register_address(&sCts);
1230
+ rb_gc_register_address(&sDsr);
1231
+ rb_gc_register_address(&sDcd);
1232
+ rb_gc_register_address(&sRi);
1233
+
1234
+ cSerialPort = rb_define_class("SerialPort", rb_cIO);
1235
+ rb_define_singleton_method(cSerialPort, "create", sp_create, 1);
1236
+
1237
+ rb_define_method(cSerialPort, "get_modem_params", sp_get_modem_params, 0);
1238
+ rb_define_method(cSerialPort, "set_modem_params", sp_set_modem_params, -1);
1239
+ rb_define_method(cSerialPort, "modem_params", sp_get_modem_params, 0);
1240
+ rb_define_method(cSerialPort, "modem_params=", sp_set_modem_params, -1);
1241
+ rb_define_method(cSerialPort, "baud", sp_get_data_rate, 0);
1242
+ rb_define_method(cSerialPort, "baud=", sp_set_data_rate, 1);
1243
+ rb_define_method(cSerialPort, "data_bits", sp_get_data_bits, 0);
1244
+ rb_define_method(cSerialPort, "data_bits=", sp_set_data_bits, 1);
1245
+ rb_define_method(cSerialPort, "stop_bits", sp_get_stop_bits, 0);
1246
+ rb_define_method(cSerialPort, "stop_bits=", sp_set_stop_bits, 1);
1247
+ rb_define_method(cSerialPort, "parity", sp_get_parity, 0);
1248
+ rb_define_method(cSerialPort, "parity=", sp_set_parity, 1);
1249
+
1250
+ rb_define_method(cSerialPort, "flow_control=", sp_set_flow_control, 1);
1251
+ rb_define_method(cSerialPort, "flow_control", sp_get_flow_control, 0);
1252
+
1253
+ rb_define_method(cSerialPort, "read_timeout", sp_get_read_timeout, 0);
1254
+ rb_define_method(cSerialPort, "read_timeout=", sp_set_read_timeout, 1);
1255
+ rb_define_method(cSerialPort, "write_timeout", sp_get_write_timeout, 0);
1256
+ rb_define_method(cSerialPort, "write_timeout=", sp_set_write_timeout, 1);
1257
+
1258
+ rb_define_method(cSerialPort, "break", sp_break, 1);
1259
+
1260
+ rb_define_method(cSerialPort, "signals", sp_signals, 0);
1261
+ rb_define_method(cSerialPort, "get_signals", sp_signals, 0);
1262
+ rb_define_method(cSerialPort, "rts", sp_get_rts, 0);
1263
+ rb_define_method(cSerialPort, "rts=", sp_set_rts, 1);
1264
+ rb_define_method(cSerialPort, "dtr", sp_get_dtr, 0);
1265
+ rb_define_method(cSerialPort, "dtr=", sp_set_dtr, 1);
1266
+ rb_define_method(cSerialPort, "cts", sp_get_cts, 0);
1267
+ rb_define_method(cSerialPort, "dsr", sp_get_dsr, 0);
1268
+ rb_define_method(cSerialPort, "dcd", sp_get_dcd, 0);
1269
+ rb_define_method(cSerialPort, "ri", sp_get_ri, 0);
1270
+
1271
+ rb_define_const(cSerialPort, "NONE", INT2FIX(NONE));
1272
+ rb_define_const(cSerialPort, "HARD", INT2FIX(HARD));
1273
+ rb_define_const(cSerialPort, "SOFT", INT2FIX(SOFT));
1274
+
1275
+ rb_define_const(cSerialPort, "SPACE", INT2FIX(SPACE));
1276
+ rb_define_const(cSerialPort, "MARK", INT2FIX(MARK));
1277
+ rb_define_const(cSerialPort, "EVEN", INT2FIX(EVEN));
1278
+ rb_define_const(cSerialPort, "ODD", INT2FIX(ODD));
1279
+
1280
+ rb_define_const(cSerialPort, "VERSION", rb_str_new2(VERSION));
1281
+
1282
+ /* The following definitions are more easily carried out in Ruby */
1283
+ //rb_eval_string(
1284
+ lineno = INT2NUM(__LINE__ + 1)
1285
+ code = rb_str_new2("class SerialPort\n"
1286
+
1287
+ "private_class_method(:create)\n"
1288
+
1289
+ "def SerialPort::new(port, *params)\n"
1290
+ "sp = create(port)\n"
1291
+ "begin\n"
1292
+ "sp.set_modem_params(*params)\n"
1293
+ "rescue\n"
1294
+ "sp.close\n"
1295
+ "raise\n"
1296
+ "end\n"
1297
+ "return sp\n"
1298
+ "end\n"
1299
+
1300
+ "def SerialPort::open(port, *params)\n"
1301
+ "sp = create(port)\n"
1302
+ "begin\n"
1303
+ "sp.set_modem_params(*params)\n"
1304
+ "if (block_given?)\n"
1305
+ "yield sp\n"
1306
+ "sp.close\n"
1307
+ "return nil\n"
1308
+ "end\n"
1309
+ "rescue\n"
1310
+ "sp.close\n"
1311
+ "raise\n"
1312
+ "end\n"
1313
+ "return sp\n"
1314
+ "end\n"
1315
+
1316
+ "end\n"
1317
+ );
1318
+ rb_obj_instance_eval(sizeof(argv), argv, rb_mKernel);
1319
+ }