extface 0.6.1 → 0.6.2

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: 37f9b8889693d6375eda12ef08594c25c98eb453
4
- data.tar.gz: 114d8706d7eeb0b4ed151bcde9a057dbddfd8a23
3
+ metadata.gz: f16bc8f1e7ca869e7d047a48a537e929af5b4c47
4
+ data.tar.gz: 765d65dd09939aa371ed039e6b2a294a66f9de6f
5
5
  SHA512:
6
- metadata.gz: 1ed1904327764ffe78fb3a8fb5511f49fc55bf582a93ff1911c47d1a98faa7abea39841162d21e24a666af0cea5a3d00058f2e157bf72517d9b83c06fb06dafc
7
- data.tar.gz: d1e7fbf59ff3bdc5e2cd49ab8d63133402c6abde5f404fd1b84db4b3492d8d3f7d0b234c285cf40428bab6a7d0d1635c5b0f7322d85de309234498aa70502094
6
+ metadata.gz: '09bf70bedb4e4aece277206127ce886e52ff8e34d03a22b687fe1106392188ff869e2767a36f60737509a9e62d1c578260c14c22179db31e642efdc45b073a14'
7
+ data.tar.gz: 829d396c2765c2b7c4bd88dd552c895257da677599ee1a68a2c381f04f84725457ca4bd7dd5fae344d8517719ecb60cf60bccd70aa33aeb7a9e9a617de797755
@@ -209,7 +209,7 @@ module Extface
209
209
  end
210
210
 
211
211
  def build_packet(cmd, data = "")
212
- String.new.tap() do |packet|
212
+ "".b.tap() do |packet|
213
213
  packet << STX
214
214
  packet << 0x20 + 4 + data.length
215
215
  packet << sequence_number
@@ -294,17 +294,17 @@ module Extface
294
294
 
295
295
  private
296
296
  def build_sale_data(item)
297
- encoded_text1 = device.encoding.present? ? item.text1.encode(device.encoding) : item.text1
297
+ encoded_text1 = device.encoding.present? ? item.text1.encode(device.encoding).b : item.text1
298
298
  encoded_text1 = encoded_text1.mb_chars.limit(27).to_s + '...' if encoded_text1 && encoded_text1.b.length > 30
299
299
 
300
- encoded_text2 = device.encoding.present? ? item.text2.encode(device.encoding) : item.text2
300
+ encoded_text2 = device.encoding.present? ? item.text2.encode(device.encoding).b : item.text2
301
301
  encoded_text2 = encoded_text1.mb_chars.limit(27).to_s + '...' if encoded_text2 && encoded_text2.b.length > 30
302
302
 
303
- "".tap() do |data|
303
+ "".b.tap() do |data|
304
304
  data << encoded_text1 unless encoded_text1.blank?
305
305
  data << "\x0a#{encoded_text2}" unless encoded_text2.blank?
306
306
  data << "\t"
307
- data << TAX_GROUPS_MAP[item.tax_group || 2]
307
+ data << TAX_GROUPS_MAP[item.tax_group || 2].b
308
308
  data << ("%.2f" % item.price)
309
309
  data << "*#{item.qty.to_s}" unless item.qty.blank?
310
310
  data << ",#{item.percent}" unless item.percent.blank?
@@ -0,0 +1,352 @@
1
+ module Extface
2
+ class Driver::Datecs::Dp35 < Extface::Driver::Base::Fiscal
3
+ NAME = 'Datecs DP35'.freeze
4
+
5
+ RESPONSE_TIMEOUT = 3 #seconds
6
+ INVALID_FRAME_RETRIES = 6 #count (bad length, bad checksum)
7
+ ACKS_MAX_WAIT = 60 #count / nothing is forever
8
+ NAKS_MAX_COUNT = 3 #count
9
+ BAD_SEQ_MAX_COUNT = 3
10
+ NO_RESP_MAX_COUNT = 3
11
+
12
+ TAX_GROUPS_MAP = {
13
+ 1 => "\xc0",
14
+ 2 => "\xc1",
15
+ 3 => "\xc2",
16
+ 4 => "\xc3",
17
+ 5 => "\xc4",
18
+ 6 => "\xc5",
19
+ 7 => "\xc6",
20
+ 8 => "\xc7"
21
+ }
22
+
23
+ PAYMENT_TYPE_MAP = {
24
+ 1 => "P",
25
+ 2 => "N",
26
+ 3 => "C",
27
+ 4 => "D",
28
+ 5 => "B"
29
+ }
30
+
31
+ include Extface::Driver::Datecs::CommandsV1
32
+
33
+ def handle(buffer)
34
+ #if i = buffer.index(/[\x03\x16\x15]/) # find position of frame possible delimiter
35
+ if i = buffer.index("\x03") || buffer.index("\x16") || buffer.index("\x15")
36
+ rpush buffer[0..i] # this will make data available for #pull(timeout) method
37
+ return i+1 # return number of bytes processed
38
+ end
39
+ end
40
+
41
+ #tests
42
+ def non_fiscal_test
43
+ device.session("Non Fiscal Text") do |s|
44
+ s.notify "Printing Non Fiscal Text"
45
+ s.open_non_fiscal_doc
46
+ s.print "********************************"
47
+ s.print "Extface Print Test".center(32)
48
+ s.print "********************************"
49
+ s.fsend Printer::PAPER_MOVE, "1"
50
+ s.print "Driver: " + "#{self.class::NAME}".truncate(24)
51
+ s.close_non_fiscal_doc
52
+ s.notify "Printing finished"
53
+ end
54
+ end
55
+
56
+ def fiscal_test
57
+ sale_and_pay_items_session([
58
+ SaleItem.new( price: 0.01, text1: "Extface Test" )
59
+ ])
60
+ end
61
+
62
+ #reports
63
+ def z_report_session
64
+ device.session("Z Report") do |s|
65
+ s.notify "Z Report Start"
66
+ s.fsend Closure::DAY_FIN_REPORT, "0"
67
+ s.notify "Z Report End"
68
+ end
69
+ end
70
+
71
+ def x_report_session
72
+ device.session("X Report") do |s|
73
+ s.notify "X Report Start"
74
+ s.fsend Closure::DAY_FIN_REPORT, "2"
75
+ s.notify "X Report End"
76
+ end
77
+ end
78
+
79
+ def period_report_session(from, to, detailed = true)
80
+ device.session("Period Report #{ '(detailed)' if detailed }") do |s|
81
+ s.notify "Period Report Start #{ '(detailed)' if detailed }"
82
+ s.fsend detailed ? Reports::REPORT_FP_BY_DATE : Reports::COMPACT_REPORT_FP_BY_DATE, "#{from.strftime('%d%m%y')},#{to.strftime('%d%m%y')}"
83
+ s.notify "Period Report End"
84
+ end
85
+ end
86
+
87
+ #print
88
+ def open_non_fiscal_doc
89
+ fsend Sales::START_NON_FISCAL_DOC
90
+ @print_session = true
91
+ end
92
+
93
+ def print(text) #up to 38 sybols, TODO check
94
+ raise "Not in print session" unless @print_session
95
+ fsend Sales::PRINT_NON_FISCAL_TEXT, text
96
+ end
97
+
98
+ def close_non_fiscal_doc
99
+ fsend Sales::END_NON_FISCAL_DOC
100
+ @print_session = false
101
+ end
102
+
103
+ def check_status
104
+ flush #clear receive buffer
105
+ fsend(Info::GET_STATUS, 'X') # get 6 bytes status
106
+ errors.empty?
107
+ end
108
+
109
+ #fiscal
110
+ def open_fiscal_doc(operator = "1", password = "0000")
111
+ fsend Sales::START_FISCAL_DOC, "#{operator.presence || "1"},#{password.presence || "0000"},1"
112
+ @fiscal_session = true
113
+ end
114
+
115
+ def close_fiscal_doc
116
+ raise "Not in fiscal session" unless @fiscal_session
117
+ fsend Sales::END_FISCAL_DOC
118
+ @fiscal_session = false
119
+ end
120
+
121
+ def add_sale(sale_item)
122
+ raise "Not in fiscal session" unless @fiscal_session
123
+ fsend Sales::SALE_AND_SHOW, build_sale_data(sale_item)
124
+ end
125
+
126
+ def add_comment(text)
127
+ raise "Not in fiscal session" unless @fiscal_session
128
+ end
129
+
130
+ def add_payment(value = nil, type_num = nil)
131
+ raise "Not in fiscal session" unless @fiscal_session
132
+ payment_data = "".tap() do |data|
133
+ data << "\t"
134
+ data << PAYMENT_TYPE_MAP[type_num || 1]
135
+ data << ("%.2f" % value) unless value.blank?
136
+ end
137
+ fsend(Sales::TOTAL, payment_data)
138
+ end
139
+
140
+ def total_payment
141
+ raise "Not in fiscal session" unless @fiscal_session
142
+ fsend(Sales::TOTAL, "\t")
143
+ end
144
+
145
+ #basket
146
+ def sale_and_pay_items_session(items = [], operator = "1", password = "0000")
147
+ device.session("Fiscal Doc") do |s|
148
+ s.notify "Fiscal Doc Start"
149
+ s.open_fiscal_doc
150
+ s.notify "Register Sale"
151
+ items.each do |item|
152
+ s.add_sale(item)
153
+ end
154
+ s.notify "Register Payment"
155
+ s.total_payment
156
+ s.notify "Close Fiscal Receipt"
157
+ s.close_fiscal_doc
158
+ s.notify "Fiscal Doc End"
159
+ end
160
+ end
161
+
162
+ def cancel_doc_session
163
+ device.session("Doc cancel") do |s|
164
+ s.notify "Doc Cancel Start"
165
+ s.fsend Sales::CANCEL_FISCAL_DOC
166
+ s.paper_cut
167
+ s.notify "Doc Cancel End"
168
+ end
169
+ end
170
+
171
+ #common
172
+ def fsend(cmd, data = "") #return data or nil
173
+ packet_data = build_packet(cmd, data) #store packet to be able to re-transmit it with the same sequence number
174
+ result = false
175
+ invalid_frames = 0 #counter for bad responses
176
+ nak_messages = 0 #counter for rejected packets (should re-transmit the packet)
177
+ no_resp = 0
178
+ flush #prevent double packet response issue like daisy driver
179
+ push packet_data #send packet
180
+ ACKS_MAX_WAIT.times do |retries|
181
+ errors.clear
182
+ if resp = frecv(RESPONSE_TIMEOUT)
183
+ if resp.valid?
184
+ human_status_errors(resp.status)
185
+ if errors.empty?
186
+ result = resp.data
187
+ break
188
+ else
189
+ raise errors.full_messages.join(',')
190
+ end
191
+ else #ack, nak or bad
192
+ if resp.nak?
193
+ nak_messages += 1
194
+ if nak_messages > NAKS_MAX_COUNT
195
+ errors.add :base, "#{NAKS_MAX_COUNT} NAKs Received. Abort!"
196
+ break
197
+ end
198
+ elsif !resp.ack?
199
+ invalid_frames += 1
200
+ if invalid_frames > INVALID_FRAME_RETRIES
201
+ errors.add :base, "#{INVALID_FRAME_RETRIES} Broken Packets Received. Abort!"
202
+ break
203
+ end
204
+ end
205
+ push packet_data unless resp.ack?
206
+ end
207
+ else
208
+ no_resp += 1
209
+ if no_resp > NO_RESP_MAX_COUNT
210
+ p "No reply in #{NO_RESP_MAX_COUNT * RESPONSE_TIMEOUT} seconds. Abort!"
211
+ errors.add :base, "No reply in #{NO_RESP_MAX_COUNT * RESPONSE_TIMEOUT} seconds. Abort!"
212
+ return result
213
+ end
214
+ end
215
+ errors.add :base, "#{ACKS_MAX_WAIT} ACKs Received. Abort!"
216
+ end
217
+ return result
218
+ end
219
+
220
+ def frecv(timeout) # return Frame or nil
221
+ rframe = nil
222
+ BAD_SEQ_MAX_COUNT.times do
223
+ errors.clear
224
+ if frame_bytes = pull(timeout)
225
+ rframe = Frame.new(frame_bytes.b)
226
+ if rframe.seq.nil? || rframe.seq.ord == sequence_number(false) #accept only current sequence number as reply
227
+ break
228
+ else
229
+ errors.add :base, "Sequence mismatch"
230
+ p "Invalid sequence (expected: #{sequence_number(false).to_s(16)}, got: #{rframe.seq.ord.to_s(16)})"
231
+ rframe = nil #invalidate mismatch sequence frame for the last retry
232
+ end
233
+ else
234
+ errors.add :base, "No data received from device"
235
+ break
236
+ end
237
+ end
238
+ return rframe
239
+ end
240
+
241
+ def build_packet(cmd, data = "")
242
+ "".b.tap() do |packet|
243
+ packet << STX #Preamble. 1 byte long. Value: 01H.
244
+ packet << 0x20 + 4 + data.b.length #Number of bytes from <01> preamble (excluded) to <05> (included) plus the fixed offset of 20H
245
+ packet << sequence_number #Sequence number of the frame. Length : 1 byte. Value: 20H – FFH.
246
+ packet << cmd #Length: 1 byte. Value: 20H - 7FH.
247
+ packet << data.b #Length: 0 - 218 bytes for Host to printer
248
+ packet << PA1 #Post-amble. Length: 1 byte. Value: 05H.
249
+ packet << Frame.bcc(packet[1..-1])#Control sum (0000H-FFFFH). Length: 4 bytes. Value of each byte: 30H-3FH
250
+ packet << ETX #Terminator. Length: 1 byte. Value: 03H.
251
+ end
252
+ end
253
+
254
+ def paper_cut
255
+ device.session('Paper Cut') do |s|
256
+ s.push build_packet(Printer::PAPER_CUT)
257
+ end
258
+ end
259
+
260
+ def human_status_errors(status) #6 bytes status
261
+ status_0 = status[0].ord
262
+ errors.add :base, "Fiscal Device General Error" unless (status_0 & 0x20).zero?
263
+ errors.add :base, "Invalid Command" unless (status_0 & 0x02).zero?
264
+ errors.add :base, "Date & Time Not Set" unless (status_0 & 0x04).zero?
265
+ errors.add :base, "Syntax Error" unless (status_0 & 0x01).zero?
266
+ status_1 = status[1].ord
267
+ errors.add :base, "Unpermitted Command In This Mode" unless (status_1 & 0x02).zero?
268
+ errors.add :base, "Field Overflow" unless (status_1 & 0x01).zero?
269
+ end
270
+
271
+ private
272
+ def build_sale_data(item)
273
+ "".b.tap() do |data|
274
+ data << item.text1.truncate(30) unless item.text1.blank?
275
+ data << "\x0a#{text2}" unless item.text2.blank?
276
+ data << "\t"
277
+ data << TAX_GROUPS_MAP[item.tax_group || 2]
278
+ data << ("%.2f" % item.price)
279
+ data << "*#{item.qty.to_s}" unless item.qty.blank?
280
+ data << ",#{item.percent}" unless item.percent.blank?
281
+ data << ",;#{'%.2f' % item.neto}" unless item.neto.blank?
282
+ end
283
+ end
284
+
285
+ def sequence_number(increment = true)
286
+ @seq ||= 0x1f
287
+ @seq += 1 if increment
288
+ @seq = 0x1f if @seq == 0x7f
289
+ @seq
290
+ end
291
+
292
+ class Frame
293
+ include ActiveModel::Validations
294
+ attr_reader :frame, :len, :seq, :cmd, :data, :status, :bcc
295
+
296
+ validates_presence_of :frame#, unless: :unpacked?
297
+ validate :bcc_validation
298
+ validate :len_validation
299
+
300
+ def initialize(buffer)
301
+ if match = buffer.match(/\x01(.{1})(.{1})(.{1})(.*)\x04(.{6})\x05(.{4})\x03/nm)
302
+ @frame = match.to_a.first
303
+ @len, @seq, @cmd, @data, @status, @bcc = match.captures
304
+ else
305
+ if buffer[/^\x16+$/] # only ACKs
306
+ @ack = true
307
+ elsif buffer.index("\x15")
308
+ @nak = true
309
+ end
310
+ end
311
+ end
312
+
313
+ def ack?; !!@ack; end #should wait, response is yet to come
314
+
315
+ def nak?; !!@nak; end #should retry command with same seq
316
+
317
+ private
318
+
319
+ def unpacked? # is it packed or unpacked message?
320
+ @ack || @nak
321
+ end
322
+
323
+ def bcc_validation
324
+ unless unpacked? || frame.blank?
325
+ calc_bcc = self.class.bcc frame[1..-6]
326
+ errors.add(:bcc, I18n.t('errors.messages.invalid')) if bcc != calc_bcc
327
+ end
328
+ end
329
+
330
+ def len_validation
331
+ unless unpacked? || frame.blank?
332
+ errors.add(:len, I18n.t('errors.messages.invalid')) if frame.nil? || len.ord != (frame[1..-6].length + 0x20)
333
+ end
334
+ end
335
+
336
+ class << self
337
+ def bcc(buffer)
338
+ sum = 0
339
+ buffer.each_byte do |byte|
340
+ sum += byte
341
+ end
342
+ "".tap() do |bcc|
343
+ 4.times do |halfbyte|
344
+ bcc.insert 0, (0x30 + ((sum >> (halfbyte*4)) & 0x0f)).chr
345
+ end
346
+ end
347
+ end
348
+ end
349
+ end
350
+
351
+ end
352
+ end
@@ -269,17 +269,17 @@ module Extface
269
269
  end
