// // Copyright (C) 2020 The Android Open Source Project // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. #include "host/commands/modem_simulator/misc_service.h" #include #include #include namespace cuttlefish { MiscService::MiscService(int32_t service_id, ChannelMonitor* channel_monitor, ThreadLooper* thread_looper) : ModemService(service_id, this->InitializeCommandHandlers(), channel_monitor, thread_looper) { ParseTimeZone(); } void MiscService::ParseTimeZone() { #if defined(__linux__) constexpr char TIMEZONE_FILENAME[] = "/etc/timezone"; std::ifstream ifs(TIMEZONE_FILENAME); if (ifs.is_open()) { std::string line; if (std::getline(ifs, line)) { FixTimeZone(line); timezone_ = line; } } #endif } void MiscService::FixTimeZone(std::string& line) { auto slashpos = line.find("/"); // "/" will be treated as separator, change it ! if (slashpos != std::string::npos) { line.replace(slashpos, 1, "!"); } } void MiscService::SetTimeZone(std::string timezone) { FixTimeZone(timezone); timezone_ = timezone; } std::vector MiscService::InitializeCommandHandlers() { std::vector command_handlers = { /* initializeCallback */ CommandHandler("E0Q0V1", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("S0=0", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+CMEE=1", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+CMOD=0", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+CSSN=0,1", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+COLP=0", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+CSCS=\"HEX\"", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+CMGF=0", [this](const Client& client) { this->HandleCommandDefaultSupported(client); }), CommandHandler("+CGSN", [this](const Client& client, std::string& cmd) { this->HandleGetIMEI(client, cmd); }), }; return (command_handlers); } void MiscService::HandleGetIMEI(const Client& client, std::string& command) { const std::string identityGsmImei = "867400022047199"; const std::string identityGsmSvn = "01"; const std::string information = "modem simulator"; std::vector responses; if (command == "AT+CGSN") { responses.push_back(identityGsmImei); } else { CommandParser cmd(command); cmd.SkipPrefix(); int snt = cmd.GetNextInt(); switch (snt) { case 0: // SN: IMEI and more information provided by manufacturers responses.push_back(identityGsmImei + information); break; case 1: // IMEI responses.push_back(identityGsmImei); break; case 2: // IMEI and software version number responses.push_back(identityGsmImei + identityGsmSvn); break; case 3: // Software version number responses.push_back(identityGsmSvn); break; default: // Default IMEI responses.push_back(identityGsmImei); break; } } responses.push_back("OK"); client.SendCommandResponse(responses); } void MiscService::TimeUpdate() { auto now = std::time(0); auto local_time = *std::localtime(&now); auto gm_time = *std::gmtime(&now); auto t_local_time = std::mktime(&local_time); auto t_gm_time = std::mktime(&gm_time); // Timezone offset is in number of quarter-hours auto tzdiff = (int)std::difftime(t_local_time, t_gm_time) / (15 * 60); std::stringstream ss; ss << "%CTZV: \"" << std::setfill('0') << std::setw(2) << local_time.tm_year % 100 << "/" << std::setfill('0') << std::setw(2) << local_time.tm_mon + 1 << "/" << std::setfill('0') << std::setw(2) << local_time.tm_mday << "," << std::setfill('0') << std::setw(2) << local_time.tm_hour << ":" << std::setfill('0') << std::setw(2) << local_time.tm_min << ":" << std::setfill('0') << std::setw(2) << local_time.tm_sec << (tzdiff >= 0 ? '+' : '-') << (tzdiff >= 0 ? tzdiff : -tzdiff) << ":" << local_time.tm_isdst; if (!timezone_.empty()) { ss << ":" << timezone_; } ss << "\""; SendUnsolicitedCommand(ss.str()); } } // namespace cuttlefish