diff --git a/biju.gemspec b/biju.gemspec index 5798961..ddce90a 100644 --- a/biju.gemspec +++ b/biju.gemspec @@ -15,8 +15,8 @@ Gem::Specification.new do |gem| gem.require_paths = ["lib"] gem.version = Biju::VERSION - gem.add_development_dependency "minitest", "3.0.0" + gem.add_development_dependency "rspec", "~> 2.14.0" - gem.add_dependency "serialport", ">=1.0.4" + gem.add_dependency "serialport", "~> 1.1.0" gem.add_dependency "parslet", "~> 1.5.0" end diff --git a/lib/biju.rb b/lib/biju.rb index 656b999..947bf99 100644 --- a/lib/biju.rb +++ b/lib/biju.rb @@ -1,4 +1,6 @@ require 'biju/version' -require "biju/modem" -require "biju/sms" -require "biju/hayes" +require 'biju/modem' +require 'biju/to_hayes' +require 'biju/hayes' +require 'biju/sms' +require 'biju/parser' diff --git a/lib/biju/hayes.rb b/lib/biju/hayes.rb index ff5d0bb..3eacc0c 100644 --- a/lib/biju/hayes.rb +++ b/lib/biju/hayes.rb @@ -1,69 +1,92 @@ module Biju class Hayes - attr_accessor :command, :attributes, :ok - attr_reader :answer + attr_reader :modem - #def method_missing(m, *args, &block) - #end + def initialize(port, options = {}) + pin = options.delete(:pin) || '0000' + @modem = Modem.new(port, options) + + attention + init_modem + unlock_pin pin + + text_mode + extended_error + end + + def at_command(cmd = nil, *args, &block) + command = ['AT', cmd].compact.join + command_args = args.compact.to_hayes + + full_command = [command, (command_args.empty? ? nil : command_args)] + .compact.join('=') + + answer = write(full_command) + + return block.call(answer) if block_given? + answer + end def attention - at_command { |response| response =~ /OK/ } - #at_command { |response| true } + at_command[:status] end def init_modem - at_command('Z') { |response| response =~ /OK/ } + at_command('Z')[:status] end def text_mode(enabled = true) - at_command('+CMGF', enabled) { |response| response =~ /OK/ } + at_command('+CMGF', enabled)[:status] end - def prefered_storage? - at_command('+CPMS') { |response| response =~ /OK/ } + def extended_error(enabled = true) + at_command('+CMEE', enabled)[:status] end - def answer=(ret) - @answer = ret - ok? + def prefered_storage(pms = nil) + result = at_command('+CPMS', pms) + return result[:array] if result[:cmd] == '+CPMS' + nil end - def ok? - ok.nil? ? true : !ok.call(answer).nil? + def unlock_pin(pin) + at_command('+CPIN', pin)[:status] + end + + def messages(which = "ALL") + prefered_storage 'MT' + sms = at_command('+CMGL', which) + + return sms[:status] if !sms.has_key?(:sms) || sms[:sms].empty? + sms[:sms].map do |msg| + Biju::Sms.new( + id: msg[:infos][0], + phone_number: msg[:infos][2], + datetime: msg[:infos][4], + message: msg[:message].chomp) + end + end + + # Delete a sms message by id. + # @param [Fixnum] Id of sms message on modem. + def delete(id) + at_command('+CMGD', id) + end + + def send(sms, options = {}) + at_command('+CMGS', sms.phone_number) + write("#{sms.message}#{26.chr}") end private - def at_command(cmd = nil, *args, &block) - option_prefix = nil #options[:prefix] || nil - cmd_root = ['AT', cmd].compact.join(option_prefix) - cmd_args = args.compact.map { |arg| to_hayes_string(arg) } unless args.empty? - self.command = [cmd_root, cmd_args].compact.join('=') - self.ok = block if block_given? - command + def write(text) + modem.write(text) + hayes_to_obj(modem.wait_answer) end def hayes_to_obj(str) - end - - # OPTIMIZE : add () to array - def to_hayes_string(arg) - case arg - when String - "\"#{arg}\"" - when Array - arg.join(',') - when TrueClass, FalseClass - !!arg ? 1 : 0 - else - "?" - end - end - end - - class HayesSms < Hayes - def unlock_pin(pin) - at_command("+CPIN=#{to_hayes_string(pin)}") { |response| response =~ /OK/ } + ATTransform.new.apply(ATParser.new.parse(str)) end end end diff --git a/lib/biju/modem.rb b/lib/biju/modem.rb index b55f2b8..a46e432 100644 --- a/lib/biju/modem.rb +++ b/lib/biju/modem.rb @@ -1,36 +1,19 @@ require 'serialport' -require_relative 'sms' module Biju class Modem + DEFAULT_OPTIONS = { baud: 9600, data_bits: 8, + stop_bits: 1, parity: SerialPort::NONE } + attr_reader :connection # @param [Hash] Options to serial connection. # @option options [String] :port The modem port to connect # - # Biju::Modem.new(:port => '/dev/ttyUSB0') + # Biju::Modem.new('/dev/ttyUSB0') # - def initialize(options={}, &block) - raise Exception.new("Port is required") unless options[:port] - pin = options[:pin] || '0000' - @connection = connect(options) - cmd("AT") - # initialize modem - cmd("ATZ") - # unlock pin code - cmd("AT+CPIN=\"#{pin}\"") if pin - - cmd("AT+CPMS=?") - - # set SMS text mode - cmd("AT+CMGF=1") - # set extended error reports - cmd('AT+CMEE=1') - #instance_eval &block if block_given? - if block_given? - yield connection - close - end + def initialize(port, options = {}) + @connection = SerialPort.new(port, DEFAULT_OPTIONS.merge!(options)) end # Close the serial connection. @@ -38,59 +21,16 @@ module Biju connection.close end - # Return an Array of Sms if there is messages nad return nil if not. - def messages(which = "ALL") - # read message from all storage in the mobile phone (sim+mem) - cmd('AT+CPMS="MT"') - # get message list - sms = cmd('AT+CMGL="%s"' % which ) - # collect messages - msgs = sms.scan(/\+CMGL\:\s*?(\d+)\,.*?\,\"(.+?)\"\,.*?\,\"(.+?)\".*?\n(.*)/) - return nil unless msgs - msgs.collect!{ |msg| Biju::Sms.new(:id => msg[0], :phone_number => msg[1], :datetime => msg[2], :message => msg[3].chomp) } + def write(text) + connection.write(text + "\r") end - # Delete a sms message by id. - # @param [Fixnum] Id of sms message on modem. - def delete(id) - cmd("AT+CMGD=#{id}") - end - - def send(sms, options = {}) - # initiate the sms, and wait for either - # the text prompt or an error message - cmd("AT+CMGS=\"#{sms.phone_number}\"") - - # send the sms, and wait until - # it is accepted or rejected - cmd("#{sms.message}#{26.chr}") - # ... check reception - end - - private - def connect(options) - port = options.delete(:port) - SerialPort.new(port, default_options.merge!(options)) - end - - def default_options - { :baud => 9600, :data_bits => 8, :stop_bits => 1, :parity => SerialPort::NONE } - end - - def cmd(cmd) -puts "SENDING : #{cmd}" - connection.write(cmd + "\r") - wait_str = wait - #p "#{cmd} --> #{wait_str}" - end - - def wait + def wait_answer buffer = '' while IO.select([connection], [], [], 0.25) - chr = connection.getc.chr; - buffer += chr + buffer << connection.getc.chr end -puts "RECEIVING : #{buffer}" + buffer end end