270
270
 
271
271
  def build_sale_data(item)
272
- encoded_text1 = device.encoding.present? ? item.text1.encode(device.encoding) : item.text1
272
+ encoded_text1 = device.encoding.present? ? item.text1.encode(device.encoding).b : item.text1
273
273
  encoded_text1 = encoded_text1.mb_chars.limit(27).to_s + '...' if encoded_text1 && encoded_text1.b.length > 30
274
274
 
275
- encoded_text2 = device.encoding.present? ? item.text2.encode(device.encoding) : item.text2
275
+ encoded_text2 = device.encoding.present? ? item.text2.encode(device.encoding).b : item.text2
276
276
  encoded_text2 = encoded_text1.mb_chars.limit(27).to_s + '...' if encoded_text2 && encoded_text2.b.length > 30
277
277
 
278
278
  "".b.tap() do |data|
279
279
  data << encoded_text1 unless encoded_text1.blank?
280
280
  data << "\x0a#{encoded_text2}" unless encoded_text2.blank?
281
281
  data << "\t"
282
- data << TAX_GROUPS_MAP[item.tax_group || 2]
282
+ data << TAX_GROUPS_MAP[item.tax_group || 2].b
283
283
  data << ("%.2f" % item.price)
284
284
  data << "*#{item.qty.to_s}" unless item.qty.blank?
