ffi-gphoto2 0.2.0

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.
Files changed (77) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.rspec +2 -0
  4. data/Gemfile +4 -0
  5. data/LICENSE.txt +22 -0
  6. data/README.md +90 -0
  7. data/Rakefile +6 -0
  8. data/examples/intervalometer.rb +12 -0
  9. data/examples/live_view.rb +21 -0
  10. data/ffi-gphoto2.gemspec +30 -0
  11. data/lib/ffi/gphoto2.rb +85 -0
  12. data/lib/ffi/gphoto2/camera.rb +12 -0
  13. data/lib/ffi/gphoto2/camera_abilities.rb +37 -0
  14. data/lib/ffi/gphoto2/camera_abilities_list.rb +15 -0
  15. data/lib/ffi/gphoto2/camera_capture_type.rb +8 -0
  16. data/lib/ffi/gphoto2/camera_driver_status.rb +9 -0
  17. data/lib/ffi/gphoto2/camera_event_type.rb +10 -0
  18. data/lib/ffi/gphoto2/camera_file.rb +28 -0
  19. data/lib/ffi/gphoto2/camera_file_access_type.rb +8 -0
  20. data/lib/ffi/gphoto2/camera_file_operation.rb +11 -0
  21. data/lib/ffi/gphoto2/camera_file_path.rb +9 -0
  22. data/lib/ffi/gphoto2/camera_file_type.rb +11 -0
  23. data/lib/ffi/gphoto2/camera_folder_operation.rb +10 -0
  24. data/lib/ffi/gphoto2/camera_list.rb +15 -0
  25. data/lib/ffi/gphoto2/camera_operation.rb +12 -0
  26. data/lib/ffi/gphoto2/camera_widget.rb +33 -0
  27. data/lib/ffi/gphoto2/camera_widget_type.rb +14 -0
  28. data/lib/ffi/gphoto2/entry.rb +9 -0
  29. data/lib/ffi/gphoto2/gp_context.rb +31 -0
  30. data/lib/ffi/gphoto2/gphoto_device_type.rb +7 -0
  31. data/lib/ffi/gphoto2_port.rb +31 -0
  32. data/lib/ffi/gphoto2_port/gp_port_info.rb +11 -0
  33. data/lib/ffi/gphoto2_port/gp_port_info_list.rb +14 -0
  34. data/lib/ffi/gphoto2_port/gp_port_result.rb +35 -0
  35. data/lib/ffi/gphoto2_port/gp_port_type.rb +12 -0
  36. data/lib/gphoto2.rb +41 -0
  37. data/lib/gphoto2/camera.rb +219 -0
  38. data/lib/gphoto2/camera_abilities.rb +44 -0
  39. data/lib/gphoto2/camera_abilities_list.rb +64 -0
  40. data/lib/gphoto2/camera_file.rb +69 -0
  41. data/lib/gphoto2/camera_file_path.rb +21 -0
  42. data/lib/gphoto2/camera_folder.rb +82 -0
  43. data/lib/gphoto2/camera_list.rb +43 -0
  44. data/lib/gphoto2/camera_widgets/camera_widget.rb +112 -0
  45. data/lib/gphoto2/camera_widgets/date_camera_widget.rb +19 -0
  46. data/lib/gphoto2/camera_widgets/menu_camera_widget.rb +4 -0
  47. data/lib/gphoto2/camera_widgets/radio_camera_widget.rb +41 -0
  48. data/lib/gphoto2/camera_widgets/range_camera_widget.rb +37 -0
  49. data/lib/gphoto2/camera_widgets/section_camera_widget.rb +4 -0
  50. data/lib/gphoto2/camera_widgets/text_camera_widget.rb +14 -0
  51. data/lib/gphoto2/camera_widgets/toggle_camera_widget.rb +18 -0
  52. data/lib/gphoto2/camera_widgets/window_camera_widget.rb +4 -0
  53. data/lib/gphoto2/context.rb +31 -0
  54. data/lib/gphoto2/entry.rb +38 -0
  55. data/lib/gphoto2/port_info.rb +70 -0
  56. data/lib/gphoto2/port_info_list.rb +46 -0
  57. data/lib/gphoto2/port_result.rb +7 -0
  58. data/lib/gphoto2/version.rb +3 -0
  59. data/spec/gphoto2/camera_abilities_list_spec.rb +45 -0
  60. data/spec/gphoto2/camera_abilities_spec.rb +38 -0
  61. data/spec/gphoto2/camera_file_path_spec.rb +27 -0
  62. data/spec/gphoto2/camera_file_spec.rb +71 -0
  63. data/spec/gphoto2/camera_folder_spec.rb +110 -0
  64. data/spec/gphoto2/camera_list_spec.rb +35 -0
  65. data/spec/gphoto2/camera_spec.rb +292 -0
  66. data/spec/gphoto2/camera_widgets/date_camera_widget_spec.rb +15 -0
  67. data/spec/gphoto2/camera_widgets/radio_camera_widget_spec.rb +31 -0
  68. data/spec/gphoto2/camera_widgets/range_camera_widget_spec.rb +27 -0
  69. data/spec/gphoto2/camera_widgets/text_camera_widget_spec.rb +15 -0
  70. data/spec/gphoto2/camera_widgets/toggle_camera_widget_spec.rb +21 -0
  71. data/spec/gphoto2/context_spec.rb +17 -0
  72. data/spec/gphoto2/entry_spec.rb +27 -0
  73. data/spec/gphoto2/port_info_list_spec.rb +33 -0
  74. data/spec/gphoto2/port_info_spec.rb +53 -0
  75. data/spec/spec_helper.rb +12 -0
  76. data/spec/support/shared_examples/camera_widget_examples.rb +89 -0
  77. metadata +194 -0
