libcx320 0.1.5

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: c3547e9bba3f0346e0343c36dc511ff05d0cc5e244e6dc949be37b008d02e5b0
4
+ data.tar.gz: 4720512b76668f1ef5bb2d4fb80faf9e534378f7ba24b9e1b53e607e10bd1a55
5
+ SHA512:
6
+ metadata.gz: 873e3f5201b0bbf394a495531762482ed9b199076f2d4f1eb4895407cefc811b5c9851e032822016e4c4c58ea643ef5fcd239efd0a672316e41131cd7472a293
7
+ data.tar.gz: 3f72f2761dcfac9803a37f92a8986fce7e3d5607c1c177f09b23c2237eb3eee1f2032416db2b1f5569bf0ad09f7aa89e86225de3c8e3901d45e36532e05abf55
checksums.yaml.gz.sig ADDED
Binary file
data/.gitignore ADDED
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.bundle
11
+ *.so
12
+ *.o
13
+ *.a
14
+ mkmf.log
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in libcx320.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2015 Holger Arndt
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,32 @@
1
+ # Libcx320
2
+
3
+ Driver for Retransfer Printer CX-320.
4
+ Usable per PCP05CT.DLL on Windows or per direct LIBUSB access on any operating system.
5
+
6
+ ## Installation
7
+
8
+ Add this line to your application's Gemfile:
9
+
10
+ ```ruby
11
+ gem 'libcx320'
12
+ ```
13
+
14
+ And then execute:
15
+
16
+ $ bundle
17
+
18
+ Or install it yourself as:
19
+
20
+ $ gem install libcx320
21
+
22
+ ## Usage
23
+
24
+ TODO: Write usage instructions here
25
+
26
+ ## Contributing
27
+
28
+ 1. Fork it ( https://github.com/larskanis/libcx320 )
29
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
30
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
31
+ 4. Push to the branch (`git push origin my-new-feature`)
32
+ 5. Create a new Pull Request
data/Rakefile ADDED
@@ -0,0 +1,3 @@
1
+ require "bundler/gem_tasks"
2
+
3
+ task :gem => :build
data/lib/libcx320/c.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'ffi'
2
+
3
+ module LibCX320
4
+ module C
5
+ extend FFI::Library
6
+
7
+ ffi_lib 'PCP05CT.DLL'
8
+
9
+ # Get Handle
10
+ attach_function :CXCMD_ScanCX320, [:pointer, :pointer], :int
11
+ attach_function :CXCMD_ScanCX320Next, [:pointer, :pointer], :int
12
+
13
+ # Checks
14
+ attach_function :CXCMD_CheckIfConnected, [:pointer, :pointer], :bool
15
+ attach_function :CXCMD_TestUnitReady, [:int, :int], :int
16
+
17
+ # Print & CardControl
18
+ attach_function :CXCMD_ReadPosition, [:int, :int, :pointer], :int
19
+ attach_function :CXCMD_ImageOut, [:int, :int, :pointer, :int, :int, :int], :int
20
+ attach_function :CXCMD_DefineLUT, [:int, :int, :int, :int, :pointer], :int
21
+ attach_function :CXCMD_Print, [:int, :int, :int, :int, :int], :int
22
+ attach_function :CXCMD_LoadCard, [:int, :int, :int, :int, :int, :int], :int
23
+ attach_function :CXCMD_MoveCard, [:int, :int, :int, :int, :int, :int], :int
24
+ attach_function :CXCMD_RetransferAndEject, [:int, :int, :int], :int
25
+ attach_function :CXCMD_RetransferAndTurn, [:int, :int, :int], :int
26
+
27
+ # MS Encoding
28
+ attach_function :CXCMD_WriteMagData, [:int, :int, :pointer, :int, :int], :int
29
+ attach_function :CXCMD_ReadMagData, [:int, :int, :pointer, :pointer, :int], :int
30
+ attach_function :CXCMD_ICControl, [:int, :int, :int, :int], :int
31
+
32
+ # Reset
33
+ attach_function :CXCMD_RezeroUnit, [:int, :int], :int
34
+
35
+ # Infos & Settings
36
+ attach_function :CXCMD_ModeSense, [:int, :int, :int, :pointer], :int
37
+ attach_function :CXCMD_ModeSelect, [:int, :int, :int, :pointer], :int
38
+ attach_function :CXCMD_LogSense, [:int, :int, :int, :pointer], :int
39
+ attach_function :CXCMD_LogSelect, [:int, :int], :int
40
+ end
41
+ end
@@ -0,0 +1,422 @@
1
+
2
+ module LibCX320
3
+ class CX320
4
+ attr_reader :dev
5
+
6
+ def initialize(dev)
7
+ @dev = dev
8
+ end
9
+
10
+ def self.devices(dev_type)
11
+ dev_type.devices.map do |dev|
12
+ self.new(dev)
13
+ end
14
+ end
15
+
16
+ def close
17
+ @dev.close if @dev
18
+ end
19
+
20
+ def ready?
21
+ @dev.ready?
22
+ end
23
+
24
+ def rezero_unit
25
+ @dev.rezero_unit
26
+ end
27
+
28
+ def get_current_card_position
29
+ resp = @dev.get_current_card_position
30
+
31
+ # PU (Position Unknown) - Byte 0 Bit 3
32
+ # 0: The card is in the printer unit.
33
+ # 1: No card in the printer unit
34
+ #
35
+ # Note: Printer reports PU = 1 even if any card is in the card hopper. Printer generates
36
+ # Check Condition if the card is being transported.
37
+ #
38
+ # Byte 7
39
+ # Position: Card position in the printer unit.
40
+ # 0: At Retransfer Position 1:At Contact IC Encoder 2: At No-Contact IC encoder
41
+ # 3: At MAG encoder Greater than 3: Reserved
42
+ #
43
+ # Byte 1 Bit 0
44
+ # Load Mode: The way to load the card
45
+ # 0: From the card tray
46
+ # 1: From the right side card entrance
47
+
48
+ card_position = { pu: nil, position: nil, load_mode: nil}
49
+ card_position[:pu] = resp.getbyte(0) & 0x4 != 0 ? :no_card_in_printer : :card_in_printer
50
+
51
+ card_position[:position] = case resp.getbyte(7)
52
+ when 0 then :retransfer
53
+ when 1 then :contact
54
+ when 2 then :contactless
55
+ when 3 then :magnetstripe
56
+ else raise "Invalid card_position: #{resp.getbyte(7).inspect}!"
57
+ end
58
+
59
+ card_position[:load_mode] = resp.getbyte(0) & 0x1 != 0 ? :right_side : :card_tray
60
+
61
+ card_position
62
+ end
63
+
64
+ ImageLayer2Code = {
65
+ K: 0,
66
+ C: 1,
67
+ M: 2,
68
+ Y: 3,
69
+ UV: 4,
70
+ PeelOff: 5
71
+ }
72
+
73
+ def image_out(layer, data, buffer=0)
74
+ buffer = Buffer2Code[buffer] || buffer
75
+ layer = ImageLayer2Code[layer] || layer
76
+
77
+ @dev.image_out(layer, data, buffer)
78
+ end
79
+
80
+ # Notice: As K LUT is used internally, K must not be specified.
81
+ LutLayer2Code = {
82
+ K: 0,
83
+ C: 2,
84
+ M: 4,
85
+ Y: 6
86
+ }
87
+ def lut=(layer, lut)
88
+ layer = LutLayer2Code[layer] ? LutLayer2Code[layer] : layer
89
+
90
+ data = FFI::MemoryPointer.new :char, 256
91
+ data.write_bytes lut
92
+
93
+ check_returncode C.CXCMD_DefineLUT(@slot, @id, data.size, data)
94
+ end
95
+
96
+ Buffer2Code = {
97
+ frontside: 0,
98
+ backside: 1,
99
+ }
100
+
101
+ PrintColor2Code = {
102
+ YMC: 0b1,
103
+ K: 0b10,
104
+ UV: 0b100,
105
+ PeelOff: 0b1000
106
+ }
107
+ def print(color=[:YMC, :K], buffer=0, async=false)
108
+ buffer = Buffer2Code[buffer] || buffer
109
+ color = color.map{|c| PrintColor2Code[c] }.inject(0, &:|) if color.kind_of?(Array)
110
+ async = async ? 1 : 0
111
+
112
+ @dev.print(color, buffer, async)
113
+ end
114
+
115
+ Position2Code = {
116
+ retransfer: 0,
117
+ contact: 1,
118
+ contactless: 2,
119
+ magnetstripe: 3,
120
+ eject: 4
121
+ }
122
+ def load_card(pos=:retransfer, flip=false, adjusted=false, async=false)
123
+ pos = Position2Code[pos] ? Position2Code[pos] : pos
124
+ flip = flip ? 1 : 0
125
+ adjusted = adjusted ? 1 : 0 # This setting is effective only when Destination is NG Card outlet
126
+ async = async ? 1 : 0
127
+
128
+ @dev.load_card(pos, flip, adjusted, async)
129
+ end
130
+
131
+ def move_card(pos=:retransfer, flip=false, adjusted=false, async=false)
132
+ pos = Position2Code[pos] ? Position2Code[pos] : pos
133
+ flip = flip ? 1 : 0
134
+ adjusted = adjusted ? 1 : 0 # This setting is effective only when Destination is NG Card outlet
135
+ async = async ? 1 : 0
136
+
137
+ @dev.move_card(pos, flip, adjusted, async)
138
+ end
139
+
140
+ def retransfer_and_eject(async=false)
141
+ async = async ? 1 : 0
142
+ @dev.retransfer_and_eject(async)
143
+ end
144
+
145
+ def retransfer_and_turn(async=false)
146
+ async = async ? 1 : 0
147
+ @dev.retransfer_and_turn(async)
148
+ end
149
+
150
+ MagFormat = {
151
+ jis2_7bit: [0x07, 69], # 69 charcters at most
152
+ iso1_6bit: [0x16, 76], # 76 charcters at most
153
+ iso1_7bit: [0x17, 69], # 69 charcters at most
154
+ iso2_4bit: [0x24, 37], # 37 charcters at most
155
+ iso3_4bit: [0x34, 104], # 104 charcters at most
156
+ iso3_7bit: [0x37, 69], # 69 charcters at most
157
+ }
158
+
159
+ def write_mag(format, data)
160
+ format, len = MagFormat[format] || format
161
+ @dev.write_mag(format, len, data)
162
+ end
163
+
164
+ def read_mag(format)
165
+ format, len = MagFormat[format] || format
166
+ @dev.read_mag(format, len)
167
+ end
168
+
169
+ IC_Types = {
170
+ contact: 0,
171
+ contactless: 1,
172
+ }
173
+
174
+ IC_Actions = {
175
+ contact: 0,
176
+ release: 1,
177
+ }
178
+
179
+ def ic_control(type, action)
180
+ type = IC_Types[type] || type
181
+ action = IC_Actions[action] || action
182
+ @dev.ic_control(type, action)
183
+ end
184
+
185
+ class AttrDescription < Struct.new(:name, :offs_read, :offs_write, :default, :typ, :params)
186
+ def to_attribute
187
+ ext_type, ext_params = case typ
188
+ when :byte
189
+ [ :int, params || (0..0xff) ]
190
+ when :word
191
+ [ :int, params || (0..0xffff) ]
192
+ when :dword
193
+ [ :int, params || (0..0xffffffff) ]
194
+ when :set, :ascii
195
+ [ typ, params ]
196
+ else
197
+ raise "invalid attr type #{typ}"
198
+ end
199
+ Attribute.new(name, !!offs_write, default, ext_type, ext_params)
200
+ end
201
+ end
202
+
203
+ Attribute = Struct.new(:name, :writeable, :default, :typ, :params, :value)
204
+
205
+ def self.to_attr_desc(hash)
206
+ hash.map do |key, args|
207
+ AttrDescription.new(key, *args).freeze
208
+ end.freeze
209
+ end
210
+
211
+ def self.make_range(hash)
212
+ byte_min = hash.inject(9999999){|m,(k, v)| [m, k].min }
213
+ byte_max = hash.inject(-9999999){|m,(k, v)| [m, k].max }
214
+ reverse = hash[byte_min].to_i > hash[byte_max].to_i
215
+ range = byte_min+1 .. byte_max-1
216
+ rhash = range.to_a.inject({}) do |h,k|
217
+ v = reverse ? byte_min + hash[byte_min].to_i - k : k - byte_min + hash[byte_min].to_i
218
+ h[k] = v.to_s # + " (#{k})"
219
+ h
220
+ end
221
+ rhash.merge(hash).sort_by{|k,v| k }.inject({}){|h,(k,v)| h[k]=v; h }
222
+ end
223
+
224
+ ModeSenseInkAttrs = to_attr_desc({
225
+ ink_code: [2, nil, nil, :set, {0x00 => 'YMCK', 0x02 => 'YMCK-PO', 0x03 => 'K', 0x04 => 'YMCKK', 0x05 => 'YMCK-UV'}],
226
+ ink_number_printed: [4, nil, nil, :word],
227
+ ink_lot_number: [8, nil, nil, :ascii, 6],
228
+ })
229
+
230
+ ModeSensePrintAttrs = to_attr_desc({
231
+ print_ink_code: [21, nil, nil, :set, {0 => 'YMCK', 2 => 'YMCK-PO', 3 => 'K', 4 => 'YMCKK', 5 => 'YMCK-UV'}],
232
+ print_resin_black_energy: [41, 13, 3, :set, make_range(0 => "-3 (bright)", 8 => "5 (dark)")],
233
+ print_resin_black_mode: [42, 14, 0, :set, {0 => 'Standard', 1 => 'Fine'}],
234
+ print_a0_energy: [43, 15, 3, :set, make_range(0 => "-3 (bright)", 8 => "5 (dark)")],
235
+ print_a1_energy: [44, 16, 3, :set, make_range(0 => "-3 (bright)", 8 => "5 (dark)")],
236
+ print_film_code: [20, 17, 0, :set, {0 => 'Standard (1000 panels)', 2 => 'Standard (750panels)'}],
237
+ print_roller_temp_retransfer: [33, 4, 4, :set, make_range(0 => "-3 (low)", 5 => "2 (high)")],
238
+ print_velocity_front: [34, 5, 0, :set, make_range(0 => "2 (Fast)", 12 => "-10 (Slow)")],
239
+ print_velocity_back: [35, 6, 0, :set, make_range(0 => "2 (Fast)", 12 => "-10 (Slow)")],
240
+
241
+ print_buzzer_mode: [45, 21, 0, :set, {0 => 'Buzzer is enabled', 1 => 'Buzzer is disabled'}],
242
+ print_power_save_minutes: [46, 22, 8, :set, {0 =>'5', 1 =>'10', 2 =>'15', 3 =>'20', 4 =>'25', 5 =>'30', 6 =>'45', 7 =>'60', 8 =>'Off'}],
243
+
244
+ print_roller_temp_card_fix: [36, 7, 3, :set, make_range(0 => "-5 (low)", 5 => "0 (high)").merge(10 => "Off")],
245
+ print_velocity_card_fix: [37, 8, 4, :set, make_range(0 => "-2 (slow)", 4 => "2 (fast)")],
246
+ print_peel_off_wait_seconds: [39, 10, 0, :byte, 0..15],
247
+
248
+ print_card_code: [22, 19, 0, :set, {0 => 'Standard', 2 => 'Thin card (Card thickness is 0.25mm)'}],
249
+ print_revision_number: [40, nil, nil, :byte],
250
+ print_film_quantity: [47, nil, nil, :byte, 0..10],
251
+ print_ink_quantity: [48, nil, nil, :byte, 0..50],
252
+ print_card_quantity: [49, nil, nil, :set, {0 => 'Greater than 25 cards', 1 => 'From 1 to 24 cards', 2 => 'No cards', 3 => 'Right Side Card loading mode'}],
253
+ print_resolution_x: [4, nil, nil, :word],
254
+ print_resolution_y: [6, nil, nil, :word],
255
+ print_card_size_x: [12, nil, nil, :word],
256
+ print_card_size_y: [14, nil, nil, :word],
257
+ print_mg_mode: [17, nil, nil, :set, {0 => 'None', 1 => 'MAG Encoder', 2 => 'JIS MAG Encoder'}],
258
+ print_ic_mode_contactless: [19, nil, nil, :set, {0 => 'None', 2 => 'External small IC Encoder', 3 => 'External large IC Encoder'}],
259
+ print_ic_mode_contact: [18, nil, nil, :set, {0 => 'None', 1 => 'Embedded IC Encoder', 2 => 'External IC Encoder'}],
260
+ print_position_x: [24, nil, nil, :word],
261
+ print_position_y: [26, nil, nil, :word],
262
+ print_size_x: [28, nil, nil, :word],
263
+ print_size_y: [30, nil, nil, :word],
264
+ })
265
+
266
+ ModeSenseEncodeAttrs = to_attr_desc({
267
+ mag_iso_mode: [2, 2, 0, :set, {0 => 'No ISO MAG encoder', 1 => '300 Oe (Lo-Co)', 2 => '2750 Oe (Hi-Co)'}],
268
+ mag_read_write_retry: [7, 7, 0, :byte, 0..3],
269
+ })
270
+
271
+ ModeSensePages = {
272
+ ink: [0x23, 4+40, [[ModeSenseInkAttrs, 0]]],
273
+ print: [0x28, 4+50, [[ModeSensePrintAttrs, 0]]],
274
+ mag: [0x2a, 4+10, [[ModeSenseEncodeAttrs, 0]]],
275
+ all: [0x3f, 4+100, [[ModeSenseInkAttrs, 0], [ModeSensePrintAttrs, 40], [ModeSenseEncodeAttrs, 40+50]]],
276
+ }
277
+
278
+ LogSenseAttrs = to_attr_desc({
279
+ log_total_count: [8, nil, nil, :dword],
280
+ log_free_count: [16, nil, nil, :dword],
281
+ log_head_count: [24, nil, nil, :dword],
282
+ log_cleaning_count: [32, nil, nil, :dword],
283
+ })
284
+
285
+ LogSensePages = {
286
+ log: [0x38, 36, [[LogSenseAttrs, 0]]],
287
+ }
288
+
289
+ def mode_sense(page_sym)
290
+ page, len, attr_lists = ModeSensePages[page_sym] || raise("invalid page: #{page_sym.inspect} not in #{ModeSensePages.keys.inspect}")
291
+ data = @dev.mode_sense(page, len)[4..-1]
292
+ lists = attr_lists.map do |attr_list, offset|
293
+ data_to_attrs(data[offset..-1], attr_list)
294
+ end
295
+ lists.inject([], &:+)
296
+ end
297
+
298
+ ModeSelectPages = {
299
+ print: [0x28, 23, [[ModeSensePrintAttrs, 0]]],
300
+ mag: [0x2a, 10, [[ModeSenseEncodeAttrs, 0]]],
301
+ }
302
+
303
+ def mode_select(page_sym, attrs={})
304
+ page, len, attr_lists = ModeSelectPages[page_sym] || raise("invalid page: #{page_sym.inspect} not in #{ModeSelectPages.keys.inspect}")
305
+
306
+ data = [0].pack("C") * len
307
+ data[0, 2] = [0x28, 0x15].pack("CC") if page == 0x28
308
+ data[0, 2] = [0x2a, 0x08].pack("CC") if page == 0x2a
309
+ lists = attr_lists.map do |attr_list, offset|
310
+ data[offset..-1] = attrs_to_data(attr_list, data[offset..-1], attrs)
311
+ end
312
+ raise "invalid data length #{data.bytesize}" if data.bytesize != len
313
+ @dev.mode_select(page, data)
314
+ end
315
+
316
+ def log_sense(page_sym)
317
+ page, len, attr_lists = LogSensePages[page_sym] || raise("invalid page: #{page_sym.inspect} not in #{LogSensePages.keys.inspect}")
318
+ data = @dev.log_sense(page, len)
319
+ lists = attr_lists.map do |attr_list, offset|
320
+ data_to_attrs(data[offset..-1], attr_list)
321
+ end
322
+ lists.inject([], &:+)
323
+ end
324
+
325
+ def log_select
326
+ @dev.log_select
327
+ end
328
+
329
+ def self.mode_sense_attrs(page_sym)
330
+ _page, _len, attr_lists = ModeSensePages[page_sym] || raise("invalid page: #{page_sym.inspect} not in #{ModeSensePages.keys.inspect}")
331
+ attr_lists.map(&:first).inject([], &:+).map{|a| a.to_attribute }
332
+ end
333
+
334
+ def self.log_sense_attrs(page_sym)
335
+ _page, _len, attr_lists = LogSensePages[page_sym] || raise("invalid page: #{page_sym.inspect} not in #{LogSensePages.keys.inspect}")
336
+ attr_lists.map(&:first).inject([], &:+).map{|a| a.to_attribute }
337
+ end
338
+
339
+ private
340
+
341
+ def data_to_attrs(data, attr_list)
342
+ attr_list.map do |attr|
343
+ val = case attr.typ
344
+ when :byte
345
+ data[attr.offs_read, 1].getbyte(0)
346
+ when :word
347
+ data[attr.offs_read, 2].unpack("n")[0]
348
+ when :dword
349
+ data[attr.offs_read, 4].unpack("N")[0]
350
+ when :set
351
+ data[attr.offs_read, 1].getbyte(0)
352
+ when :ascii
353
+ data[attr.offs_read, attr.params]
354
+ else
355
+ raise "invalid attr type #{attr.typ}"
356
+ end
357
+
358
+ nattr = attr.to_attribute
359
+ nattr.value = val
360
+ nattr
361
+ end
362
+ end
363
+
364
+ def attrs_to_data(attr_list, data, attrs)
365
+ data = data.dup
366
+ attrs.each do |name, value|
367
+ attr = attr_list.find{|a| a.name.to_s == name.to_s }
368
+ raise("invalid attr name #{name.inspect}") unless attr
369
+
370
+ case attr.typ
371
+ when :byte
372
+ if attr.params
373
+ raise("value out of range #{attr.params.inspect}: #{value.inspect}") unless attr.params === value
374
+ end
375
+ data[attr.offs_write, 1] = [value].pack("C")
376
+ when :word
377
+ if attr.params
378
+ raise("value out of range #{attr.params.inspect}: #{value.inspect}") unless attr.params === value
379
+ end
380
+ data[attr.offs_write, 2] = [value].pack("n")
381
+ when :dword
382
+ if attr.params
383
+ raise("value out of range #{attr.params.inspect}: #{value.inspect}") unless attr.params === value
384
+ end
385
+ data[attr.offs_write, 4] = [value].pack("N")
386
+ when :set
387
+ val = case value
388
+ when Integer then value
389
+ when String
390
+ attr.params[value] || raise("invalid set value #{value.inspect}")
391
+ else
392
+ raise("invalid set value #{value.inspect}")
393
+ end
394
+ data[attr.offs_write, 1] = [value].pack("C")
395
+ when :ascii
396
+ data[attr.offs_write, attr.params] = value
397
+ else
398
+ raise "invalid attr type #{attr.typ}"
399
+ end
400
+ end
401
+ data
402
+ end
403
+ end
404
+
405
+ class CX320_DLL < CX320
406
+ def self.devices(*args)
407
+ super(DeviceDll, *args)
408
+ end
409
+ end
410
+
411
+ class CX320_USB < CX320
412
+ def self.devices(*args)
413
+ super(DeviceUsb, *args)
414
+ end
415
+ end
416
+
417
+ class CX320_SIMU < CX320
418
+ def self.devices(*args)
419
+ super(DeviceSimu, *args)
420
+ end
421
+ end
422
+ end
@@ -0,0 +1,130 @@
1
+ require 'libcx320/c'
2
+
3
+ module LibCX320
4
+ class DeviceDll
5
+ extend ErrorHandling
6
+ include ErrorHandling
7
+
8
+ def self.devices
9
+ slot = FFI::MemoryPointer.new :int
10
+ id = FFI::MemoryPointer.new :int
11
+
12
+ devs = [];
13
+ begin
14
+ check_returncode C.CXCMD_ScanCX320(slot, id)
15
+ rescue NoPrinter, NoMorePrinter
16
+ else
17
+ devs << new(slot.read_int, id.read_int)
18
+ end
19
+
20
+ loop do
21
+ slot.write_int slot.read_int
22
+ id.write_int id.read_int
23
+
24
+ begin
25
+ check_returncode C.CXCMD_ScanCX320Next(slot, id)
26
+ rescue NoPrinter, NoMorePrinter
27
+ # Suche beim ersten Fehler beenden
28
+ break
29
+ else
30
+ devs << new(slot.read_int, id.read_int)
31
+ end
32
+ end
33
+ devs
34
+ end
35
+
36
+ def initialize(slot, id)
37
+ @slot = slot
38
+ @id = id
39
+ end
40
+
41
+ def connected?
42
+ slot = FFI::MemoryPointer.new :int
43
+ slot.write_int @slot
44
+ id = FFI::MemoryPointer.new :int
45
+ id.write_int @id
46
+
47
+ C.CXCMD_CheckIfConnected(slot, id)
48
+ end
49
+
50
+ def close
51
+ end
52
+
53
+ def ready?
54
+ check_returncode C.CXCMD_TestUnitReady(@slot, @id)
55
+ end
56
+
57
+ def rezero_unit
58
+ check_returncode C.CXCMD_RezeroUnit(@slot, @id)
59
+ end
60
+
61
+ def get_current_card_position
62
+ pos = FFI::MemoryPointer.new :char, 8
63
+ check_returncode C.CXCMD_ReadPosition(@slot, @id, pos)
64
+ pos.read_bytes(8)
65
+ end
66
+
67
+ def image_out(layer, data, buffer)
68
+ check_returncode C.CXCMD_ImageOut(@slot, @id, data, data.size, layer, buffer)
69
+ end
70
+
71
+ def print(color, buffer, async)
72
+ check_returncode C.CXCMD_Print(@slot, @id, color, buffer, async)
73
+ end
74
+
75
+ def load_card(pos, flip, adjusted, async)
76
+ check_returncode C.CXCMD_LoadCard(@slot, @id, pos, flip, adjusted, async)
77
+ end
78
+
79
+ def move_card(pos, flip, adjusted, async)
80
+ check_returncode C.CXCMD_MoveCard(@slot, @id, pos, flip, adjusted, async)
81
+ end
82
+
83
+ def retransfer_and_eject(async)
84
+ check_returncode C.CXCMD_RetransferAndEject(@slot, @id, async)
85
+ end
86
+
87
+ def retransfer_and_turn(async)
88
+ check_returncode C.CXCMD_RetransferAndTurn(@slot, @id, async)
89
+ end
90
+
91
+
92
+ def write_mag(format, _len, data)
93
+ cdata = FFI::MemoryPointer.from_string(data)
94
+ check_returncode C.CXCMD_WriteMagData(@slot, @id, cdata, data.bytesize, format)
95
+ end
96
+
97
+ def read_mag(format, _len)
98
+ cdata = FFI::MemoryPointer.new(:char, 105)
99
+ clen = FFI::MemoryPointer.new(:int)
100
+ clen.write_int cdata.size
101
+ check_returncode C.CXCMD_ReadMagData(@slot, @id, cdata, clen, format)
102
+ cdata.get_bytes(0, clen.read_int)
103
+ end
104
+
105
+ def ic_control(type, action)
106
+ check_returncode C.CXCMD_ICControl(@slot, @id, type, action)
107
+ end
108
+
109
+ def mode_sense(page, len)
110
+ cdata = FFI::MemoryPointer.new(:char, len)
111
+ check_returncode C.CXCMD_ModeSense(@slot, @id, page, cdata)
112
+ cdata.get_bytes(0, cdata.size)
113
+ end
114
+
115
+ def mode_select(page, data)
116
+ cdata = FFI::MemoryPointer.from_string(data)
117
+ check_returncode C.CXCMD_ModeSelect(@slot, @id, page, cdata)
118
+ end
119
+
120
+ def log_sense(page, len)
121
+ cdata = FFI::MemoryPointer.new(:char, len)
122
+ check_returncode C.CXCMD_LogSense(@slot, @id, page, cdata)
123
+ cdata.get_bytes(0, cdata.size)
124
+ end
125
+
126
+ def log_select
127
+ check_returncode C.CXCMD_LogSelect(@slot, @id)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,132 @@
1
+ module LibCX320
2
+ class DeviceSimu
3
+ include ErrorHandling
4
+
5
+ def self.devices
6
+ 2.times.map do |idx|
7
+ new(idx)
8
+ end
9
+ end
10
+
11
+ def initialize(devidx)
12
+ @devidx = devidx
13
+ @buffers = [{}, {}]
14
+ @card_pos = nil
15
+ @config = {
16
+ 0x23 => ["23:26:00:00:03:e8:00:00:59:48:34:31:34:31:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00".gsub(":","")].pack("H*"),
17
+ 0x28 => ["28:30:00:00:01:2c:01:2c:00:00:00:00:03:f5:02:7f:00:00:00:02:00:00:00:00:00:00:00:00:04:0c:02:98:00:04:00:00:03:04:00:00:01:03:00:03:03:00:03:06:22:01".gsub(":","")].pack("H*"),
18
+ 0x2a => ["2a:08:00:00:00:00:00:00:00:00".gsub(":","")].pack("H*"),
19
+ 0x38 => ["38:00:00:20:00:00:00:04:00:00:00:f5:00:01:00:04:00:00:00:00:00:02:00:04:00:00:04:90:00:03:00:04:00:00:00:f5".gsub(":","")].pack("H*"),
20
+ }
21
+ @config[0x3f] = @config[0x23] + @config[0x28] + @config[0x2a]
22
+ end
23
+
24
+ def close
25
+ end
26
+
27
+ def send_inquiry
28
+ "x" * 60
29
+ end
30
+
31
+ def log(text)
32
+ puts text
33
+ end
34
+ private :log
35
+
36
+ def ready?
37
+ log "ready?"
38
+ end
39
+
40
+ def rezero_unit
41
+ log "rezero_unit"
42
+ end
43
+
44
+ def get_current_card_position
45
+ [@card_pos ? 0x04 : 0x00, 0, 0, 0, 0, 0, 0, @card_pos].pack("CCCCCCCC")
46
+ end
47
+
48
+ def image_out(layer, data, buffer)
49
+ @buffers[buffer][layer] = data
50
+ end
51
+
52
+ def print(color, buffer, async)
53
+ log "print(#{color}, #{buffer}, #{async})"
54
+
55
+ if @buffers[buffer][1] && @buffers[buffer][2] && @buffers[buffer][3]
56
+ pic = Magick::Image.new(1036, 664)
57
+ pic.import_pixels(0, 0, 1036, 664, "R", @buffers[buffer][1])
58
+ pic.import_pixels(0, 0, 1036, 664, "G", @buffers[buffer][2])
59
+ pic.import_pixels(0, 0, 1036, 664, "B", @buffers[buffer][3])
60
+ begin
61
+ pic.display
62
+ rescue
63
+ pic.write("cx320-cmy.jpeg")
64
+ end
65
+ end
66
+ if @buffers[buffer][0]
67
+ pic = Magick::Image.new(1036, 664)
68
+ %w[R G B].each do |color|
69
+ pic.import_pixels(0, 0, 1036, 664, color, @buffers[buffer][0])
70
+ end
71
+ begin
72
+ pic.display
73
+ rescue
74
+ pic.write("cx320-k.jpeg")
75
+ end
76
+ end
77
+ end
78
+
79
+ def load_card(pos, flip, adjusted, async)
80
+ log "load_move_card(#{pos}, #{flip}, #{adjusted}, #{async})"
81
+ raise CommandSequenceError.new("card is already loaded", -0x01052A00) if @card_pos
82
+ @card_pos = pos
83
+ end
84
+
85
+ def move_card(pos, flip, adjusted, async)
86
+ log "load_move_card(#{pos}, #{flip}, #{adjusted}, #{async})"
87
+ raise CommandSequenceError.new("no card loaded", -0x01052A00) unless @card_pos
88
+ @card_pos = pos
89
+ end
90
+
91
+ def retransfer_and_eject(async)
92
+ log "load_move_card(#{async})"
93
+ raise CommandSequenceError.new("card is not in position retransfer", -0x01052A00) if @card_pos != 0
94
+ @card_pos = nil
95
+ end
96
+
97
+ def retransfer_and_turn(async)
98
+ log "load_move_card(#{async})"
99
+ raise CommandSequenceError.new("card is not in position retransfer", -0x01052A00) if @card_pos != 0
100
+ end
101
+
102
+ def write_mag(format, len, data)
103
+ log "write_mag(#{format}, #{len}, #{data.inspect})"
104
+ end
105
+
106
+ def read_mag(format, len)
107
+ "x" * len
108
+ end
109
+
110
+ def ic_control(type, action)
111
+ log "write_mag(#{type}, #{action})"
112
+ end
113
+
114
+ def mode_sense(page, len)
115
+ log "mode_sense(#{page}, #{len})"
116
+ [len - 1, 0, 0x10, 0].pack("CCCC") + @config[page]
117
+ end
118
+
119
+ def mode_select(page, data)
120
+ log "mode_select(#{page}, #{data.unpack("H*")[0]})"
121
+ end
122
+
123
+ def log_sense(page, len)
124
+ log "log_sense(#{page}, #{len})"
125
+ @config[page]
126
+ end
127
+
128
+ def log_select
129
+ log "log_select()"
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,220 @@
1
+ require 'libusb'
2
+
3
+ module LibCX320
4
+ class DeviceUsb
5
+ include ErrorHandling
6
+
7
+ attr_reader :devh
8
+
9
+ def self.devices
10
+ @@ctx = LIBUSB::Context.new
11
+
12
+ @@ctx.devices(idVendor: 0x04f1, idProduct: [0x4030, 0x4033]).map.with_index do |dev, devidx|
13
+ new(dev, devidx)
14
+ end
15
+ end
16
+
17
+ def bulk_transfer(**kwargs)
18
+ puts kwargs.inspect[0, 90]
19
+ @devh.bulk_transfer(**kwargs)
20
+ end
21
+
22
+ def send_command(cdb, data_length, direction=LIBUSB::ENDPOINT_IN)
23
+ ensure_open
24
+ @tag += 1
25
+ expected_tag = @tag
26
+ lun = 0
27
+ len = direction==LIBUSB::ENDPOINT_IN ? data_length : data_length.bytesize
28
+
29
+ cbw = ['USBC', expected_tag, len || 0, direction, lun, cdb.length, cdb].pack('a*VVCCCa*')
30
+ cbw = cbw.ljust(31, "\0")
31
+
32
+ bulk_transfer(endpoint: 0x02, dataOut: cbw)
33
+
34
+ if data_length && direction==LIBUSB::ENDPOINT_IN
35
+ recv = bulk_transfer(endpoint: 0x81, dataIn: data_length)
36
+ if recv[0,4] == "USBC".freeze
37
+ return check_status_urb(recv, expected_tag)
38
+ end
39
+ elsif data_length
40
+ recv_len = 0
41
+ while data_length && !data_length.empty?
42
+ begin
43
+ edata = data_length.slice!(0...0x10000)
44
+ recv_len += bulk_transfer(endpoint: 0x02, dataOut: edata)
45
+ rescue LIBUSB::ERROR_PIPE
46
+ @devh.clear_halt(0x02)
47
+ recv = bulk_transfer(endpoint: 0x81, dataIn: 13, timeout: 1)
48
+ return check_status_urb(recv, expected_tag)
49
+ end
50
+ end
51
+ end
52
+
53
+ retries = 5
54
+ begin
55
+ buffer = bulk_transfer(endpoint: 0x81, dataIn: 13, timeout: 999999999)
56
+ check_status_urb(buffer, expected_tag)
57
+ rescue LIBUSB::ERROR_PIPE, UnexpectedPacket
58
+ if (retries-=1)>=0
59
+ @devh.clear_halt(0x81)
60
+ retry
61
+ end
62
+ raise
63
+ end
64
+
65
+ return recv
66
+ end
67
+
68
+ def check_status_urb(buffer, expected_tag)
69
+ dCSWSignature, dCSWTag, dCSWDataResidue, bCSWStatus = buffer.unpack('a4VVC')
70
+
71
+ raise UnexpectedPacket, "Unexpected USB packet received" if expected_tag != dCSWTag
72
+ if bCSWStatus != 0
73
+ check_returncode(request_sense_error)
74
+ end
75
+ end
76
+
77
+ def initialize(dev, devidx)
78
+ @dev = dev
79
+ @devidx = devidx
80
+ @tag = 0
81
+ @devh = nil
82
+ end
83
+
84
+ def ensure_open
85
+ return @devh if @devh
86
+ @devh = @dev.open
87
+ @devh.claim_interface(0)
88
+
89
+ # loop do
90
+ # begin
91
+ # bulk_transfer(endpoint: 0x02, dataOut: "USBC\x01\x00\x00\x00`\x00\x00\x00\x80\x00\x06\x12\x00\x00\x00`\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00")
92
+ # p ["clear"]
93
+ # bulk_transfer(endpoint: 0x81, dataIn: 1300, timeout: 100)
94
+ # rescue LIBUSB::ERROR_TIMEOUT
95
+ # break
96
+ # end
97
+ # end
98
+
99
+ send_inquiry
100
+
101
+ @devh
102
+ end
103
+
104
+ def close
105
+ if @devh
106
+ @devh.release_interface(0)
107
+ @devh.close
108
+ end
109
+ end
110
+
111
+ def send_inquiry
112
+ expected_length = 0x60 # INQUIRY_LENGTH
113
+ cdb = [ 0x12, 0, 0, # Inquiry
114
+ expected_length, 0,
115
+ ].pack('CCCnC')
116
+
117
+ send_command( cdb, expected_length )
118
+ end
119
+
120
+ def request_sense_error
121
+ expected_length = 0x14
122
+ cdb = [ 0x03, 0, 0, expected_length, 0].pack('CCCnC')
123
+ res = send_command( cdb, expected_length )
124
+
125
+ -( 0x01 << 24 | res.getbyte(0x02) << 16 | res.getbyte(0x0c) << 8 | 0 )
126
+ end
127
+
128
+ def ready?
129
+ cdb = [ 0, 0].pack('Nn')
130
+ send_command( cdb, nil)
131
+ end
132
+
133
+ def rezero_unit
134
+ cdb = [ 1, 0, 0].pack('CCN')
135
+ send_command( cdb, nil)
136
+ end
137
+
138
+ def get_current_card_position
139
+ start = 0
140
+ cdb = [ 0x34, 0, # Pre-Fetch(10)
141
+ start, 0,
142
+ 0, 0,
143
+ ].pack('CCNCnC')
144
+ expected_length = 0x08
145
+
146
+ send_command(cdb, expected_length)
147
+ end
148
+
149
+ def image_out(layer, data, buffer)
150
+ cdb = [ 0x2a, 0, layer + buffer*8, 0, 0, data.bytesize, 0].pack('CCCCCNC')
151
+ send_command( cdb, data, LIBUSB::ENDPOINT_OUT )
152
+ end
153
+
154
+ def load_move_card(scode, p1, p2, pos)
155
+ cdb = [ 0x31, scode, # load card
156
+ p1, 0,
157
+ p2, 0, pos, 0,
158
+ ].pack('CCCCCnCn')
159
+ send_command(cdb, nil)
160
+ end
161
+
162
+ def print(color, buffer, async)
163
+ load_move_card(0x08, async + color*2, buffer, 0)
164
+ end
165
+
166
+ def load_card(pos, flip, adjusted, async)
167
+ load_move_card(0x01, async, flip*2 + adjusted*4, pos)
168
+ end
169
+
170
+ def move_card(pos, flip, adjusted, async)
171
+ load_move_card(0x0b, async, flip*2 + adjusted*4, pos)
172
+ end
173
+
174
+ def retransfer_and_eject(async)
175
+ load_move_card(0x09, async, 0, 0)
176
+ end
177
+
178
+ def retransfer_and_turn(async)
179
+ load_move_card(0x0a, async, 0, 0)
180
+ end
181
+
182
+
183
+ def write_mag(format, len, data)
184
+ cdb = [ 0x2f, 0, format, 0, data.bytesize, 0].pack('CNCCnC')
185
+ send_command( cdb, data, LIBUSB::ENDPOINT_OUT )
186
+ end
187
+
188
+ def read_mag(format, len)
189
+ cdb = [ 0x2e, 0, format, 0, len, 0].pack('CNCCnC')
190
+ send_command( cdb, len )
191
+ end
192
+
193
+ def ic_control(type, action)
194
+ cdb = [ 0x32, type*4 + action, 0, 0].pack('CCNN')
195
+ send_command( cdb, nil )
196
+ end
197
+
198
+ def mode_sense(page, len)
199
+ expected_length = len
200
+ cdb = [ 0x1a, 0, page, 0, expected_length, 0].pack('CCCCCC')
201
+ send_command( cdb, expected_length )
202
+ end
203
+
204
+ def mode_select(page, data)
205
+ cdb = [ 0x15, 0x10, page, 0, data.bytesize, 0].pack('CCCCCC')
206
+ send_command( cdb, data, LIBUSB::ENDPOINT_OUT )
207
+ end
208
+
209
+ def log_sense(page, len)
210
+ expected_length = len
211
+ cdb = [ 0x4d, 0, 0x40 | page, 0, 0, expected_length, 0].pack('CCCnnnC')
212
+ send_command( cdb, expected_length )
213
+ end
214
+
215
+ def log_select
216
+ cdb = [ 0x4c, 0x03, 0xc0, 0x00, 0].pack('CCCCN')
217
+ send_command( cdb, nil )
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,129 @@
1
+ module LibCX320
2
+ module ErrorHandling
3
+ class Error < RuntimeError
4
+ end
5
+
6
+ class UnexpectedPacket < Error
7
+ end
8
+
9
+ class PrinterError < Error
10
+ attr_reader :code
11
+ def initialize(text, code)
12
+ super(text)
13
+ @code = code
14
+ end
15
+ end
16
+
17
+ class UnknownPrinterError < PrinterError
18
+ end
19
+
20
+ class BusyError < PrinterError
21
+ end
22
+
23
+ ErrorById = {
24
+ 0x0102D000 => ["No card", "There is no card, or the hopper tray is not closed."],
25
+ 0x0102D100 => ["Door Open", "Printer door is opened."],
26
+ 0x0102D300 => ["Busy of Transporting", "Busy because of transporting card or retransferring. Note: This error is not returnd from functions. Control Function returns positive value as BUSY."],
27
+ 0x0102D400 => ["Busy of Printing", "Busy because of printing. Note: This error is not returnd from functions. Control Function returns positive value as BUSY."],
28
+ 0x0102D500 => ["Busy of Transporting and Printing", "Busy because of both “Busy of Transporting” and “Busy of Transporting and Printing”. Note: This error is not returnd from functions. Control Function returns positive value as BUSY."],
29
+ 0x0102D600 => ["No Cassette", "Ink ribbon cassette is not attached, or/and Retransfer film cassette is not attached."],
30
+ 0x0102D700 => ["No Cleaning Ro.", "Cleaning roller is not attached."],
31
+ 0x0102DA00 => ["Preheating", "Printer is on the way of preheating."],
32
+ 0x0102DB00 => ["Initializing", "Printer is on the way of initializing."],
33
+ 0x0102DC00 => ["Testing or Cleaning", "Printer is on the way of Off-line Test or cleaning."],
34
+ 0x0102DD00 => ["On Setting or Transport Mode", "Printer is in the setting mode or transporting mode."],
35
+ 0x0102DE00 => ["Not Ready for Download", "Firmware download cannot be done as printer is not in Download mode."],
36
+ 0x0102FD00 => ["Sleeping", "Printer is in the power save mode. Note) To exit this, initializing printer, which is pressing ENTER button after RESET button or sending REZERO command, is required."],
37
+ 0x0102FE00 => ["Password Error", "Password certification is not done."],
38
+
39
+
40
+ 0x01039000 => ["Jam(Hopper)", "The card does not arrive the card supply sensor within a predefined time."],
41
+ 0x01039100 => ["Jam(TurnOver)", "The card does not arrive the sensor inside the turnover unit within a predefined time."],
42
+ 0x01039200 => ["Jam(MG)", "The card does not arrive at the card edge sensor within a predefined time after leaving turnover unit. Also in case of magnetic encoding, when detection by the start position sensor of the MG unit is not possible."],
43
+ 0x01039300 => ["Jam(Transfer)", "The card does not arrive the card outlet sensor within a predefined time after leaving the card edge sensor."],
44
+ 0x01039400 => ["Jam(Discharge)", "The card stops at the card outlet sensor."],
45
+ 0x01039500 => ["Load Failure", "The card is not loaded within 10 seconds in Right Side Card Loading mode. Note) Load Card command can be accepted even if this error is activated."],
46
+ 0x0103A000 => ["Media Broken", "Retransfer film is broken."],
47
+ 0x0103A100 => ["Media Search", "Mark on the retransfer film could not be detected."],
48
+ 0x0103AD00 => ["MG Write Error", "Writing error to the magnetic stripe happens."],
49
+ 0x0103AE00 => ["MG Read Error", "Reading error from the magnetic stripe happens."],
50
+ 0x0103B000 => ["Ink Broken", "Ink ribbon is broken."],
51
+ 0x0103B100 => ["Ink Search", "Mark on the ink ribbon could not be detected, or TAG on the ink ribbon is invalid."],
52
+ 0x0103BB00 => ["EXT. Jam", "Card jam happens in the external IC unit."],
53
+
54
+
55
+ 0x01044400 => ["Hardware Timeout", "Time out was detected by the printer firmware."],
56
+ 0x0104A900 => ["MG Unconnected", "MG unit is not attached correctly."],
57
+ 0x0104AB00 => ["MG Mechanical", "Mechanical error happens in the MG unit."],
58
+ 0x0104AC00 => ["MG Hardware", "Hardware error happens in the MG unit."],
59
+ 0x0104AF00 => ["MG Communicate", "Communication error happens between printer and MG unit."],
60
+ 0x0104B900 => ["EXT. Unconnected", "External IC unit is not attached correctly."],
61
+ 0x0104BA00 => ["EXT. SW Setting", "Dip switch setting in the external IC unit is not correct."],
62
+ 0x0104BE00 => ["EXT. Communicate", "Communication error happens between printer and external IC unit."],
63
+ 0x0104BF00 => ["EXT2. Communicate", "Communication error happens between printer and laminator."],
64
+ 0x0104C000 => ["Turn Over Unit", "Turnover unit is out of order."],
65
+ 0x0104C100 => ["Heater Cam", "Heater Cam is out order."],
66
+ 0x0104D800 => ["Hardware", "Circuit trouble was detected at the initialization. Ex. Vth power cannot be put out from the power supply unit."],
67
+ 0x0104F000 => ["TR Overheat", "The temperature of retransfer roller is too hot."],
68
+ 0x0104F100 => ["TR Broken", "Retransfer roller is out of order."],
69
+ 0x0104F200 => ["TR Sensor Broken", "Retransfer roller thermister is out of order."],
70
+ 0x0104F300 => ["RR Overheat", "The temperature of bend remdil roller is too hot."],
71
+ 0x0104F400 => ["RR Broken", "Bend remdil roller is out of order."],
72
+ 0x0104F500 => ["RR Sensor Broken", "Bend remdil roller thermister is out of order."],
73
+ 0x0104F600 => ["Overcool", "The temperature in the printer is too cool."],
74
+ 0x0104F800 => ["Head Overheat", "The temperature of the thermal head is too hot."],
75
+ 0x0104FA00 => ["EEPROM Broken", "EEPROM on the CPU circuit board or the head EEPROM is defective."],
76
+
77
+
78
+ 0x01051A00 => ["Parameter List Length Error", "The content of command is invalid. Parameter list length value in CDB or Page Data is invalid."],
79
+ 0x01052000 => ["Invalid Command Operation Code", "The content of command is invalid. Operation Code in CDB is invalid."],
80
+ 0x01052400 => ["Illegal Field in CDB", "The content of command is invalid. The data in CDB is invalid."],
81
+ 0x01052500 => ["Invalid LUN", "The content of command is invalid. LUN value in CDB is invalid."],
82
+ 0x01052600 => ["Invalid Field in Parameter List", "The content of command is invalid. The data in Page Data is invalid."],
83
+ 0x01052700 => ["Invalid Color Code in CDB", "Invalid ink is specified.."],
84
+ 0x01052A00 => ["Command Sequence Error", "The command is issued in bad order. Ex. Load Card is done when the card is in the printer."],
85
+ 0x01052B00 => ["MG Data Error", "MG data from the host computer is invalid."],
86
+ 0x01052C00 => ["IC Encoder not installed", "There is no specified IC Encoder."],
87
+ 0x01052D00 => ["MG Encoder not installed", "There is no specified MG Encoder."],
88
+ 0x0105FB00 => ["Invalid Download Data", "Download data from the host computer is invalid."],
89
+ 0x01062800 => ["Medium Changed", "Printer was initialized by pressing RESET button."],
90
+ 0x01062900 => ["Power On or Bus Device Reset Occurred", "Printer was initialized by turning on the printer power."],
91
+ 0x0142A200 => ["Media Run Out", "End of retransfer film is detected."],
92
+ 0x0142B200 => ["Ink Run Out", "End of ink ribbon is detected."],
93
+
94
+ 0x02000006 => ["No Printer", "No printer found."],
95
+ 0x09000002 => ["No More Printer", "No further printer found."],
96
+
97
+ -1 => ["Busy Port Manager", "CX Port Manager did not send command to the printer because of Printer’s condition. This error never happens."],
98
+ -2 => ["Busy Target", "Card Printer rejected the command because it is on the way of moving the card."],
99
+ -3 => ["Busy Busy", "CX-320 Control DLL rejected the command because the command issued by other process is on the way of processing."],
100
+ -4 => ["Busy Target2", "Card Printer rejected the command because it is on the way of printing on the retransfer film."],
101
+ -5 => ["Busy Target3", "Card Printer rejected the command because of both _TARGET_BUSY1 and _TARGET_BUSY2."],
102
+ }
103
+
104
+ ErrorById.each do |id, tt|
105
+ name, text = tt
106
+ klname = name.gsub(/[^a-z0-9]/i, " ").gsub(/ +([a-z])/i){ $1.upcase }.strip
107
+ base_klass = case klname
108
+ when /^Busy/ then BusyError
109
+ else PrinterError
110
+ end
111
+ klass = Class.new(base_klass)
112
+ const_set(klname, klass)
113
+ tt << klass
114
+ end
115
+
116
+ def check_returncode(code)
117
+ return code if code==0
118
+ mc = -code
119
+ codes = [mc >> 24 & 0xff, mc >> 16 & 0xff, mc >> 8 & 0xff, mc & 0xff]
120
+ klname, text, klass = ErrorById[mc]
121
+
122
+ if klname
123
+ raise klass.new("CX320: %s (code %02x %02x %02x %02x)" % [text, *codes], code)
124
+ else
125
+ raise UnknownPrinterError.new("CX320: error %02x %02x %02x %02x" % codes, code)
126
+ end
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,3 @@
1
+ module LibCX320
2
+ VERSION = "0.1.5"
3
+ end
data/lib/libcx320.rb ADDED
@@ -0,0 +1,9 @@
1
+ require "libcx320/version"
2
+ require "libcx320/error_handling"
3
+ require "libcx320/cx320"
4
+
5
+ module LibCX320
6
+ autoload :DeviceDll, "libcx320/device_dll"
7
+ autoload :DeviceUsb, "libcx320/device_usb"
8
+ autoload :DeviceSimu, "libcx320/device_simu"
9
+ end
data/libcx320.gemspec ADDED
@@ -0,0 +1,23 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'libcx320/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "libcx320"
8
+ spec.version = LibCX320::VERSION
9
+ spec.authors = ["Lars Kanis"]
10
+ spec.email = ["lars@greiz-reinsdorf.de"]
11
+ spec.summary = %q{Driver for Retransfer Printer CX-320}
12
+ spec.description = %q{Driver for Retransfer Printer CX-320. Usable per PCP05CT.DLL or LIBUSB.}
13
+ spec.homepage = "https://github.com/larskanis/libcx320"
14
+ spec.license = "MIT"
15
+
16
+ spec.files = `git ls-files -z`.split("\x0")
17
+ spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
+ spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
+ spec.require_paths = ["lib"]
20
+
21
+ spec.add_development_dependency "bundler", "~> 1.7"
22
+ spec.add_development_dependency "rake", "~> 10.0"
23
+ end
data.tar.gz.sig ADDED
@@ -0,0 +1,2 @@
1
+ v��nqI�x}b����m�+P�sI�4܈i�e��A�W�N�U�����Y�+{?.�2=����[Z9���n���Q�D���k�3�\��d�V��|����N(G��U�D��j�4}ڀ��a"�Ct�@I�>s�
2
+ ��fQdg�3��N���Er���짰�Ɔ����ƍz����*��Q"��c��h���f��U;�5����n�?~f��� �1�������c�:�������[`ucz5=�`p�UN��сV7dLKoPF�ɫC�� ��rٙq^i�EL����C������RD�U$�G�[���IĽ������p�pl|�|�0}T���=%M��jYn�Vm��פ���Q@%b�C�h���D�mr��GD���Y
metadata ADDED
@@ -0,0 +1,107 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: libcx320
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.5
5
+ platform: ruby
6
+ authors:
7
+ - Lars Kanis
8
+ bindir: bin
9
+ cert_chain:
10
+ - |
11
+ -----BEGIN CERTIFICATE-----
12
+ MIIEBDCCAmygAwIBAgIBBDANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQDDB1sYXJz
13
+ L0RDPWdyZWl6LXJlaW5zZG9yZi9EQz1kZTAeFw0yNjAxMDUxMTE5MzRaFw0yNzAx
14
+ MDUxMTE5MzRaMCgxJjAkBgNVBAMMHWxhcnMvREM9Z3JlaXotcmVpbnNkb3JmL0RD
15
+ PWRlMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAwum6Y1KznfpzXOT/
16
+ mZgJTBbxZuuZF49Fq3K0WA67YBzNlDv95qzSp7V/7Ek3NCcnT7G+2kSuhNo1FhdN
17
+ eSDO/moYebZNAcu3iqLsuzuULXPLuoU0GsMnVMqV9DZPh7cQHE5EBZ7hlzDBK7k/
18
+ 8nBMvR0mHo77kIkapHc26UzVq/G0nKLfDsIHXVylto3PjzOumjG6GhmFN4r3cP6e
19
+ SDfl1FSeRYVpt4kmQULz/zdSaOH3AjAq7PM2Z91iGwQvoUXMANH2v89OWjQO/NHe
20
+ JMNDFsmHK/6Ji4Kk48Z3TyscHQnipAID5GhS1oD21/WePdj7GhmbF5gBzkV5uepd
21
+ eJQPgWGwrQW/Z2oPjRuJrRofzWfrMWqbOahj9uth6WSxhNexUtbjk6P8emmXOJi5
22
+ chQPnWX+N3Gj+jjYxqTFdwT7Mj3pv1VHa+aNUbqSPpvJeDyxRIuo9hvzDaBHb/Cg
23
+ 9qRVcm8a96n4t7y2lrX1oookY6bkBaxWOMtWlqIprq8JZXM9AgMBAAGjOTA3MAkG
24
+ A1UdEwQCMAAwCwYDVR0PBAQDAgSwMB0GA1UdDgQWBBQ4h1tIyvdUWtMI739xMzTR
25
+ 7EfMFzANBgkqhkiG9w0BAQsFAAOCAYEAg/1LuXN3X8xwHVnhRvmBCZYkNErko40y
26
+ juq/qPF9vkPGxLEGaeZF1rv/obTs5SgIGEUkWdRsOl3F6bQN4MYUFlN/n6rPx19g
27
+ CqUMkmRtuFD+9EFBI4twoF2IJS0pYr9tkjUq8mb0VXblvfbEEUf460BJmuBXZTc6
28
+ OoLQHxjhhqhKBoP4lHXg/OMK9dnGn8+5DoKcsyWQvqq/GdK8pi4E47M/egzw54Go
29
+ g+oeyGDsNKOQlnIA9gbyPpExD1+akJ4v88T8jOUnsOkhBBUkpSktC2QmEYIU5e9j
30
+ N7muw6O5Bz3CQuSWIEjj9mMUS2fEEfq2km6zO5vs5eD6TdFnt8AC/HlOrPaxGcUX
31
+ Hjw/K7ZTvZLEb4awRijdy4wx3OlL9FAyZPjYOh8TdJrLl076c7GyimAkgnc8BrL5
32
+ g1vGc759o2t3KNnlUg8VwqkhFJp4gCko1QO/8Io5hPQZOvJw8dmqNiiiHqaDupfl
33
+ CI4mk2K8yQa8xtQ/RmFZxYS5XbHhDJCw
34
+ -----END CERTIFICATE-----
35
+ date: 1980-01-02 00:00:00.000000000 Z
36
+ dependencies:
37
+ - !ruby/object:Gem::Dependency
38
+ name: bundler
39
+ requirement: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - "~>"
42
+ - !ruby/object:Gem::Version
43
+ version: '1.7'
44
+ type: :development
45
+ prerelease: false
46
+ version_requirements: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '1.7'
51
+ - !ruby/object:Gem::Dependency
52
+ name: rake
53
+ requirement: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - "~>"
56
+ - !ruby/object:Gem::Version
57
+ version: '10.0'
58
+ type: :development
59
+ prerelease: false
60
+ version_requirements: !ruby/object:Gem::Requirement
61
+ requirements:
62
+ - - "~>"
63
+ - !ruby/object:Gem::Version
64
+ version: '10.0'
65
+ description: Driver for Retransfer Printer CX-320. Usable per PCP05CT.DLL or LIBUSB.
66
+ email:
67
+ - lars@greiz-reinsdorf.de
68
+ executables: []
69
+ extensions: []
70
+ extra_rdoc_files: []
71
+ files:
72
+ - ".gitignore"
73
+ - Gemfile
74
+ - LICENSE.txt
75
+ - README.md
76
+ - Rakefile
77
+ - lib/libcx320.rb
78
+ - lib/libcx320/c.rb
79
+ - lib/libcx320/cx320.rb
80
+ - lib/libcx320/device_dll.rb
81
+ - lib/libcx320/device_simu.rb
82
+ - lib/libcx320/device_usb.rb
83
+ - lib/libcx320/error_handling.rb
84
+ - lib/libcx320/version.rb
85
+ - libcx320.gemspec
86
+ homepage: https://github.com/larskanis/libcx320
87
+ licenses:
88
+ - MIT
89
+ metadata: {}
90
+ rdoc_options: []
91
+ require_paths:
92
+ - lib
93
+ required_ruby_version: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - ">="
96
+ - !ruby/object:Gem::Version
97
+ version: '0'
98
+ required_rubygems_version: !ruby/object:Gem::Requirement
99
+ requirements:
100
+ - - ">="
101
+ - !ruby/object:Gem::Version
102
+ version: '0'
103
+ requirements: []
104
+ rubygems_version: 4.0.16
105
+ specification_version: 4
106
+ summary: Driver for Retransfer Printer CX-320
107
+ test_files: []
metadata.gz.sig ADDED
Binary file