285
285
  data << ",#{item.percent}" unless item.percent.blank?
@@ -1,3 +1,3 @@
1
1
  module Extface
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
  end
@@ -1,5 +1,5 @@
1
1
  # Set up gems listed in the Gemfile.
2
2
  ENV['BUNDLE_GEMFILE'] ||= File.expand_path('../../../../Gemfile', __FILE__)
3
3
 
4
- require 'bundler/setup' if File.exists?(ENV['BUNDLE_GEMFILE'])
4
+ require 'bundler/setup' if File.exist?(ENV['BUNDLE_GEMFILE'])
5
5
  $LOAD_PATH.unshift File.expand_path('../../../../lib', __FILE__)
Binary file
@@ -18642,3 +18642,90 @@ Extface::Driver::Posiflex::Aura80Test: test_status
18642
18642
  Extface::Job Load (0.5ms) SELECT "extface_jobs".* FROM "extface_jobs" WHERE "extface_jobs"."device_id" = ? [["device_id", 1033518405]]
18643
18643
  Extface::Job Load (0.5ms) SELECT "extface_jobs".* FROM "extface_jobs" WHERE "extface_jobs"."device_id" = ? AND ("extface_jobs"."completed_at" IS NULL AND "extface_jobs"."failed_at" IS NULL AND "extface_jobs"."started_at" IS NOT NULL) ORDER BY "extface_jobs"."id" ASC LIMIT 1 [["device_id", 1033518405]]
