micro_aeth-ae51-ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: d6c48744a043423d468f6efbe381db6ed005d668
4
+ data.tar.gz: 992247eaeb80568221f19142cc0a0b3f8448417d
5
+ SHA512:
6
+ metadata.gz: a49064b2b7c4ef853ce5eb51ce359ae3f1ebc9895205045e577f47986c72d2bb019d5e042d7f30ad91da2b2d7957d4ed0e162ede8af6a06b274b386837562dfa
7
+ data.tar.gz: e90dc640e49fa5f117ffa001c100db896a39bcfc2e31a642fd73c5bc13ec3d75733703c5cf59a31f2788750f443540eff9f7e1cdccc54d9e034fbaf43c6b1bee
@@ -0,0 +1,317 @@
1
+ require 'serialport'
2
+ require 'timeout'
3
+
4
+ module MicroAethAE51
5
+ class ::String
6
+ ###
7
+ # @return the first charater in the string as an integer
8
+ def byte
9
+ self.bytes[0]
10
+ end
11
+
12
+ ###
13
+ # XOR two strings
14
+ # @str assumed to be a one byte string or integer
15
+ def ^ str
16
+ if str.class == String
17
+ str = str.byte
18
+ elsif str.class == Fixnum
19
+ nil
20
+ else
21
+ raise "invalid arg: #{str.class} \n Must be String or Fixnum"
22
+ end
23
+ self.bytes.each do |i|
24
+ str = str ^ i
25
+ end
26
+ str.chr.force_encoding( "ASCII-8BIT")
27
+ end
28
+ end
29
+
30
+ class Instruction
31
+ ###
32
+ # Message constants
33
+ STX = "\x02" # Start of each message
34
+ ETX = "\x03" # End of each message
35
+ M = "AE5X:" # What each message starts with
36
+ EraseFlash = "E" # Reply:ACK, after flash is erased anotherACK issent.(erasing should take 30 – 45 seconds)
37
+ StopWrite = "S" # stopswriting to flash
38
+ StartWrite = "W" # Startswriting to flash
39
+ Kill = "K" # Kill Shuts down microAeth
40
+ end
41
+
42
+ ###
43
+ # Creates and parses messages to and from the MicroAeth.
44
+ # See MicroAeth::Com for specifications on the
45
+ # transmiting of messages.
46
+ class Message
47
+ attr :original_char_string,
48
+ :ref,
49
+ :sen1,
50
+ :sen2,
51
+ :flow,
52
+ :pcb_temp,
53
+ :time,
54
+ :status,
55
+ :battery
56
+
57
+ ###
58
+ # @param data [String] conents between the `STX` "\x02"
59
+ # and the `ETX` "0x03"
60
+ def initialize data
61
+ raise "invalid data" unless data_valid? data
62
+ @original_char_string = data
63
+ parse_data( data[7..-1])
64
+ end
65
+
66
+ private
67
+ def data_valid? d
68
+ crc = d[-1]
69
+ data = d[1..-2]
70
+ len = d[0]
71
+ (data ^ len).byte == crc.byte
72
+ end
73
+ def parse_data d
74
+ b = d.bytes
75
+ @ref = d[0..2].unpack("v")[0]
76
+ @sen1 = d[3..5].unpack("v")[0]
77
+ @sen2 = d[6..8].unpack("v")[0]
78
+ @flow = d[9..10].unpack("v")[0]
79
+ @pcb_temp = b[11]
80
+ @time = Time.new ('20' + b[12].to_s).to_i,
81
+ b[13],
82
+ b[14],
83
+ b[15],
84
+ b[16],
85
+ b[17]
86
+ @status = b[18]
87
+ @battery = d[19..20].unpack("v")[0]
88
+ end
89
+ end
90
+
91
+
92
+ ##
93
+ # Initializes a link between the the system and the device.
94
+ # used to transmit and recieive MicroAeth::Message
95
+ #
96
+ class Com
97
+ attr_accessor :com, :messages
98
+ attr_reader :com_thread
99
+
100
+ def initialize
101
+ port = '/dev/serial/by-id/usb-AethLabs_microAeth_Model_AE51_AE51-S4-649-1303-if00-port0'
102
+ baud = 500_000
103
+ bytesize = 8
104
+ stopbits = 1
105
+ parity = SerialPort::MARK
106
+ @com = SerialPort.new port, baud, bytesize, stopbits, parity
107
+ @messages = []
108
+ end
109
+
110
+ ###
111
+ # @m The message to be written
112
+ def write instruction
113
+ data = MicroAeth::Instruction::M + instruction
114
+ len = data.length.chr
115
+ crc = data ^ len
116
+ @com.write (MicroAeth::Instruction::STX + len + data + crc + MicroAeth::Instruction::ETX).force_encoding("ASCII-8BIT")
117
+ end
118
+
119
+ def erase_flash
120
+ begin
121
+ clear_buffer
122
+ write MicroAeth::Instruction::EraseFlash
123
+ Timeout::timeout(60) { wait_for_acknowledge }
124
+ sleep 45
125
+ Timeout::timeout(60) { wait_for_acknowledge }
126
+ write MicroAeth::Instruction::StartWrite
127
+ Timeout::timeout(60) { wait_for_acknowledge }
128
+ rescue Timeout::Error
129
+ retry
130
+ end
131
+ end
132
+ def clear_buffer
133
+ begin
134
+ while true
135
+ Timeout::timeout(0.5) { read_message }
136
+ end
137
+ rescue Timeout::Error
138
+ nil
139
+ end
140
+ end
141
+
142
+ def wait_for_acknowledge
143
+ while read_message != "\u0006AE5X:A\u0014".force_encoding("ASCII-8BIT")
144
+ nil
145
+ end
146
+ end
147
+
148
+ def start
149
+ puts "The MicroAeth is starting!.."
150
+ begin
151
+ clear_buffer
152
+ rescue [EOFError, Timeout::Error]
153
+ raise "Problem stating the MicroAeth"
154
+ end
155
+ end
156
+
157
+ ##
158
+ # @return A ruby thread which continually reads
159
+ # from the MicroAeth::Com#com instance
160
+ def read
161
+ @com_thread = Thread.new do
162
+ begin
163
+ while true
164
+ @messages << ( Message.new read_message )
165
+ end
166
+ # Intermitently, it the serialport library raises end of file...
167
+ rescue EOFError
168
+ sleep 1
169
+ retry
170
+ end
171
+ end
172
+ end
173
+
174
+ ###
175
+ # @file a ruby file object
176
+ def start_write_to_file file_name
177
+ @stop_writing_to_file = false
178
+ @thread = Thread.new do
179
+ clear_buffer
180
+ m_prev = nil
181
+ while @stop_writing_to_file != true
182
+ begin
183
+ m = Message.new read_message
184
+ rescue RuntimeError
185
+ retry
186
+ end
187
+ erase_flash if m.status == 64
188
+ atn = Math.log( m.ref.to_f / m.sen1.to_f) * 100
189
+ file = File.new file_name, 'a'
190
+ print message = [Time.now, m.ref, m.sen1, atn, m.flow, m.pcb_temp, m.status, m.battery, sigma_ap( m, m_prev)].join(',') + "\n"
191
+ file << message
192
+ file.close
193
+ m_prev = m
194
+ end
195
+ end
196
+ end
197
+ def stop_write_to_file
198
+ @stop_writing_to_file = true
199
+ @thread.join 30
200
+ end
201
+
202
+ def sigma_ap m, m_prev
203
+ if m_prev.nil?
204
+ "NaN"
205
+ else
206
+ Math::PI * (0.3 ** 2) / 4.0 / m.flow.to_f * 60.0 *
207
+ Math.log( m_prev.sen1.to_f / m.sen1.to_f * m.ref.to_f / m_prev.ref.to_f) * (10.0 ** 8)
208
+ end
209
+ end
210
+ def read_message
211
+ m, c = '',''
212
+ while c != "\x02"; c = @com.readchar; end
213
+ c = @com.readchar
214
+ m << c
215
+ len = c.byte
216
+ 0.upto len do |i|
217
+ c = @com.readchar
218
+ m << c
219
+ end
220
+ while c != "\x03"
221
+ c = @com.readchar
222
+ m << c
223
+ end
224
+ m[0..-2]
225
+ end
226
+ end
227
+ end
228
+
229
+ =begin
230
+ You'll need to assemble a properly formed message, or it won't respond.
231
+ ## Properly forming a messages as suggested by Karl Walter
232
+
233
+ Communication protocol is based on folowing syntax:
234
+ `STX LEN DATA CRC ETX` where:
235
+
236
+ * `STX` is one byte 0x02 (HEX values)
237
+ * `LEN` is one byte lenght of `DATA`
238
+ * `CRC` is XOR function between `LEN` byte and `DATA` bytes
239
+ * I'm assuming this is the last byte of data
240
+ * `ETX` is one byte 0x03
241
+
242
+ Every string of `DATA` that microAethCOM PC
243
+ software sends starts with `AE5X:` followed by one letter.
244
+
245
+ So you need to write some code to take the data you
246
+ want to send it, add the `STX` (`0x02`), calculate the
247
+ `LEN` and add it, Calculate the `CRC`, add that, then finally
248
+ add the `ETX` (`0x03`).
249
+
250
+ The `CRC` is always the hardest to get to work.
251
+ `CRC` is `XOR` function between `LEN` byte and `DATA` bytes.
252
+ http://en.wikipedia.org/wiki/Bitwise_operation#XOR
253
+ You'll probably have to make a best guess as how to `XOR` the `DATA` and `LEN`,
254
+ then try it on the messages that the MicroAeth sends, and see if you get the
255
+ `CRC` that it produced.
256
+
257
+ The `LEN` in the messages from it seemed like they where one longer than the
258
+ number of data bytes, so you'll have to experiment with that.
259
+
260
+ Also the `LEN` is only 1 byte, and the `DATA` can be any number, so I think you
261
+ are suppose to `XOR` the `LEN` with the first `DATA` byte, then take that and
262
+ XOR with the second, and so on, sort of like Xmodem. I'm not sure which is the
263
+ first `DATA` byte, though.
264
+
265
+ This may help: http://crcmod.sourceforge.net/crcmod.html
266
+
267
+ Also just google for `XOR CRC`, finds some good stuff like
268
+ [this](http://stackoverflow.com/questions/344961/how-do-you-compute-the-xor-remainder-used-in-crc)
269
+
270
+ You should also make sure that when you send /x02 that it sends 00000010 not
271
+
272
+ 01011100 01111000 00110000 00110010.
273
+
274
+ # from http://aethlabs.com/sites/all/content/microaeth/microAeth%20Model%20AE51%20Operating%20Manual.pdf
275
+ - Data(index)
276
+ - Data(index+1)
277
+ - Data(index+2)
278
+ - ‘Sen1
279
+ - Data(index+3)
280
+ - Data(index+4)
281
+ - Data(index+5)
282
+ - ‘Sen2
283
+ - Data(index+6)
284
+ - Data(index+7)
285
+ - Data(index+8)
286
+ - ‘Flow
287
+ - Data(index+9)
288
+ - Data(index+10)
289
+ - ‘PCBTemp
290
+ - Data(index+11)
291
+ - ‘Date
292
+ - Data(index+12)
293
+ - Data(index+13)
294
+ - Data(index+14)
295
+ - ‘Time
296
+ - Data(index+15)
297
+ - Data(index+16)
298
+ - Data(index+17)
299
+ - ‘Status
300
+ - Data(index+18)
301
+ - ‘Battery
302
+ - Data(index+19)
303
+ - Data(index+20)
304
+ - ‘Reserved forGPS etc...
305
+ - Data(index+21)
306
+ - Data(index+22)
307
+ - Data(index+23)
308
+ - Data(index+24)
309
+ - Data(index+25)
310
+ - Data(index+26)
311
+ - Data(index+27)
312
+ - Data(index+28)
313
+ - Data(index+29)
314
+ - Data(index+30)
315
+
316
+ Acknowledge: "\u0006AE5X:A\u0014"
317
+ =end
@@ -0,0 +1,8 @@
1
+ module MicroAethAE51
2
+ major = 0
3
+ minor = 0
4
+ tiny = 1
5
+ #pre = ""
6
+
7
+ VERSION = [major, minor, tiny].compact.join('.')
8
+ end
metadata ADDED
@@ -0,0 +1,92 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: micro_aeth-ae51-ruby
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Kurt R. Rudolph
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-10-10 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: serialport
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ~>
32
+ - !ruby/object:Gem::Version
33
+ version: '2.8'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ~>
39
+ - !ruby/object:Gem::Version
40
+ version: '2.8'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rdoc
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ~>
46
+ - !ruby/object:Gem::Version
47
+ version: '3.2'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ~>
53
+ - !ruby/object:Gem::Version
54
+ version: '3.2'
55
+ description: This Gem provides and easy to use API for sending and receiving data
56
+ and commands for the microAeth model AE51. This library is not complete but encompasses
57
+ the most common commands for interfacing with the device.
58
+ email:
59
+ - kurt@rudycomputing.io
60
+ executables: []
61
+ extensions: []
62
+ extra_rdoc_files: []
63
+ files:
64
+ - lib/micro_aeth-ae51/version.rb
65
+ - lib/micro_aeth-ae51.rb
66
+ homepage: https://github.com/RudyComputing/microAeth-AE51-Ruby
67
+ licenses:
68
+ - MIT
69
+ metadata: {}
70
+ post_install_message:
71
+ rdoc_options: []
72
+ require_paths:
73
+ - lib
74
+ required_ruby_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - '>='
77
+ - !ruby/object:Gem::Version
78
+ version: 2.0.0
79
+ required_rubygems_version: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - '>='
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ requirements:
85
+ - a microAeth model AE51
86
+ rubyforge_project:
87
+ rubygems_version: 2.0.3
88
+ signing_key:
89
+ specification_version: 4
90
+ summary: Ruby API for AethLabs microAeth&reg; model AE51
91
+ test_files: []
92
+ has_rdoc: