예제 #1
0
파일: commands.go 프로젝트: yazver/gsmmodem
// Init invokes a set of methods that will make the initial setup of the modem.
func (p *DefaultProfile) Init(d *Device) (err error) {
	p.dev = d
	p.dev.Send(NoopCmd) // kinda flush
	if err = p.COPS(true, true); err != nil {
		return errors.New("at init: unable to adjust the format of operator's name")
	}
	var info *SystemInfoReport
	if info, err = p.SYSINFO(); err != nil {
		return errors.New("at init: unable to read system info")
	}
	p.dev.State = &DeviceState{
		ServiceState:  info.ServiceState,
		ServiceDomain: info.ServiceDomain,
		RoamingState:  info.RoamingState,
		SystemMode:    info.SystemMode,
		SystemSubmode: info.SystemSubmode,
		SimState:      info.SimState,
	}
	if p.dev.State.OperatorName, err = p.OperatorName(); err != nil {
		return errors.New("at init: unable to read operator's name")
	}
	if p.dev.State.ModelName, err = p.ModelName(); err != nil {
		return errors.New("at init: unable to read modem's model name")
	}
	if p.dev.State.IMEI, err = p.IMEI(); err != nil {
		return errors.New("at init: unable to read modem's IMEI code")
	}
	if err = p.CMGF(false); err != nil {
		return errors.New("at init: unable to switch message format to PDU")
	}
	if err = p.CPMS(MemoryTypes.NvRAM, MemoryTypes.NvRAM, MemoryTypes.NvRAM); err != nil {
		return errors.New("at init: unable to set messages storage")
	}
	if err = p.CNMI(1, 1, 0, 0, 0); err != nil {
		return errors.New("at init: unable to turn on message notifications")
	}
	var octets map[uint64][]byte
	if octets, err = p.CMGL(MessageFlags.Any); err != nil {
		return errors.New("at init: unable to check message inbox")
	}
	for n, oct := range octets {
		var msg sms.Message
		if _, err := msg.ReadFrom(oct); err != nil {
			return errors.New("at init: error while parsing message inbox")
		}
		if err := p.CMGD(n, DeleteOptions.Index); err != nil {
			return errors.New("at init: error while cleaning message inbox")
		}
		d.messages <- &msg
	}
	return nil
}
예제 #2
0
파일: at.go 프로젝트: yazver/gsmmodem
// SendLongSMS sends an SMS message with given text to the given address,
// the encoding and other parameters are default.
// If the message is very long, it will be sent in parts.
func (d *Device) SendLongSMS(text string, address sms.PhoneNumber) (err error) {
	defer func() {
		multipartReferenceNumber = uint16((uint32(multipartReferenceNumber) + 1) & 0xFFFF)
	}()

	msg := sms.Message{
		Text:     text,
		Type:     sms.MessageTypes.Submit,
		Encoding: sms.Encodings.Gsm7Bit,
		Address:  address,
		VPFormat: sms.ValidityPeriodFormats.Relative,
		VP:       sms.ValidityPeriod(24 * time.Hour * 4),
	}
	maxSize := 130
	for _, w := range text {
		// detected a double-width char
		if w > 1 {
			msg.Encoding = sms.Encodings.UCS2
			maxSize = 60
			break
		}
	}

	msgParts := util.SplitStringBySize(text, maxSize)
	numberOfParts := byte(255)
	if len(msgParts) <= 255 {
		numberOfParts = byte(len(msgParts))
	}
	msg.UserDataStartsWithHeader = numberOfParts > 1
	for index, part := range msgParts {
		msg.MessageReference = messageReferenceCounter
		msg.Text = part
		if msg.Encoding == sms.Encodings.UCS2 {
		}
		if numberOfParts > 1 {
			msg.UserDataHeader.ConcatenationIE = sms.ConcatenationInformationElement{NumberOfParts: numberOfParts, PartNumber: byte(index + 1), ReferenceNumber: multipartReferenceNumber}
		}
		messageReferenceCounter = byte((uint16(messageReferenceCounter) + 1) & 0xFF)

		if index >= int(numberOfParts) {
			break
		}

		n, octets, err := msg.PDU()
		if err != nil {
			return err
		}
		if err = d.Commands.CMGS(n, octets); err != nil {
			return err
		}
	}

	return
}
예제 #3
0
파일: at.go 프로젝트: yazver/gsmmodem
// SendSMS sends an SMS message with given text to the given address,
// the encoding and other parameters are default.
func (d *Device) SendSMS(text string, address sms.PhoneNumber) (err error) {
	msg := sms.Message{
		Text:     text,
		Type:     sms.MessageTypes.Submit,
		Encoding: sms.Encodings.Gsm7Bit,
		Address:  address,
		VPFormat: sms.ValidityPeriodFormats.Relative,
		VP:       sms.ValidityPeriod(24 * time.Hour * 4),
	}
	for _, w := range text {
		// detected a double-width char
		if w > 1 {
			msg.Encoding = sms.Encodings.UCS2
			break
		}
	}
	n, octets, err := msg.PDU()
	if err != nil {
		return err
	}
	err = d.Commands.CMGS(n, octets)
	return
}
예제 #4
0
파일: at.go 프로젝트: yazver/gsmmodem
// handleReport detects and parses a report from the notification port represented
// as a string. The parsed values may change the inner state or be sent over out channels.
func (d *Device) handleReport(str string) (err error) {
	report := Reports.Resolve(str)
	str = strings.TrimSpace(strings.TrimPrefix(str, report.ID))
	switch report {
	case Reports.Message:
		var report messageReport
		if err = report.Parse(str); err != nil {
			return
		}
		var octets []byte
		octets, err = d.Commands.CMGR(report.Index)
		if err != nil {
			return
		}
		if err = d.Commands.CMGD(report.Index, DeleteOptions.Index); err != nil {
			return
		}
		var msg sms.Message
		if _, err = msg.ReadFrom(octets); err != nil {
			return
		}
		d.messages <- &msg
	case Reports.Ussd:
		var ussd ussdReport
		if err = ussd.Parse(str); err != nil {
			return
		}
		var text string
		if ussd.Enc == Encodings.UCS2 {
			text, err = pdu.DecodeUcs2(ussd.Octets)
			if err != nil {
				return
			}
		} else if ussd.Enc == Encodings.Gsm7Bit {
			text, err = pdu.Decode7Bit(ussd.Octets)
			if err != nil {
				return
			}
		} else {
			return ErrUnknownEncoding
		}
		d.ussd <- Ussd(text)
	case Reports.SignalStrength:
		var rssi signalStrengthReport
		if err = rssi.Parse(str); err != nil {
			return
		}
		if d.State.SignalStrength != int(rssi) {
			d.State.SignalStrength = int(rssi)
			d.updated <- struct{}{}
		}
	case Reports.Mode:
		var report modeReport
		if err = report.Parse(str); err != nil {
			return
		}
		var updated bool
		if d.State.SystemMode != report.Mode {
			d.State.SystemMode = report.Mode
			updated = true
		}
		if d.State.SystemSubmode != report.Submode {
			d.State.SystemSubmode = report.Submode
			updated = true
		}
		if updated {
			d.updated <- struct{}{}
		}
	case Reports.ServiceState:
		var report serviceStateReport
		if err = report.Parse(str); err != nil {
			return
		}
		if d.State.ServiceState != Opt(report) {
			d.State.ServiceState = Opt(report)
			d.updated <- struct{}{}
		}
	case Reports.SimState:
		var report simStateReport
		if err = report.Parse(str); err != nil {
			return
		}
		if d.State.SimState != Opt(report) {
			d.State.SimState = Opt(report)
			d.updated <- struct{}{}
		}
	case Reports.BootHandshake:
		var token bootHandshakeReport
		if err = token.Parse(str); err != nil {
			return
		}
		if err = d.Commands.BOOT(uint64(token)); err != nil {
			return
		}
	case Reports.Stin:
		// ignore. what is this btw?
	default:
		switch FinalResults.Resolve(str) {
		case FinalResults.Noop, FinalResults.NotSupported, FinalResults.Timeout:
			// ignore
		default:
			return errors.New("at: unknown report: " + str)
		}
	}
	return
}