Жиреет скетч
- Войдите на сайт для отправки комментариев
Сб, 02/02/2019 - 23:50
Проект предназначен (в том числе) для обмена с mqtt - брокером, но не суть. Проблема в том что размер скетча подошёл к критическим 30кБ скомпилированного кода, а не реализована ещё наверно половина. Начал разбираться, что за чёрт. Оказалось, что при вызове библиотченых фенкции (в частности PubSubClient) скетч жиреет просто нереально. К примеру во многих местах приходится публиковать данные, что то типа
mqtt.publish( "info/armed", armed ? "1":"0" );
И каждый ска вызов одной и той же функции прибавляет к коду пату - тройку сотен байт. Что за бред, компилятор создаёт экземпляр фунции при каждом её вызове что ли?
Добро пожаловать из мира мигающих светодиодов в мир "Где мои байты, чувак". Анализ вызова отдельной функции тут ничего может и не дать. Свинья может быть зарыта в любом месте исходного кода.
кто ж на ардуине сетевые стеки реализует? - берите ЕСП8266 - у нее 256Кфлеша и порядка 80К оперативки
А ардуины подходят только для ногодрыгов
кто ж на ардуине сетевые стеки реализует? - берите ЕСП8266 - у нее 256Кфлеша и порядка 80К оперативки
А ардуины подходят только для ногодрыгов
При всем уважении.... Т е учиться нормально программировать при ограниченных ресурсах вы призывать людей не хотите?
кто ж на ардуине сетевые стеки реализует? - берите ЕСП8266 - у нее 256Кфлеша и порядка 80К оперативки
А ардуины подходят только для ногодрыгов
Ну, там, здоровый образ жизни, фитнес там ...
кто ж на ардуине сетевые стеки реализует? - берите ЕСП8266 - у нее 256Кфлеша и порядка 80К оперативки
А ардуины подходят только для ногодрыгов
Конечно не решение, очевидно же что если у ТС скетч жиреет от библиотеки, значит надо её выкинуть и переписать самому.
Может он там строки адские к каждому запросу приделывает. А думает, что либа виновата.
Никакие не адские, вызывается одни и те же функции с одними и теми же топиками и короткими пэйлоадами.
bool pubArmed() { if (mqtt.state() == 0) return mqtt.publish( "info/armed", armed ? "1":"0" ); return false; } bool pubDoorClosed() { if (mqtt.state() == 0) return mqtt.publish( "info/doorClosed", door.active() ? "0":"1" ); return false; } bool pubHoodClosed() { if (mqtt.state() == 0) return mqtt.publish( "info/hoodClosed", hood.active() ? "0":"1" ); return false; } bool pubIgnition() { if (mqtt.state() == 0) return mqtt.publish( "info/ignOn", ignition.active() ? "1":"0" ); return false; } bool pubEngRunning() { if (mqtt.state() == 0) return mqtt.publish( "info/engRunning", engRunning ? "1":"0" ); return false; } bool pubWarmup() { if (mqtt.state() == 0) return mqtt.publish( "info/warmup", warmup ? "1":"0" ); return false; }берите ЕСП8266
Нужен GSM
если у ТС скетч жиреет от библиотеки, значит надо её выкинуть и переписать самому.
Это крайний вариант
Это крайний вариант
Крайний с какого края?
С края лени. На кой чёрт тогда библиотеки
Ну, посмотрите, может там эта publish (или state) - inline, Если так - уберите inline (и вынесете в другой файл) - перестанет расти.
Что-то я не вижу в publish() ничего такого, что тянуло бы на 300 байт.
нет инлайнов
Что-то я не вижу в publish() ничего такого, что тянуло бы на 300 байт.
В том то и дело. по идее если мы её один раз заюзали, у компилятора есть её адрес и дальше он её по нему вызывает. Ну как бы так по логике должно быть.
Ну какбэ, в любом случае, - чтобы разобраться в причинах по фрагменту кода - это к ведуньям. Они по фотографии всю жизнь человека узнать могут, а обычные люди не в силах.
Выложить весь код? Кто в нём здесь будет ковыряться?
typedef unsigned long dword; #include "consts.h" #include "classes.h" #include <CyberLib.h> #include <DallasTemperature.h> #include <OneWire.h> #include <SoftwareSerial.h> #define TINY_GSM_MODEM_SIM800; #include <TinyGsmClient.h> #include <PubSubClient.h> SoftwareSerial gsm(SIM800RX_PIN, SIM800TX_PIN); // RX Arduino (TX sim800), TX Arduino (RX sim800) TinyGsm modem(gsm); TinyGsmClient client(modem); PubSubClient mqtt(client); Input lock(LOCK_PIN), door(DOOR_PIN), hood(HOOD_PIN), fuelpump(FUELPUMP_PIN); Output siren(SIREN_PIN), flash(FLASH_PIN), dvr(DVR_PIN), led(LED_PIN); InOut ignition(IGN_SUPPLY_PIN, IGN_PIN), starter(STARTER_SUPPLY_PIN, STARTER_PIN); Shock shock; Period t7sec(7000), t1min(60*1000), t1hour(60*60*1000), t1day(24*60*60*1000); OneWire oneWire(ONEWIRE_PIN); DallasTemperature sensors(&oneWire); DeviceAddress engSensor = {0x20, 0x0C, 0x01, 0x07, 0x27, 0x74, 0x09, 0x15}; DeviceAddress outSensor = {0x20, 0x0C, 0x01, 0x07, 0x27, 0x74, 0x09, 0x15}; bool armed = false; bool warmup = false; byte stopTimer = 10; float stopTemp = 90; float engTempC = -127; float outTempC = -127; int getAnalog(int); float vBatt(void); float iBatt(void); bool neutral(void); bool engRunning(void); bool drive(void); int getDoors(void); int triggDoors(void); float tempC(DeviceAddress); void raiseAlarm(char[], dword); bool fullConnect(void); bool mqttConnect(void); void mqttCallback(char*, byte*, word); void sendMetrics(void); void setup() { //analogReference(EXTERNAL); pinMode(NEUTRAL_PIN, INPUT_PULLUP); Serial.begin(9600); gsm.begin(9600); mqtt.setServer(broker, brokerPort); mqtt.setCallback(mqttCallback); while (!fullConnect()); //------------------------------------ sendMetrics(); //------------------------------------ sensors.begin(); sensors.setResolution(engSensor, 9); sensors.setResolution(outSensor, 9); } void loop() //======================================================================================================================= { if (Serial.available()) { Serial.readString(); sendMetrics(); } static int connState = mqtt.state(); if (connState != 0) { Serial.print("disconnect reason = "); Serial.println(connState); for (byte att = 0; att <= 5; att++) { if (mqttConnect()) break; if (att == 5) fullConnect(); } } if (lock.change() == 1) // ========= следим за командой закрытия ЦЗ if (!drive()) { if (getDoors() > 0) siren.pulse(200); shock.reset(); armed = true; } if (lock.change() == 0) { armed = false; shock.reset(); shock.disable(); } if (drive()) dvr.pulse(60000); // ========= управление регистратором //led.set( armed && ((millis() & 0x3ff) > 0x370) ); // ========= в охранке раз в секунду мигаем диодом на стойке if ( !neutral() || (stopTimer < 1) || (engTempC > stopTemp) || (iBatt() > 15.0) ) { // ======== глушим движку ignition.set(false); warmup = false; pubWarmup(); } if (t1day.now()) { pubBalance(); } else if (t1hour.now()) { pubOutTemp(); pubVBatt(); } else if (t1min.now()) { if (stopTimer > 0) stopTimer--; pubStopTimer(); if (!warmup) { pubIBatt(); pubEngTemp(); } } else if (t7sec.now()) { sensors.requestTemperatures(); engTempC = sensors.getTempC(engSensor); outTempC = sensors.getTempC(outSensor); pubSignal(); pubArmed(); pubHoodClosed(); pubDoorClosed(); pubIgnition(); pubEngRunning(); pubWarmup(); if (warmup) { pubIBatt(); pubEngTemp(); } } flash.processing(); siren.processing(); dvr.processing(); mqtt.loop(); } //================================================================================================================================ int getAnalog(int pin) { word _lvl[5]; for (byte i = 0; i < 5; i++) _lvl[i] = analogRead(pin); return find_similar(_lvl, 5, 3); return(analogRead(pin)); } float vBatt() { int _lvl = getAnalog(BATT_PIN); return(_lvl/65.0); } float iBatt() { int _lvl = getAnalog(CURRENT_PIN); return (_lvl - 640) / 20.46; } bool neutral() { return(getAnalog(NEUTRAL_PIN) < 130); // ~591 при INTERNAL } bool engRunning() { return( fuelpump.active() || (vBatt() > 13.8) ); } bool drive() { return( engRunning() && !neutral() ); } int getDoors() { return ( hood.active() + (door.active() << 1) ); } int triggDoors() { // 2 = door open + 1 = hood open static int _old = 0; int _ret = 0; int _state = getDoors(); if (_state > _old) _ret = _state; _old = _state; return _ret; } byte preStart() { if (engRunning()) return 1; // движок уже работает if (!neutral()) return 2; // на скорости ignition.set(true); if (starter.active()) { ignition.set(false); return 4; } // пробило мосфет стартера if (!fuelpump.active()) { ignition.set(false); return 8; } // не включился бензонасос for ( dword _t = millis(); (millis() - _t) < 3000; ) if (fuelpump.change() == 0) { ignition.change(); return 0; } ignition.set(false); // сбрасываем фронт импульса чтоб не сработала сигналка return 1; } byte nowStart() { if (engRunning()) return 1; shock.disable(); float _relVolt = vBatt() - 2.0; dword _begin = millis(); if (!starter.set(true)) { ignition.set(false); shock.reset(); return 4; } delay(500); while ( ((millis() - _begin) < 1500) && (vBatt() < _relVolt) ); if (!starter.set(false)) { ignition.set(false); shock.reset(); return 4; } delay(2000); shock.reset(); return (engRunning() ? 0:0x10); // если недокрутил, то 0x10 } float tempC(DeviceAddress sid){ sensors.requestTemperaturesByAddress(sid); return sensors.getTempC(sid); } void raiseAlarm(const char msg[], dword dur) { siren.pulse(dur); flash.pulse(dur); mqtt.publish("messages/notify", msg); } bool fullConnect() { Serial.print("modem restart... "); modem.restart(); delay(5000); Serial.println(modem.getModemInfo()); Serial.print("wait for network... "); modem.waitForNetwork(); if (modem.isNetworkConnected()) Serial.println("OK"); else { Serial.println("error!"); return false; } Serial.print("gprs connecting... "); modem.gprsConnect(apn, apnUser, apnPass); if (modem.isGprsConnected()) Serial.println("OK"); else { Serial.println("error!"); return false; } return mqttConnect(); } bool mqttConnect() { Serial.print("broker connecting... "); if (mqtt.connect("BlackBox", brokerUser, brokerPass)) { Serial.println("OK"); mqtt.subscribe("cmd/#"); mqtt.publish("messages/notify", "Mazda is connecting"); } else { Serial.println("error!"); } return mqtt.connected(); } void mqttCallback(char* topic, byte* payload, word len) { Serial.print("Message arrived ["); Serial.print(topic); Serial.print("]: "); Serial.write(payload, len); Serial.println(); if (String(topic) == "cmd/start") { if (warmup) { warmup = !ignition.set(false); return; } static unsigned long _press = 0; if ((char*)payload == '1') _press = millis(); if ((char*)payload == '0') { if ( (_press != 0) && ((millis() - _press) > 5000) && ((millis() - _press) < 10000) ) if (preStart() == 0) warmup = (nowStart() == 0); _press = 0; } pubWarmup(); //led.set(String((char*)payload).toInt()); } if (String(topic) == "cmd/stopTemp") { stopTemp = String((char*)payload).toInt(); } if (String(topic) == "cmd/stopTime") { stopTimer = String((char*)payload).toInt(); } } bool pubSignal() { if (mqtt.state() == 0) return mqtt.publish( "info/signal", String(modem.getSignalQuality()).c_str() ); return false; } bool pubArmed() { if (mqtt.state() == 0) return mqtt.publish( "info/armed", armed ? "1":"0" ); return false; } bool pubDoorClosed() { if (mqtt.state() == 0) return mqtt.publish( "info/doorClosed", door.active() ? "0":"1" ); return false; } bool pubHoodClosed() { if (mqtt.state() == 0) return mqtt.publish( "info/hoodClosed", hood.active() ? "0":"1" ); return false; } bool pubIgnition() { if (mqtt.state() == 0) return mqtt.publish( "info/ignOn", ignition.active() ? "1":"0" ); return false; } bool pubEngRunning() { if (mqtt.state() == 0) return mqtt.publish( "info/engRunning", engRunning ? "1":"0" ); return false; } bool pubWarmup() { if (mqtt.state() == 0) return mqtt.publish( "info/warmup", warmup ? "1":"0" ); return false; } bool pubVBatt() { if (mqtt.state() == 0) return mqtt.publish( "info/vBatt", String(vBatt()).c_str() ); return false; } bool pubIBatt() { if (mqtt.state() == 0) return mqtt.publish( "info/iBatt", String(iBatt()).c_str() ); return false; } bool pubEngTemp() { if (mqtt.state() == 0) return mqtt.publish( "info/engTemp", String(engTempC).c_str() ); return false; } bool pubOutTemp() { if (mqtt.state() == 0) return mqtt.publish( "info/outTemp", String(outTempC).c_str() ); return false; } bool pubBalance() { if (mqtt.state() == 0) return mqtt.publish( "info/balance", String(modem.sendUSSD("*105#").substring(8).toFloat()).c_str() ); return false; } bool pubStopTimer() { if (mqtt.state() == 0) return mqtt.publish( "info/stopTimer", String(stopTimer).c_str() ); return false; } void sendMetrics() { }//=======classes.h========== volatile byte shSt; class Input { public: Input(int pin) { _pin = pin; pinMode(pin, INPUT_PULLUP); _old = active(); } bool active(void) { byte _cntr; do { _cntr = 0; for (byte _i = 1; _i <= 10; _i++) _cntr += (int)digitalRead(_pin); } while ((_cntr > 0) && (_cntr < 10)); return(_cntr == 0); } int change() { bool _state = active(); if (_state == _old) return -1; _old = _state; return (int)_state; } private: bool _old; int _pin; }; // Input class Output { public: Output(int pin) { _pin = pin; pinMode(pin, OUTPUT); digitalWrite(pin, LOW); } void set(bool val) { digitalWrite(_pin, val ? HIGH:LOW); _state = val; _actual = false; } void pulse(dword timeout) { _begin = millis(); _timeout = timeout; _actual = true; } void processing() { if (_actual) { bool _timely = (millis() - _begin) < _timeout; if (_timely && !_state) { digitalWrite(_pin, HIGH); _state = true;} if (!_timely && _state) { digitalWrite(_pin, LOW); _state = false; _actual = false; } } } private: int _pin; dword _begin = 0; dword _timeout = 0; bool _actual = false; bool _state = false; }; // Output class InOut : public Input, Output { public: InOut(int inPin, int outPin) : Input(inPin), Output(outPin) { } bool set(bool val) { Output::set(val); return (active() == val); } }; //InOut class Shock { public: Shock() { pinMode(2, INPUT_PULLUP); pinMode(3, INPUT_PULLUP); shSt = 0; } void reset() { shSt = 0; attachInterrupt(0, hi, FALLING); attachInterrupt(1, lo, FALLING); } void disable() { detachInterrupt(0); detachInterrupt(1); } byte state() { if (shSt == 1) for (dword _begin = millis(); (millis() - _begin) < 100;) if (shSt > 1) return 2; if (shSt> 2) shSt = 2; return shSt; } private: //static volatile byte _st; static void hi() { shSt = 2; detachInterrupt(0); } static void lo() { shSt |= 1; detachInterrupt(1); } }; // Shock class Period { public: Period (unsigned long dur) { _dur = dur; _begin = millis(); } bool now(void) { bool _ret = (millis() - _begin) > _dur; if (_ret) _begin = millis(); return _ret; } private: unsigned long _begin = 0; unsigned long _dur = 0; };человек! Ты хоть пароль от брокера убери! ;)))
человек! Ты хоть пароль от брокера убери! ;)))
лоин/пароль неверный ессенно
И да. Я всегда до новичков докапываюсь, ту не стану. Нормально все написано, аккуратно. Немножно без скидки на контроллер, как для ПК, но аккуратно.
Всякие строковые темы нужно попробовать урезать, НО! - самое первое - выкинуть даллас-темприча! Сразу дышать станет легче. Она вообще никому и никогда не нужна, Onewire всегда достаточно. На три строки больше написать придется! ;) Выкинь и посмотри, что выйдет.
И да. Я всегда до новичков докапываюсь, ту не стану. Нормально все написано, аккуратно. Немножно без скидки на контроллер, как для ПК, но аккуратно.
Всякие строковые темы нужно попробовать урезать, НО! - самое первое - выкинуть даллас-темприча! Сразу дышать станет легче. Она вообще никому и никогда не нужна, Onewire всегда достаточно. На три строки больше написать придется! ;) Выкинь и посмотри, что выйдет.
Пробовал - экономия на спичках, меня это никак не спасёт. Он хавает совсем немного. Всё по отдельности пробовал выкидывать, слёзы экономии. PubSub ска жрёт как мерен
Естественно - большой код никто за вас отлаживать не будет, тем более если всё это завязано на какие-то доп. сервисы. Если хотите попытаться докопаться до причины - сокращаете его так, чтобы остались только подозреваемые фрагменты. Потом проводите следственный эксперимент, добавляя и убавляя кол-во вызовов publish. Если гипотеза про 300 байт подтверждаетеся - значит стоит ковырять либу, если не подтверждается - чешете голову дальше.
В целом - кто-то работает, наверное, с этими TinyGSM и пр. Сможет примерно прикинуть: пожрут ли они 20кб или нет. На глазок - тут килобайт 10 в юзерспейсе, если так можно выразится. Ну вот эти float, Serial, String... если от них избавится - освободят progmem/ram. Для интереса скомпилируйте что-нить простое с float и без - посмотрите, как будет изменяться объём прошивки.
если у ТС скетч жиреет от библиотеки, значит надо её выкинуть и переписать самому.
Это крайний вариант
Что там крайнего, рядом лежат готовые функции, примитив, пихаете в отправку своего gsm и все
http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-404716
А это не поможет? https://habr.com/ru/post/311874/
https://arduino-esp8266.readthedocs.io/en/latest/PROGMEM.html
[/quote] Что там крайнего, рядом лежат готовые функции, примитив, пихаете в отправку своего gsm и все http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-404716[/quote]
Да действительно, совсем фигня... если только "лампочку мигать"
Что там крайнего, рядом лежат готовые функции, примитив, пихаете в отправку своего gsm и все http://arduino.ru/forum/programmirovanie/snova-mqtt-1#comment-404716
Да действительно, совсем фигня... если только "лампочку мигать"
Победили? А то аналогичная проблема, каждый новый топик отжирает от динамической памяти, которой всего 8К по 24 байта, блин а у меня их дофига(
24 байта это вообще ни о чем.
Проверьте, как вы строки формируете, может их можно во флеш убрать
Конечно не о чём, но когда свободной памяти осталось всего 20% и топиков ещё надо прописать «куеву тучу», то каждый байт на счету((
Подскажите, а как можно топики во флеш запихнуть?
Код покажите
если в кратце, то так
#define pubMQTT(t, v) clientMQTT.publish(t,v,true); case 121: //Включаем светодиод digitalWrite(ledPin21, LOW); // set the LED on pubMQTT("dom/controller2/204Ven","1"); break; case 21: //Выключаем светодиод digitalWrite(ledPin21, HIGH); // set the LED OFF pubMQTT("dom/controller2/204Ven","0"); break;и таких конструкций еще надо сотню прописать
Классический идиотизм - весь дом на одном сторублевом контроллере
#define pubMQTT(t, v) clientMQTT.publish(t,v,true); case 121: //Включаем светодиод digitalWrite(ledPin21, LOW); // set the LED on pubMQTT("dom/controller2/204Ven","1"); break; case 21: //Выключаем светодиод digitalWrite(ledPin21, HIGH); // set the LED OFF pubMQTT("dom/controller2/204Ven","0"); break;и таких конструкций еще надо сотню прописать
Попробуйте убрать из кода один из кейсов (один) и скажите насколько изменился расход памяти.
Классический идиотизм - весь дом на одном сторублевом контроллере
Попробуйте убрать из кода один из кейсов (один) и скажите насколько изменился расход памяти.
При одинаковом топике, расход не меняется, а вот если добавить новый топик то увеличивается на 26 байт
На двух. Ну тогда ладно, конечно. Всё правильно и по уму и не идиотизм совсем.
Всем спасибо, все свободны)))
с оптимизировал код, теперь до хрена свободной памяти стало
вот видите, форум помог!