18644
18644
  Completed 200 OK in 10004ms (ActiveRecord: 3.2ms)
18645
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18646
+  (133.3ms) DROP TABLE IF EXISTS "extface_devices"
18647
+  (0.3ms) SELECT sqlite_version(*)
18648
+  (113.7ms) CREATE TABLE "extface_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "uuid" varchar, "name" varchar, "extfaceable_id" integer, "extfaceable_type" varchar, "driver_id" integer, "created_at" datetime, "updated_at" datetime, "encoding" varchar)
18649
+  (120.4ms) DROP TABLE IF EXISTS "extface_drivers"
18650
+  (155.6ms) CREATE TABLE "extface_drivers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "type" varchar, "settings" text, "created_at" datetime, "updated_at" datetime)
18651
+  (167.1ms) DROP TABLE IF EXISTS "extface_jobs"
18652
+  (164.0ms) CREATE TABLE "extface_jobs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer, "created_at" datetime, "updated_at" datetime, "description" varchar, "error" varchar, "failed_at" datetime, "completed_at" datetime, "connected_at" datetime, "started_at" datetime)
18653
+  (229.0ms) CREATE INDEX "index_extface_jobs_on_device_id" ON "extface_jobs" ("device_id")
18654
+  (172.1ms) DROP TABLE IF EXISTS "extface_serial_configs"
18655
+  (189.0ms) CREATE TABLE "extface_serial_configs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "driver_id" integer, "serial_boud_rate" integer, "serial_data_length" integer, "serial_parity_check" integer, "serial_stop_bits" integer, "serial_handshake" integer, "created_at" datetime, "updated_at" datetime)
18656
+  (226.9ms) DROP TABLE IF EXISTS "shops"
18657
+  (125.9ms) CREATE TABLE "shops" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime, "updated_at" datetime)
18658
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18659
+  (186.3ms) CREATE TABLE "ar_internal_metadata" ("key" varchar NOT NULL PRIMARY KEY, "value" varchar, "created_at" datetime NOT NULL, "updated_at" datetime NOT NULL)
18660
+ ActiveRecord::InternalMetadata Load (0.2ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
18661
+  (0.1ms) begin transaction
18662
+ SQL (0.3ms) INSERT INTO "ar_internal_metadata" ("key", "value", "created_at", "updated_at") VALUES (?, ?, ?, ?) [["key", "environment"], ["value", "test"], ["created_at", "2017-11-18 00:22:16.699389"], ["updated_at", "2017-11-18 00:22:16.699389"]]
18663
+  (131.6ms) commit transaction
18664
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18665
+  (3845.4ms) DROP TABLE IF EXISTS "extface_devices"
18666
+  (0.2ms) SELECT sqlite_version(*)
18667
+  (103.2ms) CREATE TABLE "extface_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "uuid" varchar, "name" varchar, "extfaceable_id" integer, "extfaceable_type" varchar, "driver_id" integer, "created_at" datetime, "updated_at" datetime, "encoding" varchar)
18668
+  (101.1ms) DROP TABLE IF EXISTS "extface_drivers"
18669
+  (350.0ms) CREATE TABLE "extface_drivers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "type" varchar, "settings" text, "created_at" datetime, "updated_at" datetime)
18670
+  (109.6ms) DROP TABLE IF EXISTS "extface_jobs"
18671
+  (131.3ms) CREATE TABLE "extface_jobs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer, "created_at" datetime, "updated_at" datetime, "description" varchar, "error" varchar, "failed_at" datetime, "completed_at" datetime, "connected_at" datetime, "started_at" datetime)
18672
+  (121.4ms) CREATE INDEX "index_extface_jobs_on_device_id" ON "extface_jobs" ("device_id")
18673
+  (147.7ms) DROP TABLE IF EXISTS "extface_serial_configs"
18674
+  (131.3ms) CREATE TABLE "extface_serial_configs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "driver_id" integer, "serial_boud_rate" integer, "serial_data_length" integer, "serial_parity_check" integer, "serial_stop_bits" integer, "serial_handshake" integer, "created_at" datetime, "updated_at" datetime)
18675
+  (122.9ms) DROP TABLE IF EXISTS "shops"
18676
+  (111.8ms) CREATE TABLE "shops" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime, "updated_at" datetime)
18677
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18678
+ ActiveRecord::InternalMetadata Load (0.3ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
18679
+  (0.1ms) begin transaction
18680
+  (0.1ms) commit transaction
18681
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18682
+  (216.0ms) DROP TABLE IF EXISTS "extface_devices"
18683
+  (0.2ms) SELECT sqlite_version(*)
18684
+  (130.7ms) CREATE TABLE "extface_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "uuid" varchar, "name" varchar, "extfaceable_id" integer, "extfaceable_type" varchar, "driver_id" integer, "created_at" datetime, "updated_at" datetime, "encoding" varchar)
18685
+  (188.6ms) DROP TABLE IF EXISTS "extface_drivers"
18686
+  (114.4ms) CREATE TABLE "extface_drivers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "type" varchar, "settings" text, "created_at" datetime, "updated_at" datetime)
18687
+  (105.4ms) DROP TABLE IF EXISTS "extface_jobs"
18688
+  (114.1ms) CREATE TABLE "extface_jobs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer, "created_at" datetime, "updated_at" datetime, "description" varchar, "error" varchar, "failed_at" datetime, "completed_at" datetime, "connected_at" datetime, "started_at" datetime)
18689
+  (180.5ms) CREATE INDEX "index_extface_jobs_on_device_id" ON "extface_jobs" ("device_id")
18690
+  (114.7ms) DROP TABLE IF EXISTS "extface_serial_configs"
18691
+  (105.8ms) CREATE TABLE "extface_serial_configs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "driver_id" integer, "serial_boud_rate" integer, "serial_data_length" integer, "serial_parity_check" integer, "serial_stop_bits" integer, "serial_handshake" integer, "created_at" datetime, "updated_at" datetime)
18692
+  (98.4ms) DROP TABLE IF EXISTS "shops"
18693
+  (106.6ms) CREATE TABLE "shops" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime, "updated_at" datetime)
18694
+  (0.3ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18695
+ ActiveRecord::InternalMetadata Load (0.2ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
18696
+  (0.1ms) begin transaction
18697
+  (0.1ms) commit transaction
18698
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18699
+  (126.0ms) DROP TABLE IF EXISTS "extface_devices"
18700
+  (0.3ms) SELECT sqlite_version(*)
18701
+  (102.4ms) CREATE TABLE "extface_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "uuid" varchar, "name" varchar, "extfaceable_id" integer, "extfaceable_type" varchar, "driver_id" integer, "created_at" datetime, "updated_at" datetime, "encoding" varchar)
18702
+  (97.6ms) DROP TABLE IF EXISTS "extface_drivers"
18703
+  (89.5ms) CREATE TABLE "extface_drivers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "type" varchar, "settings" text, "created_at" datetime, "updated_at" datetime)
18704
+  (101.6ms) DROP TABLE IF EXISTS "extface_jobs"
18705
+  (94.9ms) CREATE TABLE "extface_jobs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer, "created_at" datetime, "updated_at" datetime, "description" varchar, "error" varchar, "failed_at" datetime, "completed_at" datetime, "connected_at" datetime, "started_at" datetime)
18706
+  (97.3ms) CREATE INDEX "index_extface_jobs_on_device_id" ON "extface_jobs" ("device_id")
18707
+  (108.5ms) DROP TABLE IF EXISTS "extface_serial_configs"
18708
+  (103.7ms) CREATE TABLE "extface_serial_configs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "driver_id" integer, "serial_boud_rate" integer, "serial_data_length" integer, "serial_parity_check" integer, "serial_stop_bits" integer, "serial_handshake" integer, "created_at" datetime, "updated_at" datetime)
18709
+  (93.4ms) DROP TABLE IF EXISTS "shops"
18710
+  (106.4ms) CREATE TABLE "shops" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime, "updated_at" datetime)
18711
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18712
+ ActiveRecord::InternalMetadata Load (0.2ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
18713
+  (0.1ms) begin transaction
18714
+  (0.0ms) commit transaction
18715
+  (0.2ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18716
+  (70.7ms) DROP TABLE IF EXISTS "extface_devices"
18717
+  (0.3ms) SELECT sqlite_version(*)
18718
+  (63.7ms) CREATE TABLE "extface_devices" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "uuid" varchar, "name" varchar, "extfaceable_id" integer, "extfaceable_type" varchar, "driver_id" integer, "created_at" datetime, "updated_at" datetime, "encoding" varchar)
18719
+  (70.9ms) DROP TABLE IF EXISTS "extface_drivers"
18720
+  (65.5ms) CREATE TABLE "extface_drivers" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "type" varchar, "settings" text, "created_at" datetime, "updated_at" datetime)
18721
+  (60.4ms) DROP TABLE IF EXISTS "extface_jobs"
18722
+  (73.0ms) CREATE TABLE "extface_jobs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "device_id" integer, "created_at" datetime, "updated_at" datetime, "description" varchar, "error" varchar, "failed_at" datetime, "completed_at" datetime, "connected_at" datetime, "started_at" datetime)
18723
+  (72.2ms) CREATE INDEX "index_extface_jobs_on_device_id" ON "extface_jobs" ("device_id")
18724
+  (73.2ms) DROP TABLE IF EXISTS "extface_serial_configs"
18725
+  (73.1ms) CREATE TABLE "extface_serial_configs" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "driver_id" integer, "serial_boud_rate" integer, "serial_data_length" integer, "serial_parity_check" integer, "serial_stop_bits" integer, "serial_handshake" integer, "created_at" datetime, "updated_at" datetime)
18726
+  (64.6ms) DROP TABLE IF EXISTS "shops"
18727
+  (65.5ms) CREATE TABLE "shops" ("id" INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, "created_at" datetime, "updated_at" datetime)
18728
+  (0.1ms) SELECT "schema_migrations"."version" FROM "schema_migrations" ORDER BY "schema_migrations"."version" ASC
18729
+ ActiveRecord::InternalMetadata Load (0.1ms) SELECT "ar_internal_metadata".* FROM "ar_internal_metadata" WHERE "ar_internal_metadata"."key" = ? LIMIT ? [["key", "environment"], ["LIMIT", 1]]
18730
+  (0.1ms) begin transaction
18731
+  (0.1ms) commit transaction
@@ -23,7 +23,13 @@ datecs_dp25:
23
23
  name: Datect DP25
