x10-cm17a 1.0.1-i386-mswin32
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +204 -0
- data/ext/cm17a_api/MANIFEST +4 -0
- data/ext/cm17a_api/cm17a.c +443 -0
- data/ext/cm17a_api/cm17a.h +63 -0
- data/ext/cm17a_api/cm17a_api.c +130 -0
- data/ext/cm17a_api/extconf.rb +17 -0
- data/lib/i386-mswin32/cm17a_api.so +0 -0
- data/lib/x10.rb +102 -0
- data/lib/x10/cm17a.rb +29 -0
- data/lib/x10/cm17a_device.rb +61 -0
- data/lib/x10/cm17a_remote.rb +25 -0
- data/setup.rb +1360 -0
- data/test/test_cm17a_controller.rb +35 -0
- data/test/test_cm17a_device.rb +141 -0
- data/test/test_x10.rb +36 -0
- metadata +53 -0
data/Rakefile
ADDED
@@ -0,0 +1,204 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
|
3
|
+
require 'rake/clean'
|
4
|
+
require 'rake/testtask'
|
5
|
+
require 'rake/rdoctask'
|
6
|
+
require 'rbconfig'
|
7
|
+
|
8
|
+
begin
|
9
|
+
require 'rubygems'
|
10
|
+
require 'rake/gempackagetask'
|
11
|
+
rescue Exception
|
12
|
+
nil
|
13
|
+
end
|
14
|
+
|
15
|
+
ARCH = Config::CONFIG['arch']
|
16
|
+
SO_FILE = "lib/#{ARCH}/cm17a_api.so"
|
17
|
+
|
18
|
+
MAKE = (ARCH =~ /win32/) ? 'nmake' : 'make'
|
19
|
+
|
20
|
+
CLOBBER.include(
|
21
|
+
SO_FILE,
|
22
|
+
'ext/cm17a_api/*.o',
|
23
|
+
'ext/cm17a_api/*.obj',
|
24
|
+
'ext/cm17a_api/*.def',
|
25
|
+
'ext/cm17a_api/*.exp',
|
26
|
+
'ext/cm17a_api/*.lib',
|
27
|
+
'ext/cm17a_api/*.pdb',
|
28
|
+
'ext/cm17a_api/*.so',
|
29
|
+
'ext/cm17a_api/Makefile',
|
30
|
+
'ext/cm17a_api/MANIFEST',
|
31
|
+
'lib/*-*',
|
32
|
+
'**/*.log'
|
33
|
+
)
|
34
|
+
|
35
|
+
desc "Default task (run tests)"
|
36
|
+
task :default => :test
|
37
|
+
|
38
|
+
desc "Run the unit tests"
|
39
|
+
Rake::TestTask.new do |t|
|
40
|
+
t.test_files = FileList['test/test_*.rb']
|
41
|
+
t.libs << "lib/#{ARCH}"
|
42
|
+
end
|
43
|
+
task :test => [SO_FILE]
|
44
|
+
|
45
|
+
task :xtest => [SO_FILE] do
|
46
|
+
test_files = FileList['test/test_*.rb']
|
47
|
+
ruby "-Ilib", "-Ilib/#{ARCH}", '-e0', *test_files.collect { |fn| "-r#{fn}" }
|
48
|
+
end
|
49
|
+
|
50
|
+
task :compile => [SO_FILE]
|
51
|
+
|
52
|
+
directory File.dirname(SO_FILE)
|
53
|
+
|
54
|
+
file SO_FILE => ["ext/cm17a_api/cm17a_api.so", File.dirname(SO_FILE)] do |t|
|
55
|
+
cp t.prerequisites.first, SO_FILE
|
56
|
+
end
|
57
|
+
|
58
|
+
file "ext/cm17a_api/Makefile" => ["ext/cm17a_api/extconf.rb"] do
|
59
|
+
Dir.chdir("ext/cm17a_api") do ruby "extconf.rb" end
|
60
|
+
end
|
61
|
+
|
62
|
+
CM17A_FILES = FileList[
|
63
|
+
'ext/cm17a_api/*.c',
|
64
|
+
'ext/cm17a_api/*.h',
|
65
|
+
'ext/cm17a_api/extconf.rb',
|
66
|
+
'ext/cm17a_api/Makefile',
|
67
|
+
'ext/cm17a_api/MANIFEST',
|
68
|
+
]
|
69
|
+
|
70
|
+
file "ext/cm17a_api/cm17a_api.so" => CM17A_FILES do
|
71
|
+
Dir.chdir("ext/cm17a_api") do
|
72
|
+
sh MAKE
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# RDoc Documentation -------------------------------------------------
|
77
|
+
|
78
|
+
# Choose template, prefer the jamis template if it is available
|
79
|
+
|
80
|
+
def choose_rdoc_template
|
81
|
+
libdir = Config::CONFIG['rubylibdir']
|
82
|
+
templates = Dir[File.join(libdir, 'rdoc/**/jamis.rb')]
|
83
|
+
templates.empty? ? 'html': 'jamis'
|
84
|
+
end
|
85
|
+
|
86
|
+
rd = Rake::RDocTask.new("rdoc") { |rdoc|
|
87
|
+
rdoc.rdoc_dir = 'html'
|
88
|
+
rdoc.template = choose_rdoc_template
|
89
|
+
rdoc.title = "Ruby X10 Software"
|
90
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--main' << 'README'
|
91
|
+
rdoc.rdoc_files.include(
|
92
|
+
'lib/**/*.rb',
|
93
|
+
'doc/*.rdoc',
|
94
|
+
'ext/**/cm17a_api.c',
|
95
|
+
'README',
|
96
|
+
'MIT-LICENSE')
|
97
|
+
rdoc.rdoc_files.exclude('lib/**/other.rb', 'lib/**/bottlerocket.rb')
|
98
|
+
}
|
99
|
+
|
100
|
+
|
101
|
+
# Packaging Tasks ----------------------------------------------------
|
102
|
+
|
103
|
+
file "ext/cm17a_api/MANIFEST" do |t|
|
104
|
+
open(t.name, "w") do |f|
|
105
|
+
f.puts Dir["ext/cm17a_api/*"].select { |fn|
|
106
|
+
fn =~ /\.(h|c|rb)$/
|
107
|
+
}.collect { |fn|
|
108
|
+
File.basename(fn)
|
109
|
+
}
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
PKG_VERSION = '1.0.1'
|
114
|
+
PKG_FILES = FileList[
|
115
|
+
'Rakefile',
|
116
|
+
'setup.rb',
|
117
|
+
'test/*.rb',
|
118
|
+
'lib/**/*.rb',
|
119
|
+
'ext/cm17a_api/MANIFEST',
|
120
|
+
'ext/cm17a_api/*.h',
|
121
|
+
'ext/cm17a_api/*.c',
|
122
|
+
'ext/cm17a_api/*.rb',
|
123
|
+
]
|
124
|
+
|
125
|
+
if ! defined?(Gem)
|
126
|
+
puts "Package Target requires RubyGEMs"
|
127
|
+
else
|
128
|
+
spec = Gem::Specification.new do |s|
|
129
|
+
|
130
|
+
#### Basic information.
|
131
|
+
|
132
|
+
s.name = 'x10-cm17a'
|
133
|
+
s.version = PKG_VERSION
|
134
|
+
s.summary = "Ruby based X10 CM17A Firecracker Controller"
|
135
|
+
s.description = <<-EOF
|
136
|
+
EOF
|
137
|
+
|
138
|
+
s.files = PKG_FILES.to_a
|
139
|
+
|
140
|
+
#### C code extensions.
|
141
|
+
|
142
|
+
s.extensions << "ext/cm17a_api/extconf.rb"
|
143
|
+
|
144
|
+
#### Load-time details: library and application (you will need one or both).
|
145
|
+
|
146
|
+
s.require_paths << 'lib' << "lib/#{ARCH}"
|
147
|
+
|
148
|
+
#### Documentation and testing.
|
149
|
+
|
150
|
+
s.has_rdoc = true
|
151
|
+
# s.extra_rdoc_files = rd.rdoc_files.reject { |fn| fn =~ /\.rb$/ }.to_a
|
152
|
+
# s.rdoc_options <<
|
153
|
+
# '--title' << 'Rake -- Ruby Make' <<
|
154
|
+
# '--main' << 'README' <<
|
155
|
+
# '--line-numbers'
|
156
|
+
|
157
|
+
#### Author and project details.
|
158
|
+
|
159
|
+
s.author = "Jim Weirich"
|
160
|
+
s.email = "jim@weirichhouse.org"
|
161
|
+
s.homepage = "http://x10-cm17a.rubyforge.org"
|
162
|
+
end
|
163
|
+
|
164
|
+
binary_spec = spec.dup
|
165
|
+
binary_spec.platform = ARCH
|
166
|
+
binary_spec.files += ["lib/#{ARCH}/cm17a_api.so"]
|
167
|
+
binary_spec.extensions = []
|
168
|
+
|
169
|
+
puts binary_spec.files.class
|
170
|
+
|
171
|
+
Rake::GemPackageTask.new(binary_spec) do |pkg|
|
172
|
+
pkg.need_zip = false
|
173
|
+
pkg.need_tar = false
|
174
|
+
end
|
175
|
+
|
176
|
+
# Rake::GemPackageTask.new(binary_spec) do end
|
177
|
+
end
|
178
|
+
|
179
|
+
|
180
|
+
# Publishing Tasks ---------------------------------------------------
|
181
|
+
|
182
|
+
|
183
|
+
task :publish_on_osb => ["pkg/cm17a-#{PKG_VERSION}.tgz", "pkg/cm17a-#{PKG_VERSION}.gem"] do |t|
|
184
|
+
sh %{ssh umlcoop mkdir -p "htdocs/software/cm17a"}
|
185
|
+
sh %{scp -rq #{t.prerequisites.join(' ')} umlcoop:htdocs/software/cm17a}
|
186
|
+
end
|
187
|
+
|
188
|
+
# Optional publish task for Rake
|
189
|
+
|
190
|
+
require 'rake/contrib/sshpublisher'
|
191
|
+
require 'rake/contrib/rubyforgepublisher'
|
192
|
+
|
193
|
+
publisher = Rake::CompositePublisher.new
|
194
|
+
publisher.add Rake::RubyForgePublisher.new('x10-cm17a', 'jimweirich')
|
195
|
+
publisher.add Rake::SshFilePublisher.new(
|
196
|
+
'umlcoop',
|
197
|
+
'htdocs/software/x10-cm17a',
|
198
|
+
'.',
|
199
|
+
'x10-cm17a.blurb')
|
200
|
+
|
201
|
+
desc "Publish the Documentation to RubyForge."
|
202
|
+
task :publish => [:rdoc] do
|
203
|
+
publisher.upload
|
204
|
+
end
|
@@ -0,0 +1,443 @@
|
|
1
|
+
/*
|
2
|
+
* Modification for dual Unix/Windows compatibility:
|
3
|
+
* Copyright 2004 by Jim Weirich (jim@weirichhouse.org)
|
4
|
+
* All rights reserved.
|
5
|
+
*
|
6
|
+
* See the MIT-LICENSE file included with the distribution for
|
7
|
+
* details on redistribution rights.
|
8
|
+
*
|
9
|
+
* This cm17a driver file is a merging of two separate cm17a drivers,
|
10
|
+
* one for Linux by Matt Armstrong and the other for Windows by Adam
|
11
|
+
* Briggs. Both Matt and Adam have licensed their code so that it can
|
12
|
+
* be modified and reused as long as the relevent copyrights notices,
|
13
|
+
* conditions and disclaimers are intact.
|
14
|
+
*
|
15
|
+
* So first we have Matt's copyright notice for the Linux code:
|
16
|
+
*
|
17
|
+
* Copyright (C) 1999, 2002 Matt Armstrong
|
18
|
+
* All rights reserved.
|
19
|
+
*
|
20
|
+
* Redistribution and use in source and binary forms, with or
|
21
|
+
* without modification, are permitted provided that the
|
22
|
+
* following conditions are met:
|
23
|
+
*
|
24
|
+
* 1. Redistributions of source code must retain the above
|
25
|
+
* copyright notice, this list of conditions and the following
|
26
|
+
* disclaimer.
|
27
|
+
*
|
28
|
+
* 2. Redistributions in binary form must reproduce the above
|
29
|
+
* copyright notice, this list of conditions and the following
|
30
|
+
* disclaimer in the documentation and/or other materials
|
31
|
+
* provided with the distribution.
|
32
|
+
*
|
33
|
+
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS
|
34
|
+
* IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
35
|
+
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
36
|
+
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE
|
37
|
+
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY,
|
38
|
+
* OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
39
|
+
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
|
40
|
+
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
41
|
+
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
|
42
|
+
* TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
|
43
|
+
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
|
44
|
+
* OF SUCH DAMAGE.
|
45
|
+
*
|
46
|
+
* Next we have Adam's copyright for the Windows code.
|
47
|
+
*
|
48
|
+
* This code is (c)2000, Adam Briggs. All Rights Reserved.
|
49
|
+
*
|
50
|
+
* Permission to use, copy, and distribute this software and its
|
51
|
+
* documentation for any purpose and without fee is hereby granted,
|
52
|
+
* provided that the above copyright notice appear in all copies
|
53
|
+
* and that both that copyright notice and this permission notice
|
54
|
+
* appear in supporting documentation, and that the name Adam
|
55
|
+
* Briggs not be used in advertising or publicity pertaining to
|
56
|
+
* distribution of the software without specific, written prior
|
57
|
+
* permission.
|
58
|
+
*
|
59
|
+
* *** DISCLAIMER ***
|
60
|
+
*
|
61
|
+
* ADAM BRIGGS DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS
|
62
|
+
* SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
63
|
+
* AND FITNESS, IN NO EVENT SHALL ADAM BRIGGS BE LIABLE FOR ANY
|
64
|
+
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
65
|
+
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
|
66
|
+
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTUOUS ACTION,
|
67
|
+
* ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
|
68
|
+
* THIS SOFTWARE.
|
69
|
+
* ***
|
70
|
+
*/
|
71
|
+
|
72
|
+
#ifdef HAVE_CONFIG_H
|
73
|
+
#include <config.h>
|
74
|
+
#endif
|
75
|
+
|
76
|
+
#ifdef CM17A_WIN32
|
77
|
+
|
78
|
+
#include <windows.h>
|
79
|
+
#include <stdio.h>
|
80
|
+
|
81
|
+
#else
|
82
|
+
|
83
|
+
#include <stdio.h>
|
84
|
+
#include <stddef.h>
|
85
|
+
#include <ctype.h>
|
86
|
+
#include <stdlib.h>
|
87
|
+
#include <assert.h>
|
88
|
+
|
89
|
+
#if HAVE_FCNTL_H
|
90
|
+
#include <fcntl.h>
|
91
|
+
#endif
|
92
|
+
#if HAVE_SYS_IOCTL_H
|
93
|
+
#include <sys/ioctl.h>
|
94
|
+
#endif
|
95
|
+
#if HAVE_SYS_TIME_H
|
96
|
+
#include <sys/time.h>
|
97
|
+
#endif
|
98
|
+
#if HAVE_SYS_TYPES_H
|
99
|
+
#include <sys/types.h>
|
100
|
+
#endif
|
101
|
+
#if HAVE_UNISTD_H
|
102
|
+
#include <unistd.h>
|
103
|
+
#endif
|
104
|
+
#if HAVE_TERMIO_H
|
105
|
+
#include <termio.h>
|
106
|
+
#endif
|
107
|
+
|
108
|
+
#endif
|
109
|
+
|
110
|
+
#include "cm17a.h"
|
111
|
+
|
112
|
+
/* The house code is the high nibble of the command data. */
|
113
|
+
unsigned short house_codes[16] = {
|
114
|
+
0x6000, /* A */
|
115
|
+
0x7000, /* B */
|
116
|
+
0x4000, /* C */
|
117
|
+
0x5000, /* D */
|
118
|
+
0x8000, /* E */
|
119
|
+
0x9000, /* F */
|
120
|
+
0xA000, /* G */
|
121
|
+
0xB000, /* H */
|
122
|
+
0xE000, /* I */
|
123
|
+
0xF000, /* J */
|
124
|
+
0xC000, /* K */
|
125
|
+
0xD000, /* L */
|
126
|
+
0x0000, /* M */
|
127
|
+
0x1000, /* N */
|
128
|
+
0x2000, /* O */
|
129
|
+
0x3000, /* P */
|
130
|
+
};
|
131
|
+
|
132
|
+
/* The device codes are described by bits 3, 4, 6, and 10. */
|
133
|
+
#define DEVICE_BITS 0x0458
|
134
|
+
unsigned short device_codes[16] = {
|
135
|
+
0x0000, /* 1 */
|
136
|
+
0x0010, /* 2 */
|
137
|
+
0x0008, /* 3 */
|
138
|
+
0x0018, /* 4 */
|
139
|
+
0x0040, /* 5 */
|
140
|
+
0x0050, /* 6 */
|
141
|
+
0x0048, /* 7 */
|
142
|
+
0x0058, /* 8 */
|
143
|
+
0x0400, /* 9 */
|
144
|
+
0x0410, /* 10 */
|
145
|
+
0x0408, /* 11 */
|
146
|
+
0x0418, /* 12 */
|
147
|
+
0x0440, /* 13 */
|
148
|
+
0x0450, /* 14 */
|
149
|
+
0x0448, /* 15 */
|
150
|
+
0x0458, /* 16 */
|
151
|
+
};
|
152
|
+
|
153
|
+
/* The command codes are described by bits 1, 2, 5, 7, 8, 9, and
|
154
|
+
11. */
|
155
|
+
unsigned short command_codes[] = {
|
156
|
+
0x0000, /* CM17A_ON */
|
157
|
+
0x0020, /* CM17A_OFF */
|
158
|
+
0x0088, /* BRIGHT */
|
159
|
+
0x0098, /* CM17A_DIM */
|
160
|
+
};
|
161
|
+
|
162
|
+
#define ELEMENT_COUNT(a) (sizeof(a) / sizeof((a)[0]))
|
163
|
+
|
164
|
+
static unsigned short
|
165
|
+
cm17a_command_word(int house,
|
166
|
+
int device,
|
167
|
+
enum CM17A_COMMAND command)
|
168
|
+
{
|
169
|
+
unsigned short retval;
|
170
|
+
|
171
|
+
switch (command) {
|
172
|
+
case CM17A_BRIGHTEN:
|
173
|
+
case CM17A_DIM:
|
174
|
+
retval = house_codes[house] | command_codes[command];
|
175
|
+
break;
|
176
|
+
|
177
|
+
default:
|
178
|
+
retval = (house_codes[house] |
|
179
|
+
device_codes[device] |
|
180
|
+
command_codes[command]);
|
181
|
+
break;
|
182
|
+
}
|
183
|
+
|
184
|
+
return retval;
|
185
|
+
}
|
186
|
+
|
187
|
+
#ifdef CM17A_WIN32
|
188
|
+
|
189
|
+
#define X10_DEVICE HANDLE
|
190
|
+
|
191
|
+
/* delay between bits */
|
192
|
+
static void delay(void)
|
193
|
+
{
|
194
|
+
Sleep(2);
|
195
|
+
}
|
196
|
+
|
197
|
+
/* delay between commands */
|
198
|
+
static void long_delay(void)
|
199
|
+
{
|
200
|
+
Sleep(5);
|
201
|
+
}
|
202
|
+
|
203
|
+
static int cm17a_standby(X10_DEVICE fd)
|
204
|
+
{
|
205
|
+
EscapeCommFunction(fd, SETDTR);
|
206
|
+
EscapeCommFunction(fd, SETRTS);
|
207
|
+
delay();
|
208
|
+
return 0;
|
209
|
+
}
|
210
|
+
|
211
|
+
static int write_byte(X10_DEVICE fd, unsigned char byte)
|
212
|
+
{
|
213
|
+
int theMask = 0x80 ;
|
214
|
+
|
215
|
+
while (theMask) {
|
216
|
+
if (byte & theMask) {
|
217
|
+
EscapeCommFunction(fd, SETRTS);
|
218
|
+
EscapeCommFunction(fd, CLRDTR);
|
219
|
+
}
|
220
|
+
else {
|
221
|
+
EscapeCommFunction(fd, SETDTR);
|
222
|
+
EscapeCommFunction(fd, CLRRTS);
|
223
|
+
}
|
224
|
+
delay();
|
225
|
+
|
226
|
+
EscapeCommFunction(fd, SETDTR);
|
227
|
+
EscapeCommFunction(fd, SETRTS);
|
228
|
+
delay();
|
229
|
+
|
230
|
+
theMask >>= 1;
|
231
|
+
}
|
232
|
+
return 0;
|
233
|
+
}
|
234
|
+
|
235
|
+
X10_DEVICE cm17a_open_device(const char * device_name) {
|
236
|
+
X10_DEVICE fd = CreateFile(
|
237
|
+
device_name,
|
238
|
+
GENERIC_READ | GENERIC_WRITE,
|
239
|
+
0,
|
240
|
+
NULL,
|
241
|
+
OPEN_EXISTING,
|
242
|
+
FILE_FLAG_WRITE_THROUGH,
|
243
|
+
NULL) ;
|
244
|
+
return fd;
|
245
|
+
}
|
246
|
+
|
247
|
+
void cm17a_close_device(X10_DEVICE fd) {
|
248
|
+
CloseHandle(fd);
|
249
|
+
}
|
250
|
+
|
251
|
+
|
252
|
+
#else
|
253
|
+
|
254
|
+
#define X10_DEVICE int
|
255
|
+
|
256
|
+
enum SIGNAL {
|
257
|
+
RESET = 0,
|
258
|
+
HIGH = TIOCM_RTS,
|
259
|
+
LOW = TIOCM_DTR,
|
260
|
+
STANDBY = (TIOCM_RTS | TIOCM_DTR)
|
261
|
+
};
|
262
|
+
|
263
|
+
static void
|
264
|
+
sleep_us(unsigned int nusecs)
|
265
|
+
{
|
266
|
+
struct timeval tval;
|
267
|
+
|
268
|
+
tval.tv_sec = nusecs / 1000000;
|
269
|
+
tval.tv_usec = nusecs % 1000000;
|
270
|
+
select(0, NULL, NULL, NULL, &tval);
|
271
|
+
}
|
272
|
+
|
273
|
+
static void delay(void)
|
274
|
+
{
|
275
|
+
sleep_us(500);
|
276
|
+
}
|
277
|
+
|
278
|
+
static void long_delay(void)
|
279
|
+
{
|
280
|
+
sleep_us(500000);
|
281
|
+
}
|
282
|
+
|
283
|
+
static int set(X10_DEVICE fd, enum SIGNAL signal)
|
284
|
+
{
|
285
|
+
int lines = signal;
|
286
|
+
int current;
|
287
|
+
/* FIXME: we should just remember this in a static
|
288
|
+
variable. */
|
289
|
+
if (ioctl(fd, TIOCMGET, ¤t) != 0) {
|
290
|
+
return -1;
|
291
|
+
}
|
292
|
+
current &= ~RESET;
|
293
|
+
current |= signal;
|
294
|
+
return ioctl(fd, TIOCMSET, &lines);
|
295
|
+
}
|
296
|
+
|
297
|
+
static int cm17a_standby(X10_DEVICE fd)
|
298
|
+
{
|
299
|
+
if (set(fd, STANDBY) != 0) {
|
300
|
+
return -1;
|
301
|
+
}
|
302
|
+
delay();
|
303
|
+
return 0;
|
304
|
+
}
|
305
|
+
|
306
|
+
static int write_byte(X10_DEVICE fd, unsigned char byte)
|
307
|
+
{
|
308
|
+
int mask = 0x80;
|
309
|
+
do {
|
310
|
+
enum SIGNAL signal = (byte & mask) ? HIGH : LOW;
|
311
|
+
if (set(fd, signal) != 0) {
|
312
|
+
return -1;
|
313
|
+
}
|
314
|
+
delay();
|
315
|
+
if (set(fd, STANDBY) != 0) {
|
316
|
+
return -1;
|
317
|
+
}
|
318
|
+
delay();
|
319
|
+
mask >>= 1;
|
320
|
+
} while (mask);
|
321
|
+
return 0;
|
322
|
+
}
|
323
|
+
|
324
|
+
X10_DEVICE cm17a_open_device(const char * device_name) {
|
325
|
+
X10_DEVICE fd = open(device_name, O_RDONLY | O_NDELAY);
|
326
|
+
return (fd < 0) ? INVALID_X10_DEVICE : fd;
|
327
|
+
}
|
328
|
+
|
329
|
+
void cm17a_close_device(fd) {
|
330
|
+
close(fd);
|
331
|
+
}
|
332
|
+
|
333
|
+
#endif
|
334
|
+
|
335
|
+
static int
|
336
|
+
write_stream(
|
337
|
+
X10_DEVICE fd,
|
338
|
+
const unsigned char* data,
|
339
|
+
size_t byte_count)
|
340
|
+
{
|
341
|
+
int i;
|
342
|
+
for (i = 0; i < byte_count; i++) {
|
343
|
+
int ret = write_byte(fd, data[i]);
|
344
|
+
if (ret) {
|
345
|
+
return ret;
|
346
|
+
}
|
347
|
+
}
|
348
|
+
return 0;
|
349
|
+
}
|
350
|
+
|
351
|
+
static int
|
352
|
+
cm17a_header(X10_DEVICE fd)
|
353
|
+
{
|
354
|
+
/* Header bits taken straight from the CM17A spec. */
|
355
|
+
const unsigned char header[] = {
|
356
|
+
0xD5, 0xAA
|
357
|
+
};
|
358
|
+
return write_stream(fd, header, sizeof(header));
|
359
|
+
}
|
360
|
+
|
361
|
+
static int
|
362
|
+
footer(X10_DEVICE fd)
|
363
|
+
{
|
364
|
+
/* Footer bits taken straight from the CM17A spec. */
|
365
|
+
return write_byte(fd, 0xAD);
|
366
|
+
}
|
367
|
+
|
368
|
+
static int
|
369
|
+
cm17a_write_command(
|
370
|
+
X10_DEVICE fd,
|
371
|
+
int house,
|
372
|
+
int device,
|
373
|
+
enum CM17A_COMMAND command)
|
374
|
+
{
|
375
|
+
short command_word;
|
376
|
+
|
377
|
+
command_word = cm17a_command_word(house, device, command);
|
378
|
+
|
379
|
+
if (cm17a_standby(fd)) {
|
380
|
+
return -1;
|
381
|
+
}
|
382
|
+
|
383
|
+
/* The cm17a seems to need another delay period after a
|
384
|
+
standby to settle down after the reset. */
|
385
|
+
delay();
|
386
|
+
|
387
|
+
if (cm17a_header(fd) ||
|
388
|
+
write_byte(fd, command_word >> 8) ||
|
389
|
+
write_byte(fd, command_word) ||
|
390
|
+
footer(fd)) {
|
391
|
+
return -1;
|
392
|
+
}
|
393
|
+
|
394
|
+
long_delay();
|
395
|
+
|
396
|
+
return 0;
|
397
|
+
}
|
398
|
+
|
399
|
+
void
|
400
|
+
cm17a_command(
|
401
|
+
X10_DEVICE fd,
|
402
|
+
int house,
|
403
|
+
int device,
|
404
|
+
enum CM17A_COMMAND cmd,
|
405
|
+
int steps)
|
406
|
+
{
|
407
|
+
switch (cmd) {
|
408
|
+
case CM17A_ON:
|
409
|
+
case CM17A_OFF:
|
410
|
+
if (cm17a_write_command(fd, house, device, cmd) != 0) {
|
411
|
+
fprintf(stderr, "Command failed.\n");
|
412
|
+
}
|
413
|
+
break;
|
414
|
+
case CM17A_BRIGHTEN:
|
415
|
+
case CM17A_DIM:
|
416
|
+
{
|
417
|
+
if (steps < 1 || steps > 6) {
|
418
|
+
fprintf(stderr,
|
419
|
+
"Invalid steps (%d). Must be [1..6].\n",
|
420
|
+
steps);
|
421
|
+
return;
|
422
|
+
}
|
423
|
+
|
424
|
+
/* Turn the device we wish to control on first. If we don't
|
425
|
+
do this, the dim command gets handled by the last device
|
426
|
+
that got turned on. The cm17a dim/brighten command doesn't
|
427
|
+
use a device code. */
|
428
|
+
|
429
|
+
if (cm17a_write_command(fd, house, device, CM17A_ON) != 0) {
|
430
|
+
fprintf(stderr, "Command failed.\n");
|
431
|
+
}
|
432
|
+
|
433
|
+
while (--steps >= 0) {
|
434
|
+
if (cm17a_write_command(fd, house, device, cmd)) {
|
435
|
+
fprintf(stderr, "Command failed.\n");
|
436
|
+
}
|
437
|
+
}
|
438
|
+
break;
|
439
|
+
}
|
440
|
+
default:
|
441
|
+
fprintf(stderr, "Invalid flip operation\n");
|
442
|
+
}
|
443
|
+
}
|