Last active
August 29, 2015 14:05
-
-
Save toshi3221/7a9429379cb366a94a74 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'socket' | |
require './ruby_ptp_ip/ptp.rb' | |
require './ruby_ptp_ip/ptp_ip.rb' | |
# THETAのIPアドレスとPTP-IPのポート番号 | |
ADDR = "192.168.1.1" | |
PORT = 15740 | |
# THETAに送るレスポンダ情報 | |
NAME = "Ruby_THETA_Shutter" | |
GUID = "ab653fb8-4add-44f0-980e-939b5f6ea266" | |
PROTOCOL_VERSION = 65536 | |
class PtpInitiator | |
def initialize addr=ADDR, port=PORT, guid=GUID, name=NAME, protocol_version=PROTOCOL_VERSION | |
@transaction_id = 1 | |
@addr = addr | |
@port = port | |
@guid = guid | |
@name = name | |
@protocol_version = protocol_version | |
end | |
# GUID文字列を整数の配列にする関数 | |
def str2guid(str) | |
hexes = str.scan /([a-fA-F0-9]{2})-*/ | |
hexes.flatten! | |
raise "Invalid GUID" if hexes.length != 16 | |
hexes.map do |s| | |
s.hex | |
end | |
end | |
# パケットを書き込む関数 | |
def write_packet(sock, pkt) | |
sock.send(pkt.to_data.pack("C*"), 0) | |
end | |
# パケットを読み込む関数 | |
def read_packet(sock) | |
data = [] | |
data += sock.read(PTPIP_packet::MIN_PACKET_SIZE).unpack("C*") | |
len = PTPIP_packet.parse_length(data) | |
data += sock.read(len-PTPIP_packet::MIN_PACKET_SIZE).unpack("C*") | |
PTPIP_packet.new(data) | |
end | |
# データフェイズの読み込み関数 | |
def recv_data(sock, transaction_id) | |
recv_pkt = read_packet(sock) | |
raise "Invalid Packet : #{recv_pkt.to_s}" if recv_pkt.type != PTPIP_PT_StartDataPacket | |
raise "Invalid Transaction ID" if recv_pkt.payload.transaction_id != transaction_id | |
data_len = recv_pkt.payload.total_data_length_low | |
data = [] | |
while recv_pkt.type != PTPIP_PT_EndDataPacket | |
recv_pkt = read_packet(sock) | |
raise "Invalid Packet : #{recv_pkt.to_s}" if recv_pkt.type != PTPIP_PT_DataPacket && recv_pkt.type != PTPIP_PT_EndDataPacket | |
raise "Invalid Transaction ID" if recv_pkt.payload.transaction_id != transaction_id | |
data += recv_pkt.payload.data_payload | |
end | |
raise "Invalid Data Size" unless data_len == data.length | |
return data | |
end | |
# コマンドコネクション初期化関数 | |
def init_command | |
init_command_payload = PTPIP_payload_INIT_CMD_PKT.new() | |
init_command_payload.guid = str2guid(@guid) | |
init_command_payload.friendly_name = NAME | |
init_command_payload.protocol_version = PROTOCOL_VERSION | |
init_command = PTPIP_packet.create(init_command_payload) | |
write_packet(@command_sock, init_command) | |
read_packet(@command_sock)#ACK | |
end | |
# イベントコネクション初期化関数 | |
def init_event | |
init_event_payload = PTPIP_payload_INIT_EVENT_REQ_PKT.new() | |
init_event_payload.conn_number = @conn_number | |
init_event = PTPIP_packet.create(init_event_payload); | |
write_packet(@event_sock, init_event) | |
read_packet(@event_sock) | |
end | |
def wait_event | |
read_packet @event_sock | |
end | |
# データフェイズのあるオペレーションコード実行関数 | |
def data_operation(operation_code, parameters = []) | |
transaction_id = @transaction_id | |
@transaction_id += 1 | |
op_payload = PTPIP_payload_OPERATION_REQ_PKT.new() | |
op_payload.data_phase_info = PTPIP_payload_OPERATION_REQ_PKT::NO_DATA_OR_DATA_IN_PHASE | |
op_payload.operation_code = operation_code | |
op_payload.transaction_id = transaction_id | |
op_payload.parameters = parameters | |
op_pkt = PTPIP_packet.create(op_payload) | |
write_packet(@command_sock, op_pkt) | |
data = recv_data(@command_sock, transaction_id) | |
recv_pkt = read_packet(@command_sock) | |
return recv_pkt, data | |
end | |
# シンプルなオペレーションコードの実行関数 | |
def simple_operation(operation_code, parameters = []) | |
transaction_id = @transaction_id | |
@transaction_id += 1 | |
op_payload = PTPIP_payload_OPERATION_REQ_PKT.new() | |
op_payload.data_phase_info = PTPIP_payload_OPERATION_REQ_PKT::NO_DATA_OR_DATA_IN_PHASE | |
op_payload.operation_code = operation_code | |
op_payload.transaction_id = transaction_id | |
op_payload.parameters = parameters | |
op_pkt = PTPIP_packet.create(op_payload) | |
write_packet(@command_sock, op_pkt) | |
read_packet(@command_sock) | |
end | |
def open | |
TCPSocket.open(@addr, @port) do |s| | |
@command_sock = s | |
# コマンドコネクション | |
recv_pkt = init_command | |
raise "Initialization Failed (Command) #{recv_pkt.payload.reason}" if recv_pkt.type == PTPIP_PT_InitFailPacket | |
p @conn_number = recv_pkt.payload.conn_number | |
p @guid = recv_pkt.payload.guid | |
p @name = recv_pkt.payload.friendly_name | |
p @protocol_version = recv_pkt.payload.protocol_version | |
TCPSocket.open(@addr, @port) do |es| | |
@event_sock = es | |
# イベントコネクション | |
recv_pkt = init_event | |
raise "Initialization Failed (Event) #{recv_pkt.payload.reason}" if recv_pkt.type == PTPIP_PT_InitFailPacket | |
print "Command/Event Connections are established.\n" | |
yield self | |
end | |
end | |
end | |
end | |
# | |
# ここから処理 | |
# | |
PtpInitiator.new.open do |initiator| | |
session_id = 1 | |
# DeviceInfoの取得とパースと表示 | |
recv_pkt, data = initiator.data_operation(PTP_OC_GetDeviceInfo) | |
dev_info = PTP_DeviceInfo.create(data) | |
print "Device Info :\n" | |
p dev_info.to_s | |
raise "GetDeviceInfo Failed #{recv_pkt.payload.response_code}" if recv_pkt.payload.response_code != PTP_RC_OK | |
# セッション開始 | |
recv_pkt = initiator.simple_operation(PTP_OC_OpenSession, [session_id]) | |
raise "Open Session Failed #{recv_pkt.payload.response_code}" if recv_pkt.payload.response_code != PTP_RC_OK | |
# キャプチャ開始 | |
# [0,0]はストレージIDとキャプチャフォーマット | |
# それぞれ0の時はデバイス側が判断する. | |
recv_pkt = initiator.simple_operation(PTP_OC_InitiateCapture, [0,0]) | |
raise "Initiate Capture Failed #{recv_pkt.payload.response_code}" if recv_pkt.payload.response_code != PTP_RC_OK | |
@event_transaction_id = recv_pkt.payload.transaction_id | |
print "Capturing...\r" | |
# ObjectAddedイベントの待機 | |
recv_pkt = initiator.wait_event | |
raise "Invalid Event Packet" unless recv_pkt.type == PTPIP_PT_EventPacket | |
raise "Invalid Event Code" unless recv_pkt.payload.event_code == PTP_EC_ObjectAdded | |
print "Object Added!\n" | |
# CaptureCompletedイベントの待機 | |
recv_pkt = initiator.wait_event | |
raise "Invalid Event Packet" unless recv_pkt.type == PTPIP_PT_EventPacket | |
raise "Invalid Event Code" unless recv_pkt.payload.event_code == PTP_EC_CaptureComplete | |
print "Capture Completed!\n" | |
# セッション終了 | |
recv_pkt = initiator.simple_operation(PTP_OC_CloseSession) | |
raise "Close Session Failed #{recv_pkt.payload.response_code}" if recv_pkt.payload.response_code != PTP_RC_OK | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
RICOH THETAで撮った写真をPTP-IPで取得する - stoikheia(@3xv)の日記 http://d.hatena.ne.jp/stoikheia/20131201 | |
ここにあるサンプル、Socketが生書きなのでラッピングをこころみてる |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment