/******************************************************************************* * Copyright (c) 2011, 2016 Eurotech and/or its affiliates * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Eurotech *******************************************************************************/ package org.eclipse.kura.net.admin.modem.sierra.mc87xx; import java.io.IOException; import java.net.URISyntaxException; import java.util.List; import org.eclipse.kura.KuraErrorCode; import org.eclipse.kura.KuraException; import org.eclipse.kura.comm.CommConnection; import org.eclipse.kura.comm.CommURI; import org.eclipse.kura.linux.net.modem.SupportedUsbModemInfo; import org.eclipse.kura.linux.net.modem.SupportedUsbModemsInfo; import org.eclipse.kura.net.NetConfig; import org.eclipse.kura.net.admin.modem.HspaCellularModem; import org.eclipse.kura.net.admin.modem.telit.he910.TelitHe910; import org.eclipse.kura.net.modem.ModemDevice; import org.eclipse.kura.net.modem.ModemRegistrationStatus; import org.eclipse.kura.net.modem.ModemTechnologyType; import org.eclipse.kura.usb.UsbModemDevice; import org.osgi.service.io.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class SierraMc87xx implements HspaCellularModem { private static final Logger s_logger = LoggerFactory.getLogger(SierraMc87xx.class); private ConnectionFactory m_connectionFactory = null; private String m_model = null; private String m_manufacturer = null; private String m_serialNumber = null; private String m_revisionId = null; private Object m_atLock = null; private ModemDevice m_device = null; private List<NetConfig> m_netConfigs = null; public SierraMc87xx(ModemDevice device, ConnectionFactory connectionFactory) { this.m_device = device; this.m_connectionFactory = connectionFactory; this.m_atLock = new Object(); } @Override public String getModel() throws KuraException { synchronized (this.m_atLock) { if (this.m_model == null) { s_logger.debug("sendCommand getModelNumber :: {}", SierraMc87xxAtCommands.getModelNumber.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection.sendCommand(SierraMc87xxAtCommands.getModelNumber.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { this.m_model = getResponseString(reply); reply = null; } } } return this.m_model; } @Override public String getManufacturer() throws KuraException { synchronized (this.m_atLock) { if (this.m_manufacturer == null) { s_logger.debug("sendCommand getManufacturer :: {}", SierraMc87xxAtCommands.getManufacturer.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection.sendCommand(SierraMc87xxAtCommands.getManufacturer.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { this.m_manufacturer = getResponseString(reply); reply = null; } } } return this.m_manufacturer; } @Override public String getSerialNumber() throws KuraException { synchronized (this.m_atLock) { if (this.m_serialNumber == null) { s_logger.debug("sendCommand getSerialNumber :: {}", SierraMc87xxAtCommands.getSerialNumber.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection.sendCommand(SierraMc87xxAtCommands.getSerialNumber.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { this.m_serialNumber = getResponseString(reply); } } } return this.m_serialNumber; } @Override public String getMobileSubscriberIdentity() throws KuraException { // TODO Auto-generated method stub return null; } @Override public String getIntegratedCirquitCardId() throws KuraException { // TODO Auto-generated method stub return null; } @Override public String getRevisionID() throws KuraException { synchronized (this.m_atLock) { if (this.m_revisionId == null) { s_logger.debug("sendCommand getRevision :: {}", SierraMc87xxAtCommands.getFirmwareVersion.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection .sendCommand(SierraMc87xxAtCommands.getFirmwareVersion.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { String firmwareVersion = getResponseString(reply); if (firmwareVersion.startsWith("!GVER:")) { firmwareVersion = firmwareVersion.substring("!GVER:".length()).trim(); String[] aFirmwareVersion = firmwareVersion.split(" "); this.m_revisionId = aFirmwareVersion[0]; } } } } return this.m_revisionId; } @Override public boolean isReachable() throws KuraException { boolean ret = false; synchronized (this.m_atLock) { CommConnection commAtConnection = openSerialPort(getAtPort()); ret = isAtReachable(commAtConnection); closeSerialPort(commAtConnection); } return ret; } @Override public boolean isPortReachable(String port) { boolean ret = false; synchronized (this.m_atLock) { try { CommConnection commAtConnection = openSerialPort(port); closeSerialPort(commAtConnection); ret = true; } catch (KuraException e) { s_logger.warn("isPortReachable() :: The {} is not reachable", port); } } return ret; } @Override public void reset() throws KuraException { // TODO // not supported } @Override public int getSignalStrength() throws KuraException { int rssi = -113; synchronized (this.m_atLock) { s_logger.debug("sendCommand getSignalStrength :: {}", SierraMc87xxAtCommands.getSignalStrength.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection.sendCommand(SierraMc87xxAtCommands.getSignalStrength.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { String[] asCsq = null; String sCsq = this.getResponseString(reply); if (sCsq.startsWith("+CSQ:")) { sCsq = sCsq.substring("+CSQ:".length()).trim(); asCsq = sCsq.split(","); if (asCsq.length == 2) { rssi = -113 + 2 * Integer.parseInt(asCsq[0]); } } reply = null; } } return rssi; } @Override public ModemRegistrationStatus getRegistrationStatus() throws KuraException { ModemRegistrationStatus modemRegistrationStatus = ModemRegistrationStatus.UNKNOWN; synchronized (this.m_atLock) { s_logger.debug("sendCommand getSystemInfo :: {}", SierraMc87xxAtCommands.getSystemInfo.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection.sendCommand(SierraMc87xxAtCommands.getSystemInfo.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { String sSysInfo = getResponseString(reply); if (sSysInfo != null && sSysInfo.length() > 0) { String[] aSysInfo = sSysInfo.split(","); if (aSysInfo.length == 5) { int srvStatus = Integer.parseInt(aSysInfo[0]); int roamingStatus = Integer.parseInt(aSysInfo[2]); switch (srvStatus) { case 0: modemRegistrationStatus = ModemRegistrationStatus.NOT_REGISTERED; break; case 2: switch (roamingStatus) { case 0: modemRegistrationStatus = ModemRegistrationStatus.REGISTERED_HOME; break; case 1: modemRegistrationStatus = ModemRegistrationStatus.REGISTERED_ROAMING; break; } break; } } } } } return modemRegistrationStatus; } @Override public long getCallTxCounter() throws KuraException { // TODO // Not supported via AT interface need to use HIP/CnS return 0; } @Override public long getCallRxCounter() throws KuraException { // TODO // Not supported via AT interface need to use HIP/CnS return 0; } @Override public String getServiceType() throws KuraException { String serviceType = null; synchronized (this.m_atLock) { s_logger.debug("sendCommand getMobileStationClass :: {}", SierraMc87xxAtCommands.getMobileStationClass.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection .sendCommand(SierraMc87xxAtCommands.getMobileStationClass.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { String sCgclass = this.getResponseString(reply); if (sCgclass.startsWith("+CGCLASS:")) { sCgclass = sCgclass.substring("+CGCLASS:".length()).trim(); if (sCgclass.equals("\"A\"")) { serviceType = "UMTS"; } else if (sCgclass.equals("\"B\"")) { serviceType = "GSM/GPRS"; } else if (sCgclass.equals("\"CG\"")) { serviceType = "GPRS"; } else if (sCgclass.equals("\"CC\"")) { serviceType = "GSM"; } } reply = null; } } return serviceType; } @Override public ModemDevice getModemDevice() { return this.m_device; } protected void setModemDevice(ModemDevice device) { this.m_device = device; } @Override public String getDataPort() throws KuraException { String port = null; List<String> ports = this.m_device.getSerialPorts(); if (ports != null && ports.size() > 0) { if (this.m_device instanceof UsbModemDevice) { SupportedUsbModemInfo usbModemInfo = SupportedUsbModemsInfo.getModem((UsbModemDevice) this.m_device); if (usbModemInfo != null) { port = ports.get(usbModemInfo.getDataPort()); } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "No PPP serial port available"); } } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "Unsupported modem device"); } } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "No serial ports available"); } return port; } @Override public String getAtPort() throws KuraException { String port = null; List<String> ports = this.m_device.getSerialPorts(); if (ports != null && ports.size() > 0) { if (this.m_device instanceof UsbModemDevice) { SupportedUsbModemInfo usbModemInfo = SupportedUsbModemsInfo.getModem((UsbModemDevice) this.m_device); if (usbModemInfo != null) { port = ports.get(usbModemInfo.getAtPort()); } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "No AT serial port available"); } } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "Unsupported modem device"); } } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "No serial ports available"); } return port; } @Override public String getGpsPort() throws KuraException { // TODO Auto-generated method stub return null; } @Override public boolean isGpsSupported() throws KuraException { // TODO Auto-generated method stub return false; } @Override public void enableGps() throws KuraException { // TODO Auto-generated method stub } @Override public void disableGps() throws KuraException { // TODO Auto-generated method stub } @Override public List<NetConfig> getConfiguration() { return this.m_netConfigs; } @Override public void setConfiguration(List<NetConfig> netConfigs) { this.m_netConfigs = netConfigs; } @Override public List<ModemTechnologyType> getTechnologyTypes() throws KuraException { List<ModemTechnologyType> modemTechnologyTypes = null; ModemDevice device = getModemDevice(); if (device == null) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "No modem device"); } if (device instanceof UsbModemDevice) { SupportedUsbModemInfo usbModemInfo = SupportedUsbModemsInfo.getModem((UsbModemDevice) device); if (usbModemInfo != null) { modemTechnologyTypes = usbModemInfo.getTechnologyTypes(); } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "No usbModemInfo available"); } } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "Unsupported modem device"); } return modemTechnologyTypes; } @Override @Deprecated public ModemTechnologyType getTechnologyType() { ModemTechnologyType modemTechnologyType = null; try { List<ModemTechnologyType> modemTechnologyTypes = getTechnologyTypes(); if (modemTechnologyTypes != null && modemTechnologyTypes.size() > 0) { modemTechnologyType = modemTechnologyTypes.get(0); } } catch (KuraException e) { s_logger.error("Failed to obtain modem technology - {}", e); } return modemTechnologyType; } @Override public boolean isSimCardReady() throws KuraException { boolean simReady = false; synchronized (this.m_atLock) { s_logger.debug("sendCommand getSystemInfo :: {}", SierraMc87xxAtCommands.getSystemInfo.getCommand()); byte[] reply = null; CommConnection commAtConnection = openSerialPort(getAtPort()); if (!isAtReachable(commAtConnection)) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.NOT_CONNECTED, "Modem not available for AT commands: " + TelitHe910.class.getName()); } try { reply = commAtConnection.sendCommand(SierraMc87xxAtCommands.getSystemInfo.getCommand().getBytes(), 1000, 100); } catch (IOException e) { closeSerialPort(commAtConnection); throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } closeSerialPort(commAtConnection); if (reply != null) { String sSysInfo = getResponseString(reply); if (sSysInfo != null && sSysInfo.length() > 0) { String[] aSysInfo = sSysInfo.split(","); if (aSysInfo.length == 5) { int simStatus = Integer.parseInt(aSysInfo[4]); if (simStatus == 1) { simReady = true; } } } } } return simReady; } @Override public CommURI getSerialConnectionProperties(SerialPortType portType) throws KuraException { CommURI commURI = null; try { String port; if (portType == SerialPortType.ATPORT) { port = getAtPort(); } else if (portType == SerialPortType.DATAPORT) { port = getDataPort(); } else if (portType == SerialPortType.GPSPORT) { port = getGpsPort(); } else { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "Invalid Port Type"); } if (port != null) { StringBuffer sb = new StringBuffer(); sb.append("comm:").append(port).append(";baudrate=115200;databits=8;stopbits=1;parity=0"); commURI = CommURI.parseString(sb.toString()); } } catch (URISyntaxException e) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, "URI Syntax Exception"); } return commURI; } @Override public boolean isGpsEnabled() { return false; } private CommConnection openSerialPort(String port) throws KuraException { CommConnection connection = null; if (this.m_connectionFactory != null) { String uri = new CommURI.Builder(port).withBaudRate(115200).withDataBits(8).withStopBits(1).withParity(0) .withTimeout(2000).build().toString(); try { connection = (CommConnection) this.m_connectionFactory.createConnection(uri, 1, false); } catch (Exception e) { s_logger.debug("Exception creating connection: {}", e); throw new KuraException(KuraErrorCode.CONNECTION_FAILED, e); } } return connection; } private void closeSerialPort(CommConnection connection) throws KuraException { try { connection.close(); } catch (IOException e) { throw new KuraException(KuraErrorCode.INTERNAL_ERROR, e); } } private boolean isAtReachable(CommConnection connection) { boolean status = false; int attemptNo = 0; do { try { status = connection.sendCommand(SierraMc87xxAtCommands.at.getCommand().getBytes(), 500).length > 0; } catch (Exception e) { attemptNo++; sleep(2000); } } while (status == false && attemptNo < 3); return status; } // Parse the AT command response for the relevant info private String getResponseString(String resp) { if (resp == null) { return ""; } // remove the command and space at the beginning, and the 'OK' and spaces at the end return resp.replaceFirst("^\\S*\\s*", "").replaceFirst("\\s*(OK)?\\s*$", ""); } private String getResponseString(byte[] resp) { if (resp == null) { return ""; } return getResponseString(new String(resp)); } private void sleep(long millis) { try { Thread.sleep(millis); } catch (InterruptedException e) { // ignore } } }