/* PIP - Platform Independent Primitives Single application Ivan Pelipenko peri4ko@yandex.ru This program is free software: you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. You should have received a copy of the GNU Lesser General Public License along with this program. If not, see . */ #include "pisingleapplication.h" #include "piliterals_bytes.h" #include "piliterals_time.h" #include "pisharedmemory.h" #include "pitime.h" //! \class PISingleApplication pisingleapplication.h //! \~\details //! \~english //! //! //! \~russian //! Этот класс позволяет отслеживать повторный запуск приложения //! и передавать сообщение первому запущеному. //! //! Видят друг друга %PISingleApplication с одинаковыми "app_name", //! задаваемым в конструкторе. //! //! Если проверка \a isFirst() успешна, значит этот экземпляр //! запущен первым, и можно соединиться к событию \a messageReceived(). //! //! Если проверка провалена, значит этот экземпляр не первый, //! и можно послать ему сообщение с помощью \a sendMessage(), //! а затем выйти. //! //! \~\code //! int main(int argc, char * argv[]) { //! PISingleApplication sapp("myapp"); //! if (sapp.isFirst()) { //! piCout << "I`m first, wait for another"; //! CONNECTL(&sapp, messageReceived, [](PIByteArray msg){ //! piCout << "Msg from another:" << PIString(msg); //! }); //! } else { //! piCout << "I`m not first, send and exit"; //! sapp.sendMessage(PIString("Hello!").toByteArray()); //! return 0; //! } //! WAIT_FOREVER //! return 0; //! } //! \endcode //! #define SHM_SIZE 32_KiB PISingleApplication::PISingleApplication(const PIString & app_name): PIThread() { first = true; started = false; sacnt = 0; shm = new PISharedMemory("sa_" + app_name, SHM_SIZE); start(10_Hz); } PISingleApplication::~PISingleApplication() { stop(); if (!waitForFinish(5_s)) terminate(); delete shm; } bool PISingleApplication::isFirst() const { waitFirst(); return first; } void PISingleApplication::sendMessage(const PIByteArray & m) { waitFirst(); PIByteArray ba; int lm[3] = {0, 0, 0}; for (;;) { shm->read(lm, 12); if (lm[2] == 0) break; piMSleep(10); } ba << sacnt << sacnt << int(1) << m; shm->write(ba); } void PISingleApplication::begin() { int cnt[2] = {0, 0}; int tcnt = 0; shm->read(cnt, 8); for (int i = 0; i < 5; ++i) { tcnt = cnt[0]; shm->read(cnt, 8); if (cnt[0] == cnt[1] && cnt[0] != tcnt) { first = false; break; } piMSleep(100); } // piCoutObj << "started" << first << shm->size(); readed.reserve(shm->size()); started = true; } void PISingleApplication::run() { if (!first) return; ++sacnt; int st_[2] = {sacnt, sacnt}; shm->write(st_, 8); // piCoutObj << "write" << sacnt; int ri[3] = {0, 0, 0}; const int hdr_sz = sizeof(int) * 3; shm->read(ri, hdr_sz); if (ri[2] != 0 && ri[0] == ri[1]) { readed.resize(shm->size() - hdr_sz); shm->read(readed.data(), readed.size(), hdr_sz); PIByteArray msg; readed >> msg; if (msg.isNotEmpty()) { messageReceived(msg); // piCoutObj << "message" << msg; } int wi[3] = {sacnt, sacnt, 0}; shm->write(wi, 12); } } void PISingleApplication::waitFirst() const { while (!started) piMSleep(50); }