21 Востаннє редагувалося reverse2500 (07.02.2018 22:09:36)

Re: Blynk, ESP8266, IoT

Як зі сторони esp8266 зрозуміти що прийшло: int, float чи string?

глянемо з точки зору програмування, що таке строка, строка це масив байтів і закінчується '/0'
int займає два байти.

І як ця магічна штука працює?

а що там не ясно ?
blynk-library/src/Blynk/BlynkParam.h

const char* asStr() const       { return ptr; }
        const char* asString() const    { return ptr; }
        int         asInt() const       { return atoi(ptr); }
        long        asLong() const      { return atol(ptr); 

Чи потрібно мудрувати якийсь свій протокол?

ну протокол занадто, пару функцій

- Поганому трояну фаєрвол заважає
- Ніколи не програмуйте та не пийте пиво
Якщо ви з першого разу написали програму, в якій немає жодної помилки, повідомте про це системного програмісту: він виправить помилки в компіляторі

22

Re: Blynk, ESP8266, IoT

а що там не ясно ?

Майже все не ясно.

ну протокол занадто, пару функцій

Щоб з іншого MCU керувати з'єднанням до WiFi, до серверу, відправляти/приймати різні данні, читати статуси і реагувати на події, парою функцій не обійтись. Таки протокол тре видумувати.

23

Re: Blynk, ESP8266, IoT

ця магічна штука називається препроцесором

#define BLYNK_VAR_INT(name, pin) \
    int name;  \
    BLYNK_WRITE(pin) { name = param.asInt(); } \
    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }
 
#define BLYNK_VAR_LONG(name, pin) \
    long name;  \
    BLYNK_WRITE(pin) { name = param.asLong(); } \
    BLYNK_READ(pin)  { Blynk.virtualWrite(pin, name); }

BLYNK_VAR_INT(name, pin) є користувацьким багаторядковим макросом, тобто коли ви пишете в коді програми
BLYNK_VAR_INT(REPLACE, 0x22), то в код програми цей вираз розгортається в

    int REPLACE;  \
    BLYNK_WRITE(0x22) { REPLACE = param.asInt(); } \
    BLYNK_READ(0x22)  { Blynk.virtualWrite(0x22, REPLACE); } 

Чим є вирази BLYNK_READ та BLYNK_WRITE я не знаю, але підозрюю що вини таким самим чином розгортаються в код програми. Бекслеш потрібний для того, аби перпроцесор це все вважав одним виразом, можна і без нього.

#define BLYNK_VAR_INT(name, pin) int name;  BLYNK_WRITE(pin) { name = param.asInt(); } BLYNK_READ(pin {Blynk.virtualWrite(pin, name); }

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: taburyak, leofun012

24

Re: Blynk, ESP8266, IoT

Якщо ви пишете ембеддед або трояни, то препроцесор ваш чи не найголовніший засіб розробки,

Говорила баба діду: «Я поїду к Білодіду, Ізучу двомовну мову І вернусь обратно знову». А дід бабі: «Не *изди, К Білодіду нєт їзди, — Туди не ходять поїзди»
Подякували: taburyak1

25

Re: Blynk, ESP8266, IoT

0xDADA11C7 написав:

Якщо ви пишете ембеддед або трояни, то препроцесор ваш чи не найголовніший засіб розробки,

Та користуюсь я тим препроцесором, але видно не на повну котушку. На усвідомлення таких "хитрих" макросів мені потрібен час.

26

Re: Blynk, ESP8266, IoT

Не можу я подолати ці хитрощі з передпроцесором.
Спробую пояснити що хочу, а ви вже направте в потрібне русло.
Я приймаю пакет даних, де є номер шпильки і дані, які на тій шпильці є. Номер шпильки - число від 0 до 127, а данні - масив з char'ів.
В заголовний файл почав щось шкрябати на кшталт такого (просто для попробувати розібратись):

#define BLYNK_WRITE_MY(pin) void Blynk_Write ## pin(void)

А в файлі main написав таку функцію:

BLYNK_WRITE_MY(20)
{

}

Ну а далі в мене ступор. Що треба зробити щоб коли я прийняв пакет даних для 20-тої шпильки в мене в головній програмі main викликалась функція BLYNK_WRITE_MY(20). Ну треба ще передати туди в середину ще й масив з char'ів.
Не знаю навіть що гуглити. Допоможіть будь ласка.

