#include #include "pdulib.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include //-lboost_chrono #include //split #include #include //g++ pdu_test.cpp pdulib.cpp -std=c++17 -lpthread -lboost_system -lboost_thread -lboost_chrono -lrt -pthread -lserialport -o pdu_test //https://github.com/mgaman/PDUlib/tree/master std::string ExecCmd(std::string command){ char buffer[128]; std::string cmd_out = ""; // open pipe to file and execute command in linux terminal FILE* pipe = popen(command.c_str(), "r"); if (!pipe) return "popen failed!"; // read till end of process: while (!feof(pipe)) { // read output of the sent command and add to result if (fgets(buffer, 128, pipe) != NULL) cmd_out += buffer; } pclose(pipe); // returns the output of terminal in string format return cmd_out; } //https://gist.github.com/zekroTJA/00317b41aa69f38090071b6c8065272b /** * Create asynchronous timers which execute specified * functions in set time interval. * * @param func Function which sould be executed * @param interval Interval of time in which function will be executed * (in milliseconds) */ class Timer { public: Timer() {} Timer(std::function func, const long &interval) { m_func = func; m_interval = interval; } /** * Starting the timer. */ void start() { m_running = true; m_thread = std::thread([&]() { while (m_running) { auto delta = std::chrono::steady_clock::now() + std::chrono::milliseconds(m_interval); m_func(); std::this_thread::sleep_until(delta); } }); m_thread.detach(); } /* * Stopping the timer and destroys the thread. */ void stop() { m_running = false; m_thread.~thread(); } /* * Restarts the timer. Needed if you set a new * timer interval for example. */ void restart() { stop(); start(); } /* * Check if timer is running. * * @returns boolean is running */ bool isRunning() { return m_running; } /* * Set the method of the timer after * initializing the timer instance. * * @returns boolean is running * @return Timer reference of this */ Timer *setFunc(std::function func) { m_func = func; return this; } /* * Returns the current set interval in milliseconds. * * @returns long interval */ long getInterval() { return m_interval; } /* * Set a new interval for the timer in milliseconds. * This change will be valid only after restarting * the timer. * * @param interval new interval * @return Timer reference of this */ Timer *setInterval(const long &interval) { m_interval = interval; return this; } ~Timer() { stop(); } private: // Function to be executed fater interval std::function m_func; // Timer interval in milliseconds long m_interval; // Thread timer is running into std::thread m_thread; // Status if timer is running bool m_running = false; }; class SerialClass{ public: SerialClass(){ //std::cout << "SerialClass Started OK." << std::endl; this->baudrate=115200; exspected="NOB"; } ~SerialClass(){ //std::cout << "SerialClass Ended ~OK." << std::endl; if(port){ sp_close(port); sp_free_port(port); } } bool Start(){ if(!list_ports()){ return false; } mThreadShouldRun = true; mThread = boost::thread(&SerialClass::Run, this); return true; } void Stop(){ mThreadShouldRun = false;// dont really needed anymore but may be ok if(port) sp_close(port); mThread.interrupt(); mThread.join(); } bool isSerialRunning(){ return mThreadShouldRun; } void Run(){ //DO Something enum sp_return error = sp_get_port_by_name(desired_port.c_str(),&port); if (error == SP_OK) { error = sp_open(port,SP_MODE_READ_WRITE); if (error == SP_OK) { check(sp_set_baudrate(port, this->baudrate)); check(sp_set_bits(port, 8)); check(sp_set_parity(port, SP_PARITY_NONE)); check(sp_set_stopbits(port, 1)); check(sp_set_flowcontrol(port, SP_FLOWCONTROL_NONE)); while(mThreadShouldRun){ try { boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); int bytes_waiting = sp_input_waiting(port); if (bytes_waiting > 0) { //printf("Bytes waiting %i\n", bytes_waiting); char byte_buff[512]; int byte_num = 0; byte_num = sp_nonblocking_read(port,byte_buff,512); std::string read_str=std::string(byte_buff); //std::cout << "read_str: " << read_str << std::endl; size_t exp = read_str.find(exspected); if( exp != std::string::npos ){ is_exspected=true; exspected="NOB"; //std::cout << "is_exspected OK" << std::endl; } size_t exp_csq = read_str.find("+CSQ:"); if( exp_csq != std::string::npos ){ //std::cout << "exp_csq str: " << read_str << std::endl; std::vector strs; boost::split(strs, read_str , boost::is_any_of("\n")); if( strs.size() > 0 ){ std::string exp_csq_str=strs[1]; boost::algorithm::trim(exp_csq_str); int pos = exp_csq_str.find(" "); if( pos > 0 ){ // Copy substring after pos exp_csq_str = exp_csq_str.substr(pos + 1); boost::algorithm::trim(exp_csq_str); std::replace( exp_csq_str.begin(), exp_csq_str.end(), ',', '.'); //std::cout << "exp_csq_str: " << exp_csq_str << std::endl; if( this->isNumber(exp_csq_str) ){ //this->baudrate = stoi(baudrate_str); std::stringstream ss(exp_csq_str); float my_number; ss >> my_number; //std::cout << "cqs is number:" << round(my_number) << std::endl; this->csq=round(my_number); switch(this->csq){ case 2: this->csq_str="2 -109dBm Marginal";break; case 3: this->csq_str="3 -107dBm Marginal";break; case 4: this->csq_str="4 -105dBm Marginal";break; case 5: this->csq_str="5 -103dBm Marginal";break; case 6: this->csq_str="6 -101dBm Marginal";break; case 7: this->csq_str="7 -99dBm Marginal";break; case 8: this->csq_str="8 -97dBm Marginal";break; case 9: this->csq_str="9 -95dBm Marginal";break; case 10: this->csq_str="10 -93dBm OK";break; case 11: this->csq_str="11 -91dBm OK";break; case 12: this->csq_str="12 -89dBm OK";break; case 13: this->csq_str="13 -87dBm OK";break; case 14: this->csq_str="14 -85dBm OK";break; case 15: this->csq_str="15 -83dBm Good";break; case 16: this->csq_str="16 -81dBm Good";break; case 17: this->csq_str="17 -79dBm Good";break; case 18: this->csq_str="18 -77dBm Good";break; case 19: this->csq_str="19 -75dBm Good";break; case 20: this->csq_str="20 -73dBm Excellent";break; case 21: this->csq_str="21 -71dBm Excellent";break; case 22: this->csq_str="22 -69dBm Excellent";break; case 23: this->csq_str="23 -67dBm Excellent";break; case 24: this->csq_str="24 -65dBm Excellent";break; case 25: this->csq_str="25 -63dBm Excellent";break; case 26: this->csq_str="26 -61dBm Excellent";break; case 27: this->csq_str="27 -59dBm Excellent";break; case 28: this->csq_str="28 -57dBm Excellent";break; case 29: this->csq_str="29 -55dBm Excellent";break; case 30: this->csq_str="30 -53dBm Excellent";break; case 31: this->csq_str="31 -51dBm Excellent";break; } } } } } size_t exp_baudrate = read_str.find("+IPR:"); if( exp_baudrate != std::string::npos ){ //std::cout << "baudrate str: " << read_str << std::endl; int pos = read_str.find(":"); if( pos > 0 ){ // Copy substring after pos std::string baudrate_str = read_str.substr(pos + 1); boost::algorithm::trim(baudrate_str); std::vector strs; boost::split(strs, baudrate_str , boost::is_any_of("\n")); if( strs.size() > 0 ){ baudrate_str=strs[0]; boost::algorithm::trim(baudrate_str); //std::cout << "baudrate_str: " << baudrate_str << std::endl; if( this->isNumber(baudrate_str) ){ //this->baudrate = stoi(baudrate_str); //std::cout << "baudrate: " << this->baudrate << std::endl; } } } } size_t exp_apn = read_str.find("+CGDCONT:"); if( exp_apn != std::string::npos ){ //std::cout << "exp_apn: " << read_str << std::endl; std::vector strs; boost::split(strs, read_str , boost::is_any_of("\n")); for( int i=0; i < strs.size(); i++ ){ std::string apn_str=strs[i]; boost::algorithm::trim(apn_str); std::vector strs_1; boost::split(strs_1, apn_str , boost::is_any_of(",")); if( strs_1.size() > 3 ){ boost::algorithm::trim(strs_1[0]); if(strs_1[0]=="+CGDCONT: 1"){ boost::erase_all(strs_1[2], "\""); //std::cout << "APN: " << strs_1[2] << std::endl; this->apn=strs_1[2]; } } } } size_t exp_smsc = read_str.find("+CSCA:"); if( exp_smsc != std::string::npos ){ //std::cout << "exp_smsc: " << read_str << std::endl; std::vector strs; boost::split(strs, read_str , boost::is_any_of("\n")); if( strs.size() > 1 ){ boost::algorithm::trim(strs[1]); std::vector strs_1; boost::split(strs_1, strs[1] , boost::is_any_of(",")); if( strs_1.size() > 0 ){ int pos = strs_1[0].find(" "); if( pos > 0 ){ // Copy substring after pos std::string smsc_str = strs_1[0].substr(pos + 1); boost::algorithm::trim(smsc_str); boost::erase_all(smsc_str, "\""); //std::cout << "SMSC: " << smsc_str << std::endl; this->smsc=smsc_str; } } } } } fflush(stdout); } catch(boost::thread_interrupted interrupt) { std::cout << "boost::thread_interrupted." << std::endl; mThreadShouldRun = false; break; } } } else { printf("Error opening serial device\n"); mThreadShouldRun = false; } } else { printf("Error finding serial device\n"); mThreadShouldRun = false; } } void write(std::string val){ int ret=sp_nonblocking_write(port,val.c_str(),val.length()); char *error; switch (ret) { case SP_ERR_ARG: std::cout << "serial_write: invalid serial port parameters." << std::endl; //return -DEVICE_CONF_ERROR; case SP_ERR_FAIL: error = sp_last_error_message(); std::cout << "serial_write: write error: " << sp_last_error_code() << " error: " << error << std::endl; sp_free_error_message(error); //return -DEVICE_CONN_ERROR; } } void write(std::string val,std::string exspected_str){ is_exspected=false; exspected=exspected_str; int ret=sp_nonblocking_write(port,val.c_str(),val.length()); char *error; switch (ret) { case SP_ERR_ARG: std::cout << "serial_write: invalid serial port parameters." << std::endl; //return -DEVICE_CONF_ERROR; case SP_ERR_FAIL: error = sp_last_error_message(); std::cout << "serial_write: write error: " << sp_last_error_code() << " error: " << error << std::endl; sp_free_error_message(error); //return -DEVICE_CONN_ERROR; } } void init_values(){ std::string send_val="AT+IPR?\r"; //std::cout << "send_val: " << send_val << std::endl; this->write(send_val); boost::this_thread::sleep_for(boost::chrono::seconds(1)); send_val="AT+CGDCONT?\r"; this->write(send_val); boost::this_thread::sleep_for(boost::chrono::seconds(1)); send_val="AT+CSCA?\r"; this->write(send_val); boost::this_thread::sleep_for(boost::chrono::seconds(1)); send_val="AT+CSQ\r"; this->write(send_val); } void set_port(std::string val){ desired_port=val; check(sp_get_port_by_name(desired_port.c_str(), &port)); //printf("Port name: %s\n", sp_get_port_name(port)); //printf("Description: %s\n", sp_get_port_description(port)); } void set_baudrate(int val){ this->baudrate=val; } bool get_is_exspected(){ return is_exspected; } int get_baudrate(){ return this->baudrate; } std::string get_apn(){ return this->apn; } std::string get_smsc(){ return this->smsc; } int get_csq(){ return this->csq; } std::string get_csq_str(){ return this->csq_str; } private: boost::thread mThread; bool mThreadShouldRun; std::string desired_port; struct sp_port *port=NULL; std::string exspected; bool is_exspected; int baudrate; std::string apn; std::string smsc; std::string csq_str; int csq; bool list_ports() { int i; bool found=false; struct sp_port **ports; enum sp_return error = sp_list_ports(&ports); if (error == SP_OK) { for (i = 0; ports[i]; i++) { //printf("Found port: '%s'\n", sp_get_port_name(ports[i])); if( desired_port == std::string(sp_get_port_name(ports[i]))){ found=true; break; } } sp_free_port_list(ports); } else { printf("No serial devices detected\n"); } //printf("\n"); return found; } /* Helper function for error handling. */ int check(enum sp_return result) { /* For this example we'll just exit on any error by calling abort(). */ char *error_message; switch (result) { case SP_ERR_ARG: printf("Error: Invalid argument.\n"); abort(); case SP_ERR_FAIL: error_message = sp_last_error_message(); printf("Error: Failed: %s\n", error_message); sp_free_error_message(error_message); abort(); case SP_ERR_SUPP: printf("Error: Not supported.\n"); abort(); case SP_ERR_MEM: printf("Error: Couldn't allocate memory.\n"); abort(); case SP_OK: default: return result; } } bool isNumber(std::string str) { double d; std::istringstream is(str); is >> d; return !is.fail() && is.eof(); } }; //AT+CSCA? //Get SMSC number/address //+CSCA: "+4540590000",145 //AT+CSCA="+4540590000" //Set SMSC adresse "sms message service centernumber" int main(int argc, char **argv){ char letter; std::string message="Hello ÆØÅæøå. Er der noget med ÆØÅæøå???? 2. Hello ÆØÅæøå. Er der noget med ÆØÅæøå????"; int buffer_length=(30+7*(message.length()/8))*2; std::cout << "Message buffer length: " << buffer_length << std::endl; PDU mypdu = PDU(buffer_length); std::string SCAnumber="+4540590000"; mypdu.setSCAnumber(SCAnumber.c_str()); std::string Target="+4527581259"; std::string pdu_str=""; int pdu_len = mypdu.encodePDU(Target.c_str(),message.c_str()); if (pdu_len < 0) { switch (pdu_len) { case mypdu.UCS2_TOO_LONG: case mypdu.GSM7_TOO_LONG: std::cout << "Message too long to send as a single message, change to multipart" << std::endl; return 1; case mypdu.WORK_BUFFER_TOO_SMALL: std::cout << "Work buffer too small, change PDU constructor" << std::endl; return 1; case mypdu.ADDRESS_FORMAT: std::cout << "SCA or Target address illegal characters or too long" << std::endl; return 1; case mypdu.MULTIPART_NUMBERS: case mypdu.ALPHABET_8BIT_NOT_SUPPORTED: std::cout << "How did we get here?" << std::endl; return 1; } } else { pdu_str=std::string(mypdu.getSMS()); std::cout << "mypdu.getSMS: " << pdu_str << std::endl; std::cout << "pdu_len: " << pdu_len << std::endl; } std::string apn_str="simstaticip.com"; std::string smsc_str="+4540590000"; std::string ttyUSB_port=""; std::string ttySIM_port="/dev/ttySIM02"; std::string ret=ExecCmd("ls -l /dev/ttySIM0*"); int pos = ret.find(ttySIM_port); if( pos > 0 ){ // Copy substring after pos std::string str = ret.substr(pos + 1); boost::algorithm::trim(str); std::vector strs; boost::split(strs, str , boost::is_any_of("\n")); if( strs.size() > 0 ){ //std::cout << strs.size() << " str: " << strs[0] << std::endl; std::vector strs_1; boost::split(strs_1, strs[0] , boost::is_any_of(" ")); if( strs_1.size() > 0 ){ ttyUSB_port=strs_1[strs_1.size()-1]; boost::algorithm::trim(ttyUSB_port); ttyUSB_port="/dev/"+ttyUSB_port; //std::cout << " ttyUSB_port: " << ttyUSB_port << std::endl; }else{ std::cout << "No serial PORT found" << std::endl; return 1; } }else{ std::cout << "No serial PORT found" << std::endl; return 1; } }else{ std::cout << "No serial PORT found" << std::endl; return 1; } Timer t2; int time_out; int iGoUp; SerialClass *serial=NULL; serial=new SerialClass(); serial->set_port(ttyUSB_port); serial->set_baudrate(115200); if( !serial->Start() ){ std::cout << "error findig port? " << std::endl; return 1; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); if( serial->isSerialRunning() ){ serial->init_values(); boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); if( apn_str != serial->get_apn() ){ std::cout << "Set APN" << std::endl; std::string send_val="AT+CGDCONT=1,\"IP\",\""+apn_str+"\"\r"; std::string expected="OK"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); int ii=0; while(!serial->get_is_exspected()){ if( ii > 6 ){ std::cout << "Error set APN: " << apn_str << std::endl; return 1; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); ii++; } } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); if( smsc_str != serial->get_smsc() ){ std::cout << "Set SMSC" << std::endl; std::string send_val="AT+CSCA=\""+smsc_str+"\",145\r"; std::string expected="OK"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); int ii=0; while(!serial->get_is_exspected()){ if( ii > 6 ){ std::cout << "Error set SMSC: " << smsc_str << std::endl; return 1; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); ii++; } } std::cout << "baudrate: " << serial->get_baudrate() << std::endl; std::cout << "apn: " << serial->get_apn() << std::endl; std::cout << "smsc: " << serial->get_smsc() << std::endl; std::cout << "Quality CSQ int: " << serial->get_csq() << std::endl; std::cout << "Quality CSQ String: " << serial->get_csq_str() << std::endl; } std::cout << "Started OK" << std::endl; //std::cout << "final: " << final << std::endl; while(1) { scanf(" %c", &letter ); if( letter == 'x' ){ break; }else if( letter == 'a' ){ if( serial->isSerialRunning() ){ std::string send_val="AT\r"; std::string expected="OK"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); iGoUp = 0; time_out=3;//3sec t2.setFunc([&](){ if (++iGoUp > time_out ){ t2.stop(); std::cout << "Time OUT????" << std::endl; }else if (serial->get_is_exspected()){ t2.stop(); std::cout << "Hurray: expected: " << expected << std::endl; } }) ->setInterval(1000) ->start(); } }else if( letter == 'b' ){ if( serial->isSerialRunning() ){ std::string send_val="ATE0\r"; //Turn off echo std::string expected="OK"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); int ii=0; while(!serial->get_is_exspected()){ if( ii > 6 ){ std::cout << "Error set Turn off echo: " << std::endl; break; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); ii++; } send_val="AT+CMGF=0\r"; //Set to PDU mode expected="OK"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); ii=0; while(!serial->get_is_exspected()){ if( ii > 6 ){ std::cout << "Error set PDU mode: " << std::endl; break; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); ii++; } send_val="AT+CMGS="+std::to_string(pdu_len)+"\r"; //Set to PDU string length expected=">"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); ii=0; while(!serial->get_is_exspected()){ if( ii > 6 ){ std::cout << "Error set PDU string length: " << std::endl; break; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); ii++; } send_val=pdu_str+"\032"; //Set to PDU string length expected="OK"; std::cout << "send_val: " << send_val << std::endl; serial->write(send_val,expected); ii=0; while(!serial->get_is_exspected()){ if( ii > 6 ){ std::cout << "Error send string: " << std::endl; break; } boost::this_thread::sleep_for(boost::chrono::milliseconds(500)); ii++; } } } } if( serial->isSerialRunning() ){ serial->Stop(); delete serial; } serial=NULL; return 0; }