24
24
  extfaceable: one(Shop)
25
25
  driver: datecs_dp25
26
-
26
+
27
+ datecs_dp35:
28
+ uuid: datecs_dp35
29
+ name: Datect DP35
30
+ extfaceable: one(Shop)
31
+ driver: datecs_dp35
32
+
27
33
  daisy_fx1200:
28
34
  uuid: daisy_fx1200
29
35
  name: Daisy Fx1200
@@ -15,6 +15,9 @@ datecs_fp550:
15
15
  datecs_dp25:
16
16
  type: Extface::Driver::Datecs::Dp25
17
17
 
18
+ datecs_dp35:
19
+ type: Extface::Driver::Datecs::Dp35
20
+
18
21
  daisy_fx1200:
19
22
  type: Extface::Driver::DaisyFx1200
20
23
 
@@ -0,0 +1,63 @@
1
+ require 'test_helper'
2
+
3
+ module Extface
4
+ class Driver::Datecs::Dp35Test < ActiveSupport::TestCase
5
+ setup do
6
+ @driver = extface_drivers(:datecs_dp35)
7
+ @driver.flush # clear receive buffer
8
+ end
9
+
10
+ test "handle" do
11
+ assert_equal nil, @driver.handle('bad packet')
12
+ assert_equal 6, @driver.handle("\x01data\x03data"), "Frame not match"
13
+ assert_equal 9, @driver.handle("pre\x01data\x03data"), "Frame with preamble not match"
14
+ assert_equal 8, @driver.handle("\x16\x16\x01data\x03data"), "Frame with ACK preamble not match"
15
+ assert_equal 4, @driver.handle("pre\x15"), "NAK not match"
16
+ end
17
+
18
+ test "build packet" do
19
+ assert_equal "\x01\x24\x20\x4a\x05\x30\x30\x39\x33\x03".b, @driver.build_packet(0x4a), "packet without data"
20
+ assert_equal "\x01\x25\x21\x4a\x58\x05\x30\x30\x3e\x3d\x03".b, @driver.build_packet(0x4a, 'X'), "packet with data"
21
+ end
22
+
23
+ test "response frame" do
24
+ frame_class = @driver.class::Frame
25
+ assert frame_class.new("\x15").nak?, "NAK message failed"
26
+ assert frame_class.new("\x16\x16").ack?, "ACK message failed"
27
+ assert_nothing_raised do
28
+ assert_equal false, frame_class.new("bad data\x01\x25\x21\x4asome broken packet\x58\x05\x30\x30\x3e\x3d\x03".b).valid?
29
+ end
30
+ frame = frame_class.new("\x16\x01\x2C\x2F\x2D\x50\x04\x88\x80\xC0\x80\x80\xB0\x05\x30\x34\x35\x39\x03".b)
31
+ assert frame.valid?, "Vailid frame not recognized"
32
+ assert_equal "\x01\x2C\x2F\x2D\x50\x04\x88\x80\xC0\x80\x80\xB0\x05\x30\x34\x35\x39\x03".b, frame.frame
33
+ assert_equal "\x2c".b, frame.len
34
+ assert_equal "\x2f".b, frame.seq
35
+ assert_equal "\x2d".b, frame.cmd
36
+ assert_equal "\x50".b, frame.data
37
+ assert_equal "\x88\x80\xC0\x80\x80\xB0".b, frame.status
38
+ assert_equal "\x30\x34\x35\x39".b, frame.bcc
39
+ #bad check sum
40
+ frame = frame_class.new("\x01\x2C\x2F\x2D\x50\x04\x88\x80\xC0\x80\x80\xB0\x05\x30\x34\x35\x38\x03".b)
41
+ assert_equal false, frame.valid?
42
+ assert frame.errors.messages[:bcc]
43
+ #bad length
44
+ frame = frame_class.new("\x01\x2b\x2F\x2D\x50\x04\x88\x80\xC0\x80\x80\xB0\x05\x30\x34\x35\x38\x03".b)
45
+ assert_equal false, frame.valid?
46
+ assert frame.errors.messages[:len]
47
+ end
48
+
49
+ test "fsend" do
50
+ job = extface_jobs(:one)
51
+ job_thread = Thread.new do
52
+ @driver.set_job(job)
53
+ result = @driver.fsend(0x2C) # paper move command
54
+ end
55
+ simulate_device_pull(job)
56
+ @driver.handle("\x01\x31\x20\x4A\x88\x80\xC0\x80\x80\xB8\x04\x88\x80\xC0\x80\x80\xB8\x05\x30\x37\x3A\x34\x03".b)
57
+ simulate_device_pull(job)
58
+ @driver.handle("\x01\x38\x21\x30\x30\x30\x30\x30\x35\x30\x2C\x30\x30\x30\x30\x34\x39\x04\x80\x80\x88\x80\x80\xB8\x05\x30\x36\x35\x30\x03".b)
59
+ job_thread.join
60
+ assert @driver.errors.empty?
61
+ end
62
+ end
63
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: extface
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.6.1
4
+ version: 0.6.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Vangelov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-05-31 00:00:00.000000000 Z
11
+ date: 2018-11-15 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: redis
@@ -105,6 +105,7 @@ files:
105
105
  - app/models/extface/driver/daisy_fx1200.rb
