// 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 }
// 处理短信PUD字符串. // s 串口接收到的PDU字符串. func (g *Gsm) handleSMS(s string) { b, err := hex.DecodeString(s) if nil != err { g.mLogger.Error(`GSMSMS: Decode sms hex string error "%v"`, err) return } var msg sms.Message _, err = msg.ReadFrom(b) if err != nil { g.mLogger.Error(`GSMSMS: Decode sms message error "%v"`, err) return } select { case g.mChanSMS <- &msg: default: g.mLogger.Debug(`GSMSMS: Drop [%v]"%v"`, string(msg.Address), msg.Text) } }
// 发送短信. // num 接收者的号码. // msg 需要发送的短信内容. // return 错误; ==nil 发送正常. func (g *Gsm) SendSMS(num, msg string) error { g.mMutex.Lock() defer g.mMutex.Unlock() if _, err := g.atcmd("AT", "OK", time.Millisecond*250); nil != err { return err } s := sms.Message{ Encoding: sms.Encodings.Gsm7Bit, Text: msg, Address: sms.PhoneNumber(num), VP: sms.ValidityPeriod(time.Hour * 24 * 4), VPFormat: sms.ValidityPeriodFormats.Relative, Type: sms.MessageTypes.Submit, } if len(msg) != len([]rune(msg)) { s.Encoding = sms.Encodings.UCS2 } n, octets, err := s.PDU() if err != nil { return err } cmd := fmt.Sprintf("AT+CMGS=%d", n) if _, err := g.atcmd(cmd, "", time.Millisecond*300); nil != err { return err } buf := make([]byte, hex.EncodedLen(len(octets))+1) n = hex.Encode(buf, octets) buf[n] = 0x1A if _, err := g.mPort.Write(buf); nil != err { return err } _, err = g.atcmd("", "OK", time.Second*10) return err }
// 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 }
// 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 }