@@ -0,0 +1,8 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-file.h
4
+ CameraFileAccessType = enum :memory,
5
+ :fd,
6
+ :handler
7
+ end
8
+ end
@@ -0,0 +1,11 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-abilities-list.h
4
+ CameraFileOperation = enum :none, 0,
5
+ :delete, 1 << 1,
6
+ :preview, 1 << 3,
7
+ :raw, 1 << 4,
8
+ :audio, 1 << 5,
9
+ :exif, 1 << 6
10
+ end
11
+ end
@@ -0,0 +1,9 @@
1
+ module FFI
2
+ module GPhoto2
3
+ class CameraFilePath < FFI::Struct
4
+ # gphoto2/gphoto2-camera.h
5
+ layout :name, [:char, 128],
6
+ :folder, [:char, 1024]
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,11 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-file.h
4
+ CameraFileType = enum :preview,
5
+ :normal,
6
+ :raw,
7
+ :audio,
8
+ :exif,
9
+ :metadata
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-abilities-list.h
4
+ CameraFolderOperation = enum :none, 0,
5
+ :delete_all, 1 << 0,
6
+ :put_file, 1 << 1,
7
+ :make_dir, 1 << 2,
8
+ :remove_dir, 1 << 3
9
+ end
10
+ end
@@ -0,0 +1,15 @@
1
+ module FFI
2
+ module GPhoto2
3
+ class CameraList < FFI::ManagedStruct
4
+ # libgphoto2/gphoto2-list.c
5
+ layout :used, :int,
6
+ :max, :int,
7
+ :_entry, :pointer, # Entry*
8
+ :ref_count, :int
9
+
10
+ def self.release(ptr)
11
+ FFI::GPhoto2.gp_list_free(ptr)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,12 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-abilities-list.h
4
+ CameraOperation = enum :none, 0,
5
+ :capture_image, 1 << 0,
6
+ :capture_video, 1 << 1,
7
+ :capture_audio, 1 << 2,
8
+ :capture_preview, 1 << 3,
9
+ :config, 1 << 4,
10
+ :trigger_capture, 1 << 5
11
+ end
12
+ end
@@ -0,0 +1,33 @@
1
+ module FFI
2
+ module GPhoto2
3
+ class CameraWidget < FFI::Struct
4
+ # libgphoto2/gphoto2-widget.c
5
+ layout :type, CameraWidgetType,
6
+ :label, [:char, 256],
7
+ :info, [:char, 1024],
8
+ :name, [:char, 256],
9
+
10
+ :parent, :pointer, # CameraWidget
11
+
12
+ :value_string, :string,
13
+ :value_int, :int,
14
+ :value_float, :float,
15
+
16
+ :choice, :pointer,
17
+ :choice_count, :int,
18
+
19
+ :min, :float,
20
+ :max, :float,
21
+ :increment, :float,
22
+
23
+ :children, :pointer, # CameraWidget**
24
+ :children_count, :int,
25
+
26
+ :changed, :int,
27
+ :readonly, :int,
28
+ :ref_count, :int,
29
+ :id, :int,
30
+ :callback, :pointer # CameraWidgetCallback
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,14 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-widget.h
4
+ CameraWidgetType = enum :window,
5
+ :section,
6
+ :text,
7
+ :range,
8
+ :toggle,
9
+ :radio,
10
+ :menu,
11
+ :button,
12
+ :date
13
+ end
14
+ end
@@ -0,0 +1,9 @@
1
+ module FFI
2
+ module GPhoto2
3
+ class Entry < FFI::Struct
4
+ # libgphoto2/gphoto2-list.c
5
+ layout :name, :string,
6
+ :value, :string
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,31 @@
1
+ module FFI
2
+ module GPhoto2
3
+ class GPContext < FFI::Struct
4
+ # libgphoto2/gphoto2-context.c
5
+ layout :idle_func, :pointer, # GPContextIdleFunc
6
+ :idle_func_data, :pointer, # void*
7
+
8
+ :progress_start_func, :pointer, # GPContextProgressStartFunc
9
+ :progress_update_func, :pointer, # GPContextProgressUpdateFunc
10
+ :progress_stop_func, :pointer, # GPContextProgressStopFunc
11
+ :progress_func_data, :pointer, # void*
12
+
13
+ :error_func, :pointer, # GPContextErrorFunc
14
+ :error_func_data, :pointer, # void*
15
+
16
+ :question_func, :pointer, # GPContextQuestionFunc
17
+ :question_func_data, :pointer, # void*
18
+
19
+ :cancel_func, :pointer, # GPContextCancelFunc
20
+ :cancel_func_data, :pointer, # void*
21
+
22
+ :status_func, :pointer, # GPContextStatusFunc
23
+ :status_func_data, :pointer, # void*
24
+
25
+ :message_func, :pointer, # GPContextMessageFunc
26
+ :message_func_data, :pointer, # void*
27
+
28
+ :ref_count, :uint
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,7 @@
1
+ module FFI
2
+ module GPhoto2
3
+ # gphoto2/gphoto2-abilities-list.h
4
+ GphotoDeviceType = enum :still_camera, 0,
5
+ :audio_player, 1 << 0
6
+ end
7
+ end
@@ -0,0 +1,31 @@
1
+ module FFI
2
+ module GPhoto2Port
3
+ extend FFI::Library
4
+
5
+ ffi_lib 'libgphoto2_port'
6
+
7
+ # constants
8
+ require 'ffi/gphoto2_port/gp_port_result'
9
+
10
+ # enums
11
+ require 'ffi/gphoto2_port/gp_port_type'
12
+
13
+ # structs
14
+ require 'ffi/gphoto2_port/gp_port_info'
15
+ require 'ffi/gphoto2_port/gp_port_info_list'
16
+
17
+ # libgphoto2_port/gphoto2/gphoto2-port-info-list.h
18
+ attach_function :gp_port_info_get_name, [GPPortInfo, :pointer], :int
19
+ attach_function :gp_port_info_get_path, [GPPortInfo, :pointer], :int
20
+ attach_function :gp_port_info_get_type, [GPPortInfo, :pointer], :int
21
+
22
+ attach_function :gp_port_info_list_new, [:pointer], :int
23
+ attach_function :gp_port_info_list_free, [GPPortInfoList.by_ref], :int
24
+ attach_function :gp_port_info_list_load, [GPPortInfoList.by_ref], :int
25
+ attach_function :gp_port_info_list_lookup_path, [GPPortInfoList.by_ref, :string], :int
26
+ attach_function :gp_port_info_list_get_info, [GPPortInfoList.by_ref, :int, :pointer], :int
27
+
28
+ # libgphoto2_port/gphoto2/gphoto2-port-result.h
29
+ attach_function :gp_port_result_as_string, [:int], :string
30
+ end
31
+ end
@@ -0,0 +1,11 @@
1
+ module FFI
2
+ module GPhoto2Port
3
+ class GPPortInfo < FFI::Struct
4
+ # libgphoto2_port/libgphoto2_port/gphoto2-port-info.h
5
+ layout :type, GPPortType,
6
+ :name, :string,
7
+ :path, :string,
8
+ :library_filename, :string
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,14 @@
1
+ module FFI
2
+ module GPhoto2Port
3
+ class GPPortInfoList < FFI::ManagedStruct
4
+ # libgphoto2_port/libgphoto2_port/gphoto2-port-info-list.c
5
+ layout :info, :pointer, # GPPortInfo*
6
+ :count, :uint,
7
+ :iolib_count, :uint
8
+
9
+ def self.release(ptr)
10
+ FFI::GPhoto2Port.gp_port_info_list_free(ptr)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,35 @@
1
+ module FFI
2
+ module GPhoto2Port
3
+ # libgphoto2_port/gphoto2/gphoto2-port-result.h
4
+ GP_OK = 0
5
+
6
+ GP_ERROR = -1
7
+ GP_ERROR_BAD_PARAMETERS = -2
8
+ GP_ERROR_NO_MEMORY = -3
9
+ GP_ERROR_LIBRARY = -4
10
+ GP_ERROR_UNKNOWN_PORT = -5
11
+ GP_ERROR_NOT_SUPPORTED = -6
12
+ GP_ERROR_IO = -7
13
+ GP_ERROR_FIXED_LIMIT_EXCEEDED = -8
14
+
15
+ GP_ERROR_TIMEOUT = -10
16
+
17
+ GP_ERROR_IO_SUPPORTED_SERIAL = -20
18
+ GP_ERROR_IO_SUPPORTED_USB = -21
19
+
20
+ GP_ERROR_IO_INIT = -31
21
+ GP_ERROR_IO_READ = -34
22
+ GP_ERROR_IO_WRITE = -35
23
+ GP_ERROR_IO_UPDATE = -37
24
+
25
+ GP_ERROR_IO_SERIAL_SPEED = -41
26
+
27
+ GP_ERROR_IO_USB_CLEAR_HALT = -51
28
+ GP_ERROR_IO_USB_FIND = -52
29
+ GP_ERROR_IO_USB_CLAIM = -53
30
+
31
+ GP_ERROR_IO_LOCK = -60
32
+
33
+ GP_ERROR_HAL = -70
34
+ end
35
+ end
@@ -0,0 +1,12 @@
1
+ module FFI
2
+ module GPhoto2Port
3
+ # libgphoto2_port/gphoto2/gphoto2-port-info-list.h
4
+ GPPortType = enum :none, 0,
5
+ :serial, 1 << 0,
6
+ :usb, 1 << 2,
7
+ :disk, 1 << 3,
8
+ :ptpip, 1 << 4,
9
+ :usb_disk_direct, 1 << 5,
10
+ :usb_scsi, 1 << 6
11
+ end
12
+ end
data/lib/gphoto2.rb ADDED
@@ -0,0 +1,41 @@
1
+ require 'logger'
2
+
3
+ require 'ffi'
4
+
5
+ require 'ffi/gphoto2'
6
+ require 'ffi/gphoto2_port'
7
+
8
+ require 'gphoto2/camera_widgets/camera_widget'
9
+ require 'gphoto2/camera_widgets/date_camera_widget'
10
+ require 'gphoto2/camera_widgets/menu_camera_widget'
11
+ require 'gphoto2/camera_widgets/radio_camera_widget'
12
+ require 'gphoto2/camera_widgets/range_camera_widget'
13
+ require 'gphoto2/camera_widgets/section_camera_widget'
14
+ require 'gphoto2/camera_widgets/text_camera_widget'
15
+ require 'gphoto2/camera_widgets/toggle_camera_widget'
16
+ require 'gphoto2/camera_widgets/window_camera_widget'
17
+ require 'gphoto2/camera'
18
+ require 'gphoto2/camera_abilities'
19
+ require 'gphoto2/camera_abilities_list'
20
+ require 'gphoto2/camera_file'
21
+ require 'gphoto2/camera_file_path'
22
+ require 'gphoto2/camera_folder'
23
+ require 'gphoto2/camera_list'
24
+ require 'gphoto2/context'
25
+ require 'gphoto2/entry'
26
+ require 'gphoto2/port_info'
27
+ require 'gphoto2/port_info_list'
28
+ require 'gphoto2/port_result'
29
+ require 'gphoto2/version'
30
+
31
+ module GPhoto2
32
+ def self.logger
33
+ @logger ||= Logger.new(STDERR)
34
+ end
35
+
36
+ def self.check!(rc)
37
+ logger.debug "#{caller.first} => #{rc}" if ENV['DEBUG']
38
+ return if rc >= FFI::GPhoto2Port::GP_OK
39
+ raise "#{PortResult.as_string(rc)} (#{rc})"
40
+ end
41
+ end
@@ -0,0 +1,219 @@
1
+ module GPhoto2
2
+ class Camera
3
+ include FFI::GPhoto2
4
+
5
+ attr_reader :context, :model, :port
6
+
7
+ def self.all
8
+ context = Context.new
9
+
10
+ camera_abilities_list = CameraAbilitiesList.new(context)
11
+ camera_list = camera_abilities_list.detect
12
+
13
+ entries = camera_list.to_a.map { |entry| Camera.new(entry) }
14
+
15
+ context.finalize
16
+
17
+ entries
18
+ end
19
+
20
+ def self.first
21
+ entries = all
22
+ raise RuntimeError, 'no devices detected' if entries.empty?
23
+ entries.first
24
+ end
25
+
26
+ def self.open(entry)
27
+ camera = new(entry)
28
+
29
+ if block_given?
30
+ begin
31
+ yield camera
32
+ ensure
33
+ camera.finalize
34
+ end
35
+ else
36
+ camera
37
+ end
38
+ end
39
+
40
+ def self.where(pattern)
41
+ all.select { |c| c.model.match(pattern) }
42
+ end
43
+
44
+ def initialize(entry)
45
+ @model, @port = entry.name, entry.value
46
+ @dirty = false
47
+ end
48
+
49
+ def finalize
50
+ @context.finalize if @context
51
+ @window.finalize if @window
52
+ unref if @ptr
53
+ end
54
+ alias_method :close, :finalize
55
+
56
+ def exit
57
+ _exit
58
+ end
59
+
60
+ def capture(type = :image)
61
+ save
62
+ path = _capture(type)
63
+ CameraFile.new(self, path.folder, path.name)
64
+ end
65
+
66
+ def preview
67
+ save
68
+ capture_preview
69
+ end
70
+
71
+ # timeout in milliseconds
72
+ def wait(timeout = 2000)
73
+ wait_for_event(timeout)
74
+ end
75
+
76
+ def ptr
77
+ @ptr || (init && @ptr)
78
+ end
79
+
80
+ def abilities
81
+ @abilities || (init && @abilities)
82
+ end
83
+
84
+ def port_info
85
+ @port_info || (init && @port_info)
86
+ end
87
+
88
+ def context
89
+ @context ||= Context.new
90
+ end
91
+
92
+ def window
93
+ @window ||= get_config
94
+ end
95
+
96
+ def config
97
+ @config ||= window.flatten
98
+ end
99
+
100
+ def filesystem(root = '/')
101
+ root = "/#{root}" if root[0] != '/'
102
+ CameraFolder.new(self, root)
103
+ end
104
+ alias_method :/, :filesystem
105
+
106
+ def file(file)
107
+ file_get(file)
108
+ end
109
+
110
+ def [](key)
111
+ config[key]
112
+ end
113
+
114
+ def []=(key, value)
115
+ self[key].value = value
116
+ @dirty = true
117
+ value
118
+ end
119
+
120
+ def dirty?
121
+ @dirty
122
+ end
123
+
124
+ def save
125
+ return false unless dirty?
126
+ set_config
127
+ @dirty = false
128
+ true
129
+ end
130
+
131
+ def to_ptr
132
+ @ptr
133
+ end
134
+
135
+ private
136
+
137
+ def init
138
+ new
139
+ set_abilities(CameraAbilities.find(@model))
140
+ set_port_info(PortInfo.find(@port))
141
+ end
142
+
143
+ def new
144
+ ptr = FFI::MemoryPointer.new(FFI::GPhoto2::Camera)
145
+ rc = gp_camera_new(ptr)
146
+ GPhoto2.check!(rc)
147
+ @ptr = FFI::GPhoto2::Camera.new(ptr.read_pointer)
148
+ end
149
+
150
+ def _exit
151
+ rc = gp_camera_exit(ptr, context.ptr)
152
+ GPhoto2.check!(rc)
153
+ end
154
+
155
+ def set_port_info(port_info)
156
+ rc = gp_camera_set_port_info(ptr, port_info.ptr)
157
+ GPhoto2.check!(rc)
158
+ @port_info = port_info
159
+ end
160
+
161
+ def set_abilities(abilities)
162
+ rc = gp_camera_set_abilities(ptr, abilities.ptr)
163
+ GPhoto2.check!(rc)
164
+ @abilities = abilities
165
+ end
166
+
167
+ def _capture(type)
168
+ path = CameraFilePath.new
169
+ rc = gp_camera_capture(ptr, type, path.ptr, context.ptr)
170
+ GPhoto2.check!(rc)
171
+ path
172
+ end
173
+
174
+ def capture_preview
175
+ file = CameraFile.new(self)
176
+ rc = gp_camera_capture_preview(ptr, file.ptr, context.ptr)
177
+ GPhoto2.check!(rc)
178
+ file
179
+ end
180
+
181
+ def get_config
182
+ widget_ptr = FFI::MemoryPointer.new(FFI::GPhoto2::CameraWidget)
183
+ rc = gp_camera_get_config(ptr, widget_ptr, context.ptr)
184
+ GPhoto2.check!(rc)
185
+ widget = FFI::GPhoto2::CameraWidget.new(widget_ptr.read_pointer)
186
+ CameraWidget.factory(widget)
187
+ end
188
+
189
+ def set_config
190
+ rc = gp_camera_set_config(ptr, window.ptr, context.ptr)
191
+ GPhoto2.check!(rc)
192
+ end
193
+
194
+ def file_get(file, type = :normal)
195
+ rc = gp_camera_file_get(ptr, file.folder, file.name, type, file.ptr, context.ptr)
196
+ GPhoto2.check!(rc)
197
+ file
198
+ end
199
+
200
+ def unref
201
+ rc = gp_camera_unref(ptr)
202
+ GPhoto2.check!(rc)
203
+ end
204
+
205
+ def wait_for_event(timeout)
206
+ # assume CameraEventType is an int
207
+ type = FFI::MemoryPointer.new(:int)
208
+
209
+ data = FFI::MemoryPointer.new(:pointer)
210
+ data_ptr = FFI::MemoryPointer.new(:pointer)
211
+ data_ptr.write_pointer(data)
212
+
213
+ rc = gp_camera_wait_for_event(ptr, timeout, type, data, context.ptr)
214
+ GPhoto2.check!(rc)
215
+
216
+ CameraEventType[type.read_int]
217
+ end
218
+ end
219
+ end