ruby_astm 1.4.3 → 1.4.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
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1edecd39318ba2231234a0bd46de36f2eded3843
|
4
|
+
data.tar.gz: c0da0a6d63ec31c478b083ecbf11c5772f709ab9
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b4ad9ac1b9db8eedcddf90db7fb09a2b8868388f8268591b7273900e66f4baeebf447dc93ec4772398fd87928b5edf2f591d20d895daa12a5db16e7ace0d678
|
7
|
+
data.tar.gz: 72c2afa43a44ae1d6c20ea21e26e8d9ea3cd357495c291a08694fdc1d0f65289b23b5c0e5ec5b296bf9731ddc667bd6fb9aac8c849a0ed90c467cbf6b6fc9f0d
|
data/lib/ruby_astm.rb
CHANGED
@@ -17,5 +17,6 @@ require_relative "ruby_astm/HL7/hl7_header"
|
|
17
17
|
require_relative "ruby_astm/HL7/hl7_patient"
|
18
18
|
require_relative "ruby_astm/HL7/hl7_order"
|
19
19
|
require_relative "ruby_astm/HL7/hl7_observation"
|
20
|
+
require_relative "ruby_astm/custom/siemens_abg_electrolyte_module"
|
20
21
|
require_relative "ruby_astm/custom/siemens_abg_electrolyte_server"
|
21
22
|
|
@@ -9,27 +9,6 @@ require "rest-firebase"
|
|
9
9
|
class AstmServer
|
10
10
|
|
11
11
|
include LabInterface
|
12
|
-
|
13
|
-
|
14
|
-
def self.log(message)
|
15
|
-
puts "" + message
|
16
|
-
$redis.zadd("ruby_astm_log",Time.now.to_i,message)
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.root_path
|
20
|
-
File.dirname __dir__
|
21
|
-
end
|
22
|
-
|
23
|
-
def self.default_mappings
|
24
|
-
File.join AstmServer.root_path,"mappings.json"
|
25
|
-
end
|
26
|
-
|
27
|
-
$ENQ = "[5]"
|
28
|
-
$start_text = "[2]"
|
29
|
-
$end_text = "[3]"
|
30
|
-
$record_end = "[13]"
|
31
|
-
$frame_end = "[10]"
|
32
|
-
|
33
12
|
|
34
13
|
## DEFAULT SERIAL PORT : /dev/ttyS0
|
35
14
|
## DEFAULT USB PORT : /dev/ttyUSB0
|
@@ -38,7 +17,7 @@ class AstmServer
|
|
38
17
|
#def initialize(server_ip=nil,server_port=nil,mpg=nil,respond_to_queries=false,serial_port='/dev/ttyS0',usb_port='/dev/ttyUSB0',serial_baud=9600,serial_parity=8,usb_baud=19200,usb_parity=8)
|
39
18
|
def initialize(ethernet_connections,serial_connections,mpg=nil,respond_to_queries=nil)
|
40
19
|
$redis = Redis.new
|
41
|
-
|
20
|
+
self.class.log("Initializing AstmServer")
|
42
21
|
self.ethernet_connections = ethernet_connections
|
43
22
|
self.serial_connections = serial_connections
|
44
23
|
self.server_ip = server_ip || "127.0.0.1"
|
@@ -50,7 +29,7 @@ class AstmServer
|
|
50
29
|
self.usb_port = usb_port
|
51
30
|
self.usb_baud = usb_baud
|
52
31
|
self.usb_parity = usb_parity
|
53
|
-
$mappings = JSON.parse(IO.read(mpg ||
|
32
|
+
$mappings = JSON.parse(IO.read(mpg || self.class.default_mappings))
|
54
33
|
end
|
55
34
|
|
56
35
|
def start_server
|
@@ -59,7 +38,7 @@ class AstmServer
|
|
59
38
|
raise "please provide a valid ethernet configuration with ip address" unless econn[:server_ip]
|
60
39
|
raise "please provide a valid ethernet configuration with port" unless econn[:server_port]
|
61
40
|
EventMachine::start_server econn[:server_ip], econn[:server_port], LabInterface
|
62
|
-
|
41
|
+
self.class.log("Running ETHERNET with configuration #{econn}")
|
63
42
|
end
|
64
43
|
self.serial_connections.each do |sconn|
|
65
44
|
raise "please provide a valid serial configuration with port address" unless sconn[:port_address]
|
@@ -0,0 +1,322 @@
|
|
1
|
+
module SiemensAbgElectrolyteModule
|
2
|
+
|
3
|
+
include LabInterface
|
4
|
+
|
5
|
+
def self.included base
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
SIEMENS_ELECTROLYTE_END = [10,10,10,10]
|
11
|
+
ELECTROLYTE_START = [45, 45, 45, 32]
|
12
|
+
attr_accessor :current_text_segment
|
13
|
+
|
14
|
+
def get_po2
|
15
|
+
m = []
|
16
|
+
self.current_text_segment.scan(/pO2\s+(?<k>(\d+)(\.\d)*)(\^|v)?\s+mmHg/) do |l|
|
17
|
+
n = Regexp.last_match
|
18
|
+
m << n[:k].to_s
|
19
|
+
end
|
20
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
21
|
+
return m[0] if m.size == 1
|
22
|
+
return nil
|
23
|
+
end
|
24
|
+
|
25
|
+
def get_pco2
|
26
|
+
m = []
|
27
|
+
self.current_text_segment.scan(/pCO2\s+(?<k>(\d+)(\.\d)*)(\^|v)?\s+mmHg/) do |l|
|
28
|
+
n = Regexp.last_match
|
29
|
+
m << n[:k].to_s
|
30
|
+
end
|
31
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
32
|
+
return m[0] if m.size == 1
|
33
|
+
return nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_ph
|
37
|
+
m = []
|
38
|
+
self.current_text_segment.scan(/pH\s+(?<k>(\d+)[\.\d]*)(\^|v)?\s+$/) do |l|
|
39
|
+
n = Regexp.last_match
|
40
|
+
m << n[:k].to_s
|
41
|
+
end
|
42
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
43
|
+
return m[0] if m.size == 1
|
44
|
+
return nil
|
45
|
+
end
|
46
|
+
|
47
|
+
def get_na
|
48
|
+
m = []
|
49
|
+
self.current_text_segment.scan(/Na\+\s+(?<k>(\d+)[\.\d]*)(\^|v)?\s+mmol\/L/) do |l|
|
50
|
+
n = Regexp.last_match
|
51
|
+
m << n[:k].to_s
|
52
|
+
end
|
53
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
54
|
+
return m[0] if m.size == 1
|
55
|
+
return nil
|
56
|
+
end
|
57
|
+
|
58
|
+
def get_k
|
59
|
+
m = []
|
60
|
+
self.current_text_segment.scan(/K\+\s+(?<k>(\d+)[\.\d]*)(\^|v)?\s+mmol\/L/) do |l|
|
61
|
+
n = Regexp.last_match
|
62
|
+
m << n[:k].to_s
|
63
|
+
end
|
64
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
65
|
+
return m[0] if m.size == 1
|
66
|
+
return nil
|
67
|
+
end
|
68
|
+
|
69
|
+
def get_cl
|
70
|
+
m = []
|
71
|
+
self.current_text_segment.scan(/Cl\-\s+(?<k>(\d+)[\.\d]*)(\^|v)?\s+mmol\/L/) do |l|
|
72
|
+
n = Regexp.last_match
|
73
|
+
m << n[:k].to_s
|
74
|
+
end
|
75
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
76
|
+
return m[0] if m.size == 1
|
77
|
+
return nil
|
78
|
+
end
|
79
|
+
|
80
|
+
def get_patient_id
|
81
|
+
m = []
|
82
|
+
self.current_text_segment.scan(/Patient\s+ID\s+(?<k>\d+)$/) do |l|
|
83
|
+
n = Regexp.last_match
|
84
|
+
m << n[:k].to_s
|
85
|
+
end
|
86
|
+
raise "more than one result #{m.to_s}" if (m.size > 1)
|
87
|
+
return m[0] if m.size == 1
|
88
|
+
return nil
|
89
|
+
end
|
90
|
+
|
91
|
+
## we override the lab interface methods
|
92
|
+
## and we don't pollute the lab interface itself.
|
93
|
+
## as this is a custom analyzer.
|
94
|
+
## @param[Array] :
|
95
|
+
## [[bytes],[bytes]....]
|
96
|
+
def process_electrolytes(data_bytes)
|
97
|
+
#puts "came to process electrolytes_plain_text"
|
98
|
+
byte_arr = data_bytes.flatten
|
99
|
+
#puts "the end part of the arr is"
|
100
|
+
return if byte_arr[-4..-1] != SIEMENS_ELECTROLYTE_END
|
101
|
+
self.data_bytes = []
|
102
|
+
concat = ""
|
103
|
+
byte_arr.each do |byte|
|
104
|
+
x = [byte].pack('c*').force_encoding('UTF-8')
|
105
|
+
if x == "\r"
|
106
|
+
concat+="\n"
|
107
|
+
elsif x == "\n"
|
108
|
+
#puts "new line found --- "
|
109
|
+
concat+=x
|
110
|
+
#puts "last thing in concat."
|
111
|
+
#puts concat[-1].to_s
|
112
|
+
else
|
113
|
+
concat+=x
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
self.headers ||= [Header.new]
|
118
|
+
concat.split("--------------------------------").each do |record|
|
119
|
+
|
120
|
+
self.current_text_segment = record
|
121
|
+
if patient_id = get_patient_id
|
122
|
+
self.headers[-1].patients ||= []
|
123
|
+
p = Patient.new
|
124
|
+
p.patient_id = patient_id
|
125
|
+
p.orders ||= []
|
126
|
+
o = Order.new
|
127
|
+
o.results ||= {}
|
128
|
+
if sodium = get_na
|
129
|
+
r = Result.new
|
130
|
+
r.name = "SNATRIUM"
|
131
|
+
r.report_name = "Serum Electrolytes"
|
132
|
+
r.value = sodium
|
133
|
+
r.units = "mmol/L"
|
134
|
+
r.timestamp = Time.now.to_i
|
135
|
+
o.results["SNATRIUM"] = r
|
136
|
+
end
|
137
|
+
|
138
|
+
if potassium = get_k
|
139
|
+
r = Result.new
|
140
|
+
r.name = "SPOTASSIUM"
|
141
|
+
r.report_name = "Serum Electrolytes"
|
142
|
+
r.value = potassium
|
143
|
+
r.units = "mmol/L"
|
144
|
+
r.timestamp = Time.now.to_i
|
145
|
+
o.results["SPOTASSIUM"] = r
|
146
|
+
end
|
147
|
+
|
148
|
+
if chloride = get_cl
|
149
|
+
r = Result.new
|
150
|
+
r.name = "SCHLORIDE"
|
151
|
+
r.report_name = "Serum Electrolytes"
|
152
|
+
r.value = chloride
|
153
|
+
r.units = "mmol/L"
|
154
|
+
r.timestamp = Time.now.to_i
|
155
|
+
o.results["SCHLORIDE"] = r
|
156
|
+
end
|
157
|
+
|
158
|
+
if ph = get_ph
|
159
|
+
r = Result.new
|
160
|
+
r.name = "pH"
|
161
|
+
r.report_name = "Serum Electrolytes"
|
162
|
+
r.value = ph
|
163
|
+
r.units = "mmol/L"
|
164
|
+
r.timestamp = Time.now.to_i
|
165
|
+
o.results["pH"] = r
|
166
|
+
end
|
167
|
+
|
168
|
+
if po2 = get_po2
|
169
|
+
r = Result.new
|
170
|
+
r.name = "po2"
|
171
|
+
r.report_name = "Serum Electrolytes"
|
172
|
+
r.value = po2
|
173
|
+
r.units = "mmHg"
|
174
|
+
r.timestamp = Time.now.to_i
|
175
|
+
o.results["po2"] = r
|
176
|
+
end
|
177
|
+
|
178
|
+
if pco2 = get_pco2
|
179
|
+
r = Result.new
|
180
|
+
r.name = "pco2"
|
181
|
+
r.report_name = "Serum Electrolytes"
|
182
|
+
r.value = pco2
|
183
|
+
r.units = "mmHg"
|
184
|
+
r.timestamp = Time.now.to_i
|
185
|
+
o.results["pco2"] = r
|
186
|
+
end
|
187
|
+
|
188
|
+
p.orders << o
|
189
|
+
self.headers[-1].patients << p
|
190
|
+
end
|
191
|
+
end
|
192
|
+
|
193
|
+
end
|
194
|
+
|
195
|
+
def process_text_file(full_file_path)
|
196
|
+
k = IO.read(full_file_path)
|
197
|
+
process_electrolytes(k.bytes)
|
198
|
+
end
|
199
|
+
|
200
|
+
|
201
|
+
def receive_data(data)
|
202
|
+
|
203
|
+
|
204
|
+
begin
|
205
|
+
|
206
|
+
|
207
|
+
self.data_buffer ||= ''
|
208
|
+
|
209
|
+
concat = ""
|
210
|
+
|
211
|
+
byte_arr = data.bytes.to_a
|
212
|
+
|
213
|
+
self.test_data_bytes ||= []
|
214
|
+
|
215
|
+
self.data_bytes ||= []
|
216
|
+
|
217
|
+
self.test_data_bytes.push(byte_arr)
|
218
|
+
|
219
|
+
self.data_bytes.push(byte_arr)
|
220
|
+
|
221
|
+
|
222
|
+
concat = pre_process_bytes(byte_arr,concat)
|
223
|
+
|
224
|
+
#puts "concat is:"
|
225
|
+
|
226
|
+
#puts concat.to_s
|
227
|
+
|
228
|
+
self.data_buffer << concat
|
229
|
+
|
230
|
+
## if the last byte is EOT, then call process text.
|
231
|
+
## inside that split by line and process one at a time.
|
232
|
+
##process_text(concat)
|
233
|
+
#puts "data bytes -1: #{self.data_bytes[-1]}"
|
234
|
+
#puts "data bytes 0: #{self.data_bytes[0]}"
|
235
|
+
#if self.data_bytes[0] == ELECTROLYTE_START
|
236
|
+
self.process_electrolytes(self.data_bytes)
|
237
|
+
#end
|
238
|
+
=begin
|
239
|
+
if data.bytes.to_a[-1] == 4
|
240
|
+
puts "GOT EOT --- PROCESSING BUFFER, AND CLEARING."
|
241
|
+
process_text(self.data_buffer)
|
242
|
+
#root_path = File.dirname __dir
|
243
|
+
#puts "root path #{root_path}"
|
244
|
+
#IO.write((File.join root_path,'test','resources','roche_multi_frame_bytes.txt'),self.test_data_bytes.to_s)
|
245
|
+
#puts self.test_data_bytes.flatten.to_s
|
246
|
+
self.data_buffer = ''
|
247
|
+
unless self.headers.blank?
|
248
|
+
if self.headers[-1].queries.blank?
|
249
|
+
#puts "no queries in header so sending ack after getting EOT and processing the buffer"
|
250
|
+
send_data(ACK)
|
251
|
+
else
|
252
|
+
#puts "sending ENQ"
|
253
|
+
send_data(ENQ)
|
254
|
+
end
|
255
|
+
else
|
256
|
+
puts "sending catch all --------------- ACK --------------"
|
257
|
+
send_data(ACK)
|
258
|
+
end
|
259
|
+
elsif data.bytes.to_a[0] == 6
|
260
|
+
puts "GOT ACK --- GENERATING RESPONSE"
|
261
|
+
unless self.headers.blank?
|
262
|
+
header_responses = self.headers[-1].build_one_response({machine_name: self.headers[-1].machine_name})
|
263
|
+
## if no queries then, we have to send ack.
|
264
|
+
if header_responses.blank?
|
265
|
+
#puts "sending ACK since there are no queries in the header"
|
266
|
+
send_data(ACK)
|
267
|
+
end
|
268
|
+
header_responses.each_with_index {|response,key|
|
269
|
+
message_checksum = checksum(response + terminator + ETX)
|
270
|
+
final_resp = STX + response + terminator + ETX + message_checksum + "\r"
|
271
|
+
final_resp_arr = final_resp.bytes.to_a
|
272
|
+
final_resp_arr << 10
|
273
|
+
if (self.headers[-1].response_sent == false)
|
274
|
+
#puts "sending the data as follows----------------------------------------------"
|
275
|
+
#puts "response sent is:"
|
276
|
+
#puts self.headers[-1].response_sent
|
277
|
+
#puts final_resp_arr.pack('c*').gsub(/\r/,'\n')
|
278
|
+
send_data(final_resp_arr.pack('c*'))
|
279
|
+
self.headers[-1].response_sent = true if (key == (header_responses.size - 1))
|
280
|
+
else
|
281
|
+
#puts "sending EOT"
|
282
|
+
send_data(EOT)
|
283
|
+
end
|
284
|
+
}
|
285
|
+
else
|
286
|
+
#puts "NO HEADERS PRESENT --- "
|
287
|
+
end
|
288
|
+
elsif data.bytes.to_a[0] == 255
|
289
|
+
puts " ----------- got 255 data -----------, not sending anything back. "
|
290
|
+
else
|
291
|
+
#unless self.data_buffer.blank?
|
292
|
+
# puts self.data_buffer.gsub(/\r/,'\n').to_s
|
293
|
+
#end
|
294
|
+
## send the header
|
295
|
+
#puts "--------- SENT ACK -----------"
|
296
|
+
## strip non utf 8 characters from it.
|
297
|
+
self.data_buffer.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
298
|
+
if self.data_buffer =~ /MSH\|/
|
299
|
+
#puts " -------------- HEADERS ARE BLANK WITH HL7, sending ack. ------------ "
|
300
|
+
process_text(self.data_buffer)
|
301
|
+
self.data_buffer = ''
|
302
|
+
if self.headers.size > 0
|
303
|
+
self.headers[-1].commit
|
304
|
+
send_data(self.headers[-1].generate_ack_success_response)
|
305
|
+
end
|
306
|
+
else
|
307
|
+
#puts " -------------- HEADERS ARE BLANK NOT HL7, sending ack. ------------ "
|
308
|
+
send_data(ACK)
|
309
|
+
end
|
310
|
+
end
|
311
|
+
=end
|
312
|
+
rescue => e
|
313
|
+
|
314
|
+
#self.headers = []
|
315
|
+
AstmServer.log("data was: " + self.data_buffer + "error is:" + e.backtrace.to_s)
|
316
|
+
#send_data(EOT)
|
317
|
+
end
|
318
|
+
|
319
|
+
end
|
320
|
+
|
321
|
+
|
322
|
+
end
|
@@ -1,315 +1,46 @@
|
|
1
|
-
class SiemensAbgElectrolyteServer
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
self.
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
end
|
46
|
-
raise "more than one result #{m.to_s}" if (m.size > 1)
|
47
|
-
return m[0] if m.size == 1
|
48
|
-
return nil
|
49
|
-
end
|
50
|
-
|
51
|
-
def get_k
|
52
|
-
m = []
|
53
|
-
self.current_text_segment.scan(/K\+\s+(?<k>(\d+)[\.\d]*)(\^|v)?\s+mmol\/L/) do |l|
|
54
|
-
n = Regexp.last_match
|
55
|
-
m << n[:k].to_s
|
56
|
-
end
|
57
|
-
raise "more than one result #{m.to_s}" if (m.size > 1)
|
58
|
-
return m[0] if m.size == 1
|
59
|
-
return nil
|
60
|
-
end
|
61
|
-
|
62
|
-
def get_cl
|
63
|
-
m = []
|
64
|
-
self.current_text_segment.scan(/Cl\-\s+(?<k>(\d+)[\.\d]*)(\^|v)?\s+mmol\/L/) do |l|
|
65
|
-
n = Regexp.last_match
|
66
|
-
m << n[:k].to_s
|
67
|
-
end
|
68
|
-
raise "more than one result #{m.to_s}" if (m.size > 1)
|
69
|
-
return m[0] if m.size == 1
|
70
|
-
return nil
|
71
|
-
end
|
72
|
-
|
73
|
-
def get_patient_id
|
74
|
-
m = []
|
75
|
-
self.current_text_segment.scan(/Patient\s+ID\s+(?<k>\d+)$/) do |l|
|
76
|
-
n = Regexp.last_match
|
77
|
-
m << n[:k].to_s
|
78
|
-
end
|
79
|
-
raise "more than one result #{m.to_s}" if (m.size > 1)
|
80
|
-
return m[0] if m.size == 1
|
81
|
-
return nil
|
82
|
-
end
|
83
|
-
|
84
|
-
## we override the lab interface methods
|
85
|
-
## and we don't pollute the lab interface itself.
|
86
|
-
## as this is a custom analyzer.
|
87
|
-
## @param[Array] :
|
88
|
-
## [[bytes],[bytes]....]
|
89
|
-
def process_electrolytes(data_bytes)
|
90
|
-
#puts "came to process electrolytes_plain_text"
|
91
|
-
byte_arr = data_bytes.flatten
|
92
|
-
#puts "the end part of the arr is"
|
93
|
-
return if byte_arr[-4..-1] != SIEMENS_ELECTROLYTE_END
|
94
|
-
self.data_bytes = []
|
95
|
-
concat = ""
|
96
|
-
byte_arr.each do |byte|
|
97
|
-
x = [byte].pack('c*').force_encoding('UTF-8')
|
98
|
-
if x == "\r"
|
99
|
-
concat+="\n"
|
100
|
-
elsif x == "\n"
|
101
|
-
#puts "new line found --- "
|
102
|
-
concat+=x
|
103
|
-
#puts "last thing in concat."
|
104
|
-
#puts concat[-1].to_s
|
105
|
-
else
|
106
|
-
concat+=x
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
self.headers ||= [Header.new]
|
111
|
-
concat.split("--------------------------------").each do |record|
|
112
|
-
|
113
|
-
self.current_text_segment = record
|
114
|
-
if patient_id = get_patient_id
|
115
|
-
self.headers[-1].patients ||= []
|
116
|
-
p = Patient.new
|
117
|
-
p.patient_id = patient_id
|
118
|
-
p.orders ||= []
|
119
|
-
o = Order.new
|
120
|
-
o.results ||= {}
|
121
|
-
if sodium = get_na
|
122
|
-
r = Result.new
|
123
|
-
r.name = "SNATRIUM"
|
124
|
-
r.report_name = "Serum Electrolytes"
|
125
|
-
r.value = sodium
|
126
|
-
r.units = "mmol/L"
|
127
|
-
r.timestamp = Time.now.to_i
|
128
|
-
o.results["SNATRIUM"] = r
|
129
|
-
end
|
130
|
-
|
131
|
-
if potassium = get_k
|
132
|
-
r = Result.new
|
133
|
-
r.name = "SPOTASSIUM"
|
134
|
-
r.report_name = "Serum Electrolytes"
|
135
|
-
r.value = potassium
|
136
|
-
r.units = "mmol/L"
|
137
|
-
r.timestamp = Time.now.to_i
|
138
|
-
o.results["SPOTASSIUM"] = r
|
139
|
-
end
|
140
|
-
|
141
|
-
if chloride = get_cl
|
142
|
-
r = Result.new
|
143
|
-
r.name = "SCHLORIDE"
|
144
|
-
r.report_name = "Serum Electrolytes"
|
145
|
-
r.value = chloride
|
146
|
-
r.units = "mmol/L"
|
147
|
-
r.timestamp = Time.now.to_i
|
148
|
-
o.results["SCHLORIDE"] = r
|
149
|
-
end
|
150
|
-
|
151
|
-
if ph = get_ph
|
152
|
-
r = Result.new
|
153
|
-
r.name = "pH"
|
154
|
-
r.report_name = "Serum Electrolytes"
|
155
|
-
r.value = ph
|
156
|
-
r.units = "mmol/L"
|
157
|
-
r.timestamp = Time.now.to_i
|
158
|
-
o.results["pH"] = r
|
159
|
-
end
|
160
|
-
|
161
|
-
if po2 = get_po2
|
162
|
-
r = Result.new
|
163
|
-
r.name = "po2"
|
164
|
-
r.report_name = "Serum Electrolytes"
|
165
|
-
r.value = po2
|
166
|
-
r.units = "mmHg"
|
167
|
-
r.timestamp = Time.now.to_i
|
168
|
-
o.results["po2"] = r
|
169
|
-
end
|
170
|
-
|
171
|
-
if pco2 = get_pco2
|
172
|
-
r = Result.new
|
173
|
-
r.name = "pco2"
|
174
|
-
r.report_name = "Serum Electrolytes"
|
175
|
-
r.value = pco2
|
176
|
-
r.units = "mmHg"
|
177
|
-
r.timestamp = Time.now.to_i
|
178
|
-
o.results["pco2"] = r
|
179
|
-
end
|
180
|
-
|
181
|
-
p.orders << o
|
182
|
-
self.headers[-1].patients << p
|
183
|
-
end
|
184
|
-
end
|
185
|
-
|
186
|
-
end
|
187
|
-
|
188
|
-
def process_text_file(full_file_path)
|
189
|
-
k = IO.read(full_file_path)
|
190
|
-
process_electrolytes(k.bytes)
|
191
|
-
end
|
192
|
-
|
193
|
-
|
194
|
-
def receive_data(data)
|
195
|
-
|
196
|
-
|
197
|
-
begin
|
198
|
-
|
199
|
-
|
200
|
-
self.data_buffer ||= ''
|
201
|
-
|
202
|
-
concat = ""
|
203
|
-
|
204
|
-
byte_arr = data.bytes.to_a
|
205
|
-
|
206
|
-
self.test_data_bytes ||= []
|
207
|
-
|
208
|
-
self.data_bytes ||= []
|
209
|
-
|
210
|
-
self.test_data_bytes.push(byte_arr)
|
211
|
-
|
212
|
-
self.data_bytes.push(byte_arr)
|
213
|
-
|
214
|
-
|
215
|
-
concat = pre_process_bytes(byte_arr,concat)
|
216
|
-
|
217
|
-
#puts "concat is:"
|
218
|
-
|
219
|
-
#puts concat.to_s
|
220
|
-
|
221
|
-
self.data_buffer << concat
|
222
|
-
|
223
|
-
## if the last byte is EOT, then call process text.
|
224
|
-
## inside that split by line and process one at a time.
|
225
|
-
##process_text(concat)
|
226
|
-
#puts "data bytes -1: #{self.data_bytes[-1]}"
|
227
|
-
#puts "data bytes 0: #{self.data_bytes[0]}"
|
228
|
-
#if self.data_bytes[0] == ELECTROLYTE_START
|
229
|
-
self.process_electrolytes(self.data_bytes)
|
230
|
-
#end
|
231
|
-
=begin
|
232
|
-
if data.bytes.to_a[-1] == 4
|
233
|
-
puts "GOT EOT --- PROCESSING BUFFER, AND CLEARING."
|
234
|
-
process_text(self.data_buffer)
|
235
|
-
#root_path = File.dirname __dir
|
236
|
-
#puts "root path #{root_path}"
|
237
|
-
#IO.write((File.join root_path,'test','resources','roche_multi_frame_bytes.txt'),self.test_data_bytes.to_s)
|
238
|
-
#puts self.test_data_bytes.flatten.to_s
|
239
|
-
self.data_buffer = ''
|
240
|
-
unless self.headers.blank?
|
241
|
-
if self.headers[-1].queries.blank?
|
242
|
-
#puts "no queries in header so sending ack after getting EOT and processing the buffer"
|
243
|
-
send_data(ACK)
|
244
|
-
else
|
245
|
-
#puts "sending ENQ"
|
246
|
-
send_data(ENQ)
|
247
|
-
end
|
248
|
-
else
|
249
|
-
puts "sending catch all --------------- ACK --------------"
|
250
|
-
send_data(ACK)
|
251
|
-
end
|
252
|
-
elsif data.bytes.to_a[0] == 6
|
253
|
-
puts "GOT ACK --- GENERATING RESPONSE"
|
254
|
-
unless self.headers.blank?
|
255
|
-
header_responses = self.headers[-1].build_one_response({machine_name: self.headers[-1].machine_name})
|
256
|
-
## if no queries then, we have to send ack.
|
257
|
-
if header_responses.blank?
|
258
|
-
#puts "sending ACK since there are no queries in the header"
|
259
|
-
send_data(ACK)
|
260
|
-
end
|
261
|
-
header_responses.each_with_index {|response,key|
|
262
|
-
message_checksum = checksum(response + terminator + ETX)
|
263
|
-
final_resp = STX + response + terminator + ETX + message_checksum + "\r"
|
264
|
-
final_resp_arr = final_resp.bytes.to_a
|
265
|
-
final_resp_arr << 10
|
266
|
-
if (self.headers[-1].response_sent == false)
|
267
|
-
#puts "sending the data as follows----------------------------------------------"
|
268
|
-
#puts "response sent is:"
|
269
|
-
#puts self.headers[-1].response_sent
|
270
|
-
#puts final_resp_arr.pack('c*').gsub(/\r/,'\n')
|
271
|
-
send_data(final_resp_arr.pack('c*'))
|
272
|
-
self.headers[-1].response_sent = true if (key == (header_responses.size - 1))
|
273
|
-
else
|
274
|
-
#puts "sending EOT"
|
275
|
-
send_data(EOT)
|
276
|
-
end
|
277
|
-
}
|
278
|
-
else
|
279
|
-
#puts "NO HEADERS PRESENT --- "
|
280
|
-
end
|
281
|
-
elsif data.bytes.to_a[0] == 255
|
282
|
-
puts " ----------- got 255 data -----------, not sending anything back. "
|
283
|
-
else
|
284
|
-
#unless self.data_buffer.blank?
|
285
|
-
# puts self.data_buffer.gsub(/\r/,'\n').to_s
|
286
|
-
#end
|
287
|
-
## send the header
|
288
|
-
#puts "--------- SENT ACK -----------"
|
289
|
-
## strip non utf 8 characters from it.
|
290
|
-
self.data_buffer.encode!('UTF-8', 'binary', invalid: :replace, undef: :replace, replace: '')
|
291
|
-
if self.data_buffer =~ /MSH\|/
|
292
|
-
#puts " -------------- HEADERS ARE BLANK WITH HL7, sending ack. ------------ "
|
293
|
-
process_text(self.data_buffer)
|
294
|
-
self.data_buffer = ''
|
295
|
-
if self.headers.size > 0
|
296
|
-
self.headers[-1].commit
|
297
|
-
send_data(self.headers[-1].generate_ack_success_response)
|
298
|
-
end
|
299
|
-
else
|
300
|
-
#puts " -------------- HEADERS ARE BLANK NOT HL7, sending ack. ------------ "
|
301
|
-
send_data(ACK)
|
302
|
-
end
|
303
|
-
end
|
304
|
-
=end
|
305
|
-
rescue => e
|
306
|
-
|
307
|
-
#self.headers = []
|
308
|
-
AstmServer.log("data was: " + self.data_buffer + "error is:" + e.backtrace.to_s)
|
309
|
-
#send_data(EOT)
|
310
|
-
end
|
311
|
-
|
312
|
-
end
|
313
|
-
|
1
|
+
class SiemensAbgElectrolyteServer
|
2
|
+
|
3
|
+
include SiemensAbgElectrolyteModule
|
4
|
+
|
5
|
+
## DEFAULT SERIAL PORT : /dev/ttyS0
|
6
|
+
## DEFAULT USB PORT : /dev/ttyUSB0
|
7
|
+
## @param[Array] ethernet_connections : each element is expected to be a hash, with keys for :server_ip, :server_port.
|
8
|
+
## @param[Array] serial_connections : each element is expected to be a hash with port_address, baud_rate, and parity
|
9
|
+
#def initialize(server_ip=nil,server_port=nil,mpg=nil,respond_to_queries=false,serial_port='/dev/ttyS0',usb_port='/dev/ttyUSB0',serial_baud=9600,serial_parity=8,usb_baud=19200,usb_parity=8)
|
10
|
+
def initialize(ethernet_connections,serial_connections,mpg=nil,respond_to_queries=nil)
|
11
|
+
$redis = Redis.new
|
12
|
+
self.class.log("Initializing AstmServer")
|
13
|
+
self.ethernet_connections = ethernet_connections
|
14
|
+
self.serial_connections = serial_connections
|
15
|
+
self.server_ip = server_ip || "127.0.0.1"
|
16
|
+
self.server_port = server_port || 3000
|
17
|
+
self.respond_to_queries = respond_to_queries
|
18
|
+
self.serial_port = serial_port
|
19
|
+
self.serial_baud = serial_baud
|
20
|
+
self.serial_parity = serial_parity
|
21
|
+
self.usb_port = usb_port
|
22
|
+
self.usb_baud = usb_baud
|
23
|
+
self.usb_parity = usb_parity
|
24
|
+
$mappings = JSON.parse(IO.read(mpg || self.class.default_mappings))
|
25
|
+
end
|
26
|
+
|
27
|
+
def start_server
|
28
|
+
EventMachine.run {
|
29
|
+
self.ethernet_connections.each do |econn|
|
30
|
+
raise "please provide a valid ethernet configuration with ip address" unless econn[:server_ip]
|
31
|
+
raise "please provide a valid ethernet configuration with port" unless econn[:server_port]
|
32
|
+
EventMachine::start_server econn[:server_ip], econn[:server_port], SiemensAbgElectrolyteModule
|
33
|
+
self.class.log("Running ETHERNET with configuration #{econn}")
|
34
|
+
end
|
35
|
+
self.serial_connections.each do |sconn|
|
36
|
+
raise "please provide a valid serial configuration with port address" unless sconn[:port_address]
|
37
|
+
raise "please provide a valid serial configuration with baud rate" unless sconn[:baud_rate]
|
38
|
+
raise "please provide a valid serial configuration with parity" unless sconn[:parity]
|
39
|
+
EventMachine.open_serial(sconn[:port_address], sconn[:baud_rate], sconn[:parity],SiemensAbgElectrolyteModule)
|
40
|
+
puts "RUNNING SERIAL port with configuration : #{sconn}"
|
41
|
+
end
|
42
|
+
|
43
|
+
}
|
44
|
+
end
|
314
45
|
|
315
46
|
end
|
@@ -2,6 +2,10 @@ require "active_support/all"
|
|
2
2
|
|
3
3
|
module LabInterface
|
4
4
|
|
5
|
+
def self.included base
|
6
|
+
base.extend ClassMethods
|
7
|
+
end
|
8
|
+
|
5
9
|
ACK = "\x06"
|
6
10
|
ENQ = "\x05"
|
7
11
|
STX = "\x02"
|
@@ -13,7 +17,6 @@ module LabInterface
|
|
13
17
|
|
14
18
|
attr_accessor :ethernet_connections
|
15
19
|
attr_accessor :serial_connections
|
16
|
-
|
17
20
|
attr_accessor :ethernet_server
|
18
21
|
attr_accessor :server_ip
|
19
22
|
attr_accessor :server_port
|
@@ -38,7 +41,37 @@ module LabInterface
|
|
38
41
|
|
39
42
|
## buffer of incoming data.
|
40
43
|
attr_accessor :data_buffer
|
44
|
+
|
45
|
+
$ENQ = "[5]"
|
46
|
+
$start_text = "[2]"
|
47
|
+
$end_text = "[3]"
|
48
|
+
$record_end = "[13]"
|
49
|
+
$frame_end = "[10]"
|
50
|
+
|
41
51
|
|
52
|
+
#######################################################
|
53
|
+
##
|
54
|
+
##
|
55
|
+
##
|
56
|
+
## CLASS METHODS
|
57
|
+
##
|
58
|
+
##
|
59
|
+
##
|
60
|
+
#######################################################
|
61
|
+
module ClassMethods
|
62
|
+
def log(message)
|
63
|
+
puts "" + message
|
64
|
+
$redis.zadd("ruby_astm_log",Time.now.to_i,message)
|
65
|
+
end
|
66
|
+
|
67
|
+
def root_path
|
68
|
+
File.dirname __dir__
|
69
|
+
end
|
70
|
+
|
71
|
+
def default_mappings
|
72
|
+
File.join root_path,"mappings.json"
|
73
|
+
end
|
74
|
+
end
|
42
75
|
|
43
76
|
## returns the root directory of the gem.
|
44
77
|
def root
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ruby_astm
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.4.
|
4
|
+
version: 1.4.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Bhargav Raut
|
@@ -155,6 +155,7 @@ files:
|
|
155
155
|
- lib/ruby_astm/HL7/hl7_order.rb
|
156
156
|
- lib/ruby_astm/HL7/hl7_patient.rb
|
157
157
|
- lib/ruby_astm/astm_server.rb
|
158
|
+
- lib/ruby_astm/custom/siemens_abg_electrolyte_module.rb
|
158
159
|
- lib/ruby_astm/custom/siemens_abg_electrolyte_server.rb
|
159
160
|
- lib/ruby_astm/frame.rb
|
160
161
|
- lib/ruby_astm/header.rb
|