106
106
  - app/models/extface/driver/datecs/commands_v1.rb
107
107
  - app/models/extface/driver/datecs/dp25.rb
108
+ - app/models/extface/driver/datecs/dp35.rb
108
109
  - app/models/extface/driver/datecs/fp550.rb
109
110
  - app/models/extface/driver/eltrade/commands_fp4.rb
110
111
  - app/models/extface/driver/eltrade_tm_u220.rb
@@ -259,6 +260,7 @@ files:
259
260
  - test/models/extface/device_test.rb
260
261
  - test/models/extface/driver/daisy_fx1200_test.rb
261
262
  - test/models/extface/driver/datecs/dp25_test.rb
263
+ - test/models/extface/driver/datecs/dp35_test.rb
262
264
  - test/models/extface/driver/datecs/fp550_test.rb
263
265
  - test/models/extface/driver/generic_pos_test.rb
264
266
  - test/models/extface/driver/posiflex/aura80_test.rb
@@ -287,7 +289,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
287
289
  version: '0'
288
290
  requirements: []
289
291
  rubyforge_project:
290
- rubygems_version: 2.5.0
292
+ rubygems_version: 2.6.14
291
293
  signing_key:
292
294
  specification_version: 4
293
295
  summary: External Interfaces for Cloud-Based Applications (Rails 4)
@@ -387,6 +389,7 @@ test_files:
387
389
  - test/models/extface/driver/posiflex/aura80_test.rb
388
390
  - test/models/extface/driver/daisy_fx1200_test.rb
389
391
  - test/models/extface/driver/star_tsp200_test.rb
392
+ - test/models/extface/driver/datecs/dp35_test.rb
390
393
  - test/models/extface/driver/datecs/fp550_test.rb
391
394
  - test/models/extface/driver/datecs/dp25_test.rb
392
395
  - test/models/extface/serial_config_test.rb