27

Re: Blynk, ESP8266, IoT

taburyak написав:

Не можу я подолати ці хитрощі з передпроцесором.
Спробую пояснити що хочу, а ви вже направте в потрібне русло.
Я приймаю пакет даних, де є номер шпильки і дані, які на тій шпильці є. Номер шпильки - число від 0 до 127, а данні - масив з char'ів.
В заголовний файл почав щось шкрябати на кшталт такого (просто для попробувати розібратись):

#define BLYNK_WRITE_MY(pin) void Blynk_Write ## pin(void)

А в файлі main написав таку функцію:

BLYNK_WRITE_MY(20)
{

}

Ну а далі в мене ступор. Що треба зробити щоб коли я прийняв пакет даних для 20-тої шпильки в мене в головній програмі main викликалась функція BLYNK_WRITE_MY(20). Ну треба ще передати туди в середину ще й масив з char'ів.
Не знаю навіть що гуглити. Допоможіть будь ласка.

Викликати

Blynk_Write20();

Як туди передати масив - це вже окреме питання. Наприклад, додати параметр замість void.
В цілому можете сказати, як ви хочете, щоб виглядав код у main?

28 Востаннє редагувалося taburyak (19.02.2018 15:14:06)

Re: Blynk, ESP8266, IoT

koala написав:

В цілому можете сказати, як ви хочете, щоб виглядав код у main?

У файлі blynk_protocol.c викликається функція коли прийшла відповідна команда, де я можу отримати номер pin і дані які на тому pin є:

void Blynk_Handler_Command(char * data, uint8_t size)
{
   if (data[BLYNK_OFFSET_RW_PIN] == BLYNK_READ_PIN)
   {
     //TODO: Для STM32. Тут обробляємо те що приходить з серверу
     HAL_UART_Transmit(&huart2, (uint8_t*) data, size, 1000); // Для відладки, просто дивимось в терміналі ПК що прийшло.
     int pin = data[BLYNK_OFFSET_NUM_PIN]; // Отримуємо номер шпильки
     // Тут колись буде отримання даних з цієї шпильки
    }
}

Далі я не знаю що робити, щоб в викликалась функція в головному файлі, якщо вона там є, і не викликалась, як її немає. От наприклад мене цікавлять дані на V0 і V20, а дані на V40 мене не цікавлять, хоча дані з V40 надходять і
функція Blynk_Handler_Command викликається.

Тоді в голоному файлі main.c я пишу функції для 0 і 20 шпильки:

BLYNK_WRITE_MY(V0)
{
    HAL_GPIO_TogglePin(LD3_GPIO_Port, LD3_Pin);
}

BLYNK_WRITE_MY(V20)
{
    HAL_GPIO_TogglePin(LD4_GPIO_Port, LD4_Pin);
}

А для 40-вої шпильки не пишу. І все має компілюватись і працювати.

29 Востаннє редагувалося koala (19.02.2018 16:30:46)

Re: Blynk, ESP8266, IoT

Отже, в Blynk_Handler_Command ви отримуєте під час роботи номер піна, і хочете викликати відповідну функцію, якщо вона існує, то вам потрібно якось перевіряти її існування під час роботи. Тобто щонайменше зробити якийсь диспетчер, хоча б табличкою

typedef void (*Event_handler)(char *);//вам же треба туди посилання на дані передавати, чи не так?
Event_handler func_table[128] = {NULL};//не певен, що воно так працює в C. Я маю на увазі масив, забитий NULL-ами.
//а тепер трохи ігор: проголошуємо функцію, пхаємо вказівник на неї в масив і чекаємо на проголошення
#define BLYNK_WRITE_MY(pin) void Blynk_Write ## pin(void); \
func_table[pin]=&Blynk_Write ## pin; \
void Blynk_Write ## pin(void)
...
//а тепер викликаємо
if(func_table[pin]!=NULL){
  func_table[pin](параметри);
}
Подякували: taburyak, NagarD, leofun013

30

Re: Blynk, ESP8266, IoT

