extface 0.6.1 → 0.6.2

Sign up to get free protection for your applications and to get access to all the features.
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