Перепрошую, я не зрозумів як це працює. Взагалі :(

typedef void (*Event_handler)(char *);//вам же треба туди посилання на дані передавати, чи не так?

Це я так розумію, типу вказівник на функцію?
Ну так, потрібно викликати функцію в main.c, якщо вона там є, з "прив'язкою" до конкретної шпильки і передати в неї масив char чи посилання на масив.

Event_handler func_table[128] = {NULL};//не певен, що воно так працює в C. Я маю на увазі масив, забитий NULL-ами.

Це масив для вказівників на фукнцію?
Далі вже повне не розуміння, що там відбувається, тому я навіть не знаю як цим скористатись :((( Біда, біда, огорченіє...

Подякували: NagarD1

31

Re: Blynk, ESP8266, IoT

Намагаюсь розібратись і ось що поки є.

У заголовному файлі blynk_protocol.h

//------------------------------------------------------------
#define MYHIOT_WRITE(pin) \
    void MyhiotWidgetWrite##pin(char *)

typedef void (*WidgetWriteHandler)(char *);

WidgetWriteHandler GetWriteHandler(uint8_t pin);

MYHIOT_WRITE(0 );
...
MYHIOT_WRITE(127 );

В сирцевому файлі blynk_protocol.с

static const WidgetWriteHandler MyhiotWriteHandlerVector[128] = {
        MyhiotWidgetWrite0,       MyhiotWidgetWrite1,       MyhiotWidgetWrite2,       MyhiotWidgetWrite3,
        ......................        ......................        ......................
        MyhiotWidgetWrite124,    MyhiotWidgetWrite125,    MyhiotWidgetWrite126,    MyhiotWidgetWrite127
};

WidgetWriteHandler GetWriteHandler(uint8_t pin)
{

    return MyhiotWriteHandlerVector[pin];

}

Та в цьому ж файлі в обробнику те що приходить з сервера blynk

void Blynk_Handler_Command(char * data, uint8_t size)
{
    if (data[BLYNK_OFFSET_RW_PIN] == BLYNK_READ_PIN)
    {
        WidgetWriteHandler handler = GetWriteHandler(data[BLYNK_OFFSET_NUM_PIN]);
        handler(data);
    }
}

Компілюється без помилок! Тепер коли в головному файлі main.c роблю запис:

MYHIOT_WRITE(V20)
{
    //Має сюди перекинути коли щось прийшло від 20-тої шпильки
}

Але дає помилку: "Description    Resource    Path    Location    Type
parameter name omitted    main.c    /STM32F103Nucleo_communication_between_boards/Src    line 380    C/C++ Problem"

Думаю я ще щось залишив поза уваги. Поки не можу зрозуміти. Є думки?

32 Востаннє редагувалося taburyak (21.02.2018 13:54:58)

Re: Blynk, ESP8266, IoT

Зробив так:

#define MYHIOT_WRITE(pin) \
    void MyhiotWidgetWrite##pin(char * UNUSED)

typedef void (*WidgetWriteHandler)(char * UNUSED);

Попередня помилка зникла, але вилізло інше: blynk_protocol.o:(.rodata.MyhiotWriteHandlerVector+0x0): undefined reference to `MyhiotWidgetWrite0'
І так по всім векторам.

Я не розумію. Що робити?

33 Востаннє редагувалося ReAl (21.02.2018 14:36:31)

Re: Blynk, ESP8266, IoT

Те ж саме, що вже зроблено у системі програмування для обробників переривань.
Адже таблиця векторів формується завжди вся, а обробники Ви створюєте лише ті, які потрібні.

// Створюємо одну функцію-«затичку»
void MyhiotWidgetWriteDummy(char * UNUSED) {
    // do nothing or signal run-time error ...
}

// Створюємо weak-aliases на всі імена функцій.
//  weak означає, що якщо у проекті буде не-weak мітка, то буде використана та
//  «нормальна» функція. Для всіх функцій, не створених у проекті, в таблиці
//  буде посилання на одну MyhiotWidgetWriteDummy
//  Це робота лінкера, тобто «справжні» функції можуть бути
//  розкидані по файлах і нічого не знати про weak-версії
#pragma weak MyhiotWidgetWrite0    = MyhiotWidgetWriteDummy
#pragma weak MyhiotWidgetWrite1    = MyhiotWidgetWriteDummy
// ...
#pragma weak MyhiotWidgetWrite127  = MyhiotWidgetWriteDummy
printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: taburyak, leofun012

34

Re: Blynk, ESP8266, IoT

ReAl написав:

Створюємо weak-aliases на всі імена функцій

Працює!!!
Пішов поплачу десь в куточку.

Давай я тобі хоч мобільний поповню чи що.

35

Re: Blynk, ESP8266, IoT

Наплакався.
Тепер не можу зрозуміти, як передати той масив char'ів коли викликаю:

WidgetWriteHandler handler = GetWriteHandler(data[BLYNK_OFFSET_NUM_PIN]);
        handler(data);

То перекидує на:

MYHIOT_WRITE(20)
{    
    HAL_GPIO_TogglePin(LD6_GPIO_Port, LD6_Pin);
}

А як "data" тут зловити? Може я щось не вірно початково заклав у код?

36

Re: Blynk, ESP8266, IoT

От прикручу на сайті якусь «донатку», тоді.
А взагалі — як все остаточно втруситься і запрацює, то має бути докладна стаття тут на форумі на цю тему. Із фрагментами коду, знімками екрану, архівом простого демонстраційного проекту.
Потрійна вигода:
• коли щось комусь пояснюєш, то розбираєшся у цьому ще краще(1)
• розвивається форум і більше сюди зазиратимуть з гугла
• я почитаю і може нарешті сам пограюся, бо закладка на цей Blynk десь давно у переглядачі збережена, а досі не дивився.

________________________________
(1) Старий анекдот:
Ну й тупі ці студенти, раз їм все розказав, другий, третій, вже й сам все зрозумів, а вони — ніяк.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");
Подякували: taburyak1

37

Re: Blynk, ESP8266, IoT

taburyak написав:

Наплакався.
Тепер не можу зрозуміти, як передати той масив char'ів коли викликаю:

WidgetWriteHandler handler = GetWriteHandler(data[BLYNK_OFFSET_NUM_PIN]);
        handler(data);

То перекидує на:

MYHIOT_WRITE(20)
{    
    HAL_GPIO_TogglePin(LD6_GPIO_Port, LD6_Pin);
}

А як "data" тут зловити? Може я щось не вірно початково заклав у код?

А що ото за char * UNUSED? Чи не треба його перейменувати на char * pdata

MYHIOT_WRITE(20)
{    
    // тут працюємо з pdata, воно ж у макросі MYHIOT_WRITE вже додане у прототип функції
    HAL_GPIO_TogglePin(LD6_GPIO_Port, LD6_Pin);
}
printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");

38

Re: Blynk, ESP8266, IoT

ReAl написав:

то має бути докладна стаття тут на форумі на цю тему. Із фрагментами коду, знімками екрану, архівом простого демонстраційного проекту.

Це обов'язково. Бо ж самі блінкери не зацікавлені в створені бібліотеки для stm32, або там PIC. Мовляв не популярні платформи, ля-ля-тополя. А портувати з C++ на С на інше залізо, то мені не під силу. Та й все одно, як і на STM32 запустити блінка, потрібна ESP8266 чи ESP32, як модем. То я й подумав, а як блінк на ESP8266 робить прекрасно, хай там і робить. Потрібна залізо-назалежна прокладка між блінком на ESP8266 і іншим MCU. Так навіть крутіше вийде. Задумав і оновлення прошивок по ОТА, і керування на рівні заліза тим ESP8266 з іншого MCU, або навпаки. Головне зараз зробити кістяк, визначитись з командами, та базовий функціонал запустити. А далі вже допилювати потроху. Звісно в вільний доступ то все дам.

39

Re: Blynk, ESP8266, IoT

ReAl написав:

А що ото за char * UNUSED? Чи не треба його перейменувати на char * pdata

Ну звісно що так. Величезне дякую. Воно працює!!! Так як я і хотів. Фантастика. Поплачу від щастя :)

40

Re: Blynk, ESP8266, IoT

taburyak написав:
ReAl написав:

то має бути докладна стаття тут на форумі на цю тему. Із фрагментами коду, знімками екрану, архівом простого демонстраційного проекту.

Це обов'язково. Бо ж самі блінкери не зацікавлені в створені бібліотеки для stm32, або там PIC…

Ну тим паче потрібна стаття. Буде популярною.

printf("Nested comments is %s\n", */*/**/"*/"/*"/**/ == '*' ? "OFF" : "ON");