dev(UML-981): Реализован механизм евентов от профинета до приложения
This commit is contained in:
parent
86e4f454c2
commit
d5c127d911
@ -2,6 +2,7 @@
|
||||
|
||||
#include <mutex>
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
|
||||
class Flags {
|
||||
public:
|
||||
@ -10,6 +11,7 @@ public:
|
||||
void set_flag(uint32_t mask) {
|
||||
std::lock_guard<std::mutex> guard(mutex_);
|
||||
flags_ |= mask;
|
||||
flag_cond_.notify_one();
|
||||
}
|
||||
|
||||
uint32_t get_flag(uint32_t mask) {
|
||||
@ -28,7 +30,16 @@ public:
|
||||
flags_ &= ~mask;
|
||||
}
|
||||
|
||||
uint32_t wait_flags(uint32_t mask)
|
||||
{
|
||||
std::unique_lock<std::mutex> lk(mutex_);
|
||||
flag_cond_.wait(lk, [&]{return flags_ & mask;});
|
||||
lk.unlock();
|
||||
return flags_;
|
||||
}
|
||||
|
||||
private:
|
||||
uint32_t flags_;
|
||||
mutable std::mutex mutex_;
|
||||
std::condition_variable flag_cond_;
|
||||
};
|
55
src/main.cpp
55
src/main.cpp
@ -44,11 +44,8 @@ void endian_convert_32(uint8_t * p_data)
|
||||
|
||||
int main(int argc, char * argv[])
|
||||
{
|
||||
Echo_inpCycData.data.data_f = 54321.9f; /// Преобразовать в big endian
|
||||
Echo_inpCycData.data.data_i = 876; /// Преобразовать в big endian
|
||||
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f);
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_i);
|
||||
Echo_inpCycData.data.data_f = 0.0f; /// Преобразовать в big endian
|
||||
Echo_inpCycData.data.data_i = 0; /// Преобразовать в big endian
|
||||
|
||||
Echo_outCycData.data.data_f = 0.0f;
|
||||
Echo_outCycData.data.data_i = 0;
|
||||
@ -83,6 +80,11 @@ int main(int argc, char * argv[])
|
||||
/// Запуск потока Profinet
|
||||
profinet.Start();
|
||||
|
||||
|
||||
/**
|
||||
* @brief Ниже тестовый функционал
|
||||
*
|
||||
*/
|
||||
auto echo_mod = profinet.getModule(ECHO_MODULE_ID);
|
||||
auto echo_submod = echo_mod->getSubmodulePtr(ECHO_SUBMOD_ID);
|
||||
echo_submod->putDataToPlc(Echo_inpCycData.mem);
|
||||
@ -90,24 +92,31 @@ int main(int argc, char * argv[])
|
||||
auto param = echo_submod->getParameterPtr(ECHO_PARAMETER_GAIN_IDX);
|
||||
|
||||
|
||||
uint32_t ix = 0;
|
||||
while(1)
|
||||
{
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
++ix;
|
||||
std::cout << "tick: " << ix << endl;
|
||||
if (echo_submod->isDataUpdated())
|
||||
uint32_t event_mask = (Profinet::EVENT_CONNECTION_ESTABLISHED |
|
||||
Profinet::EVENT_NEW_CYCLIC_DATA |
|
||||
Profinet::EVENT_NEW_PARAM_DATA );
|
||||
for (;;)
|
||||
{
|
||||
uint32_t events = profinet.EventWait(event_mask);
|
||||
//std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
//++ix;
|
||||
//std::cout << "tick: " << ix << endl;
|
||||
|
||||
if (events & Profinet::EVENT_CONNECTION_ESTABLISHED)
|
||||
{
|
||||
std::cout << "New data from Plc" << endl;
|
||||
profinet.EventClear(Profinet::EVENT_CONNECTION_ESTABLISHED);
|
||||
|
||||
std::cout << "Event: PLC connection established" << endl;
|
||||
}
|
||||
else if (events & Profinet::EVENT_NEW_CYCLIC_DATA)
|
||||
{
|
||||
profinet.EventClear(Profinet::EVENT_NEW_CYCLIC_DATA);
|
||||
|
||||
///Читаем данные от ПЛК
|
||||
echo_submod->getDataFromPlc(Echo_outCycData.mem);
|
||||
//Читаем параметр записанный ПЛК при установлении связи
|
||||
param->readParameter((uint8_t*)&Echo_Gain);
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_Gain);
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_i);
|
||||
endian_convert_32((uint8_t*)&Echo_outCycData.data.data_f);
|
||||
|
||||
///Подготавливаем данные для ПЛК
|
||||
Echo_inpCycData.data.data_i = Echo_Gain * Echo_outCycData.data.data_i;
|
||||
Echo_inpCycData.data.data_f = Echo_Gain * Echo_outCycData.data.data_f;
|
||||
@ -116,6 +125,18 @@ int main(int argc, char * argv[])
|
||||
endian_convert_32((uint8_t*)&Echo_inpCycData.data.data_f);
|
||||
///Отправляем данные для ПЛК
|
||||
echo_submod->putDataToPlc(Echo_inpCycData.mem);
|
||||
|
||||
}
|
||||
else if (events & Profinet::EVENT_NEW_PARAM_DATA)
|
||||
{
|
||||
profinet.EventClear(Profinet::EVENT_NEW_PARAM_DATA);
|
||||
|
||||
std::cout << "Event: New parameter data: ";
|
||||
//Читаем параметр записанный ПЛК при установлении связи
|
||||
param->readParameter((uint8_t*)&Echo_Gain);
|
||||
/// Конвертируем в литл эндиан
|
||||
endian_convert_32((uint8_t*)&Echo_Gain);
|
||||
std::cout << "Echo_Gain = " << std::to_string(Echo_Gain) << endl;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -33,7 +33,6 @@ using namespace std;
|
||||
#define GET_HIGH_BYTE(id) ((id >> 8) & 0xFF)
|
||||
#define GET_LOW_BYTE(id) (id & 0xFF)
|
||||
|
||||
#define APP_MAIN_SLEEPTIME_US 5000 * 1000
|
||||
#define APP_SNMP_THREAD_PRIORITY 1
|
||||
#define APP_SNMP_THREAD_STACKSIZE 256 * 1024 /* bytes */
|
||||
#define APP_ETH_THREAD_PRIORITY 10
|
||||
@ -43,9 +42,9 @@ using namespace std;
|
||||
|
||||
#define FLAGS_AREP_APP_READY 0x00000001
|
||||
|
||||
//#define RELEASE
|
||||
#define LOG_ENABLE
|
||||
|
||||
#ifndef RELEASE
|
||||
#ifdef LOG_ENABLE
|
||||
#define LOG(STR) log_.put(STR)
|
||||
#else
|
||||
#define LOG(STR)
|
||||
@ -588,15 +587,16 @@ void Profinet::cyclicIoData()
|
||||
|
||||
if (submodule_ptr->m_data_cfg.outsize > 0)
|
||||
{
|
||||
bool outdata_updated;
|
||||
uint16_t outdata_length = submodule_ptr->m_data_cfg.outsize;
|
||||
uint8_t outdata_iops;
|
||||
|
||||
/// Копируем данные от контроллера в m_out_data_ptr
|
||||
submodule_ptr->outputGetData( m_pnet_data.pnet_ptr,
|
||||
m_pnet_data.api,
|
||||
slot_ptr->m_slot_nbr,
|
||||
subslot_ptr->m_subslot_nbr);
|
||||
subslot_ptr->m_subslot_nbr);
|
||||
|
||||
if (submodule_ptr->isDataUpdated())
|
||||
{
|
||||
events_.set_flag(EVENT_NEW_CYCLIC_DATA);
|
||||
}
|
||||
}
|
||||
|
||||
if (submodule_ptr->m_data_cfg.insize > 0)
|
||||
@ -672,12 +672,17 @@ int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
||||
* @brief Коды ошибок в err_cls и err_code
|
||||
* TODO: Нужно передавать в управляющее приложение
|
||||
*/
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
/// Ошибок нет
|
||||
}
|
||||
|
||||
events_.clear_flags(EVENT_CONNECTION_ESTABLISHED);
|
||||
|
||||
m_pnet_data.arep = UINT32_MAX;
|
||||
|
||||
/* Only abort AR with correct session key */
|
||||
///os_event_set (app->main_events, APP_EVENT_ABORT);
|
||||
}
|
||||
@ -719,6 +724,7 @@ int Profinet::callbackStateInd ( uint32_t arep, pnet_event_values_t event)
|
||||
else if (event == PNET_EVENT_STARTUP)
|
||||
{
|
||||
LOG("callbackStateInd: PNET_EVENT_STARTUP: A connection has been initiated.");
|
||||
events_.set_flag(EVENT_CONNECTION_ESTABLISHED);
|
||||
}
|
||||
else if (event == PNET_EVENT_APPLRDY)
|
||||
{
|
||||
@ -769,10 +775,7 @@ int Profinet::callbackDcontrolInd ( uint32_t arep,
|
||||
int Profinet::callbackCcontrolInd ( uint32_t arep, pnet_result_t * p_result)
|
||||
{
|
||||
LOG("callbackCcontrolInd");
|
||||
/**
|
||||
* @brief
|
||||
* Можно оставить пустым
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -854,7 +857,15 @@ int Profinet::callbackWriteInd ( uint32_t arep,
|
||||
}
|
||||
|
||||
///3. Копируем данные
|
||||
return param_ptr->writeParameter(p_write_data);
|
||||
if (!param_ptr->writeParameter(p_write_data))
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
|
||||
/// Устанавливаем событие
|
||||
events_.set_flag(EVENT_NEW_PARAM_DATA);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int Profinet::callbackExpModuleInd ( uint16_t slot, uint32_t module_ident)
|
||||
|
@ -18,6 +18,13 @@
|
||||
|
||||
class Profinet {
|
||||
public:
|
||||
enum Events
|
||||
{
|
||||
EVENT_CONNECTION_ESTABLISHED = 0x00000001, /// Установлено соединение с ПЛК
|
||||
EVENT_NEW_CYCLIC_DATA = 0x00000002, /// Получение новых циклических данных от ПЛК
|
||||
EVENT_NEW_PARAM_DATA = 0x00000004, /// Новая запись параметра от ПЛК
|
||||
};
|
||||
|
||||
Profinet();
|
||||
|
||||
bool Config(ProfinetSettings& Settings,
|
||||
@ -143,6 +150,11 @@ public:
|
||||
*/
|
||||
void Start();
|
||||
|
||||
uint32_t EventWait(uint32_t mask) { return events_.wait_flags(mask); }
|
||||
|
||||
void EventClear(uint32_t mask) { events_.clear_flags(mask); }
|
||||
|
||||
|
||||
~Profinet();
|
||||
|
||||
private:
|
||||
@ -168,22 +180,36 @@ private:
|
||||
std::map<uint32_t, std::shared_ptr<ProfinetModule>> m_modules;
|
||||
|
||||
Log log_;
|
||||
|
||||
Flags flags_;
|
||||
|
||||
|
||||
Flags flags_; /// Внутренние флаги: взаимодействиe между потоком Profinet и потоком стека Pnet
|
||||
|
||||
Flags events_; /// Флаги для внешних событий. Это более общие флаги, например флаг получения данных от ПЛК, а в каком подмодуле, уже не уточняется.
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Проверяет наличие слота slot_nbr в конфигурации
|
||||
* @brief Проверяет наличие слота slot_nbr в конфигурации и возвращает указатель на него
|
||||
*
|
||||
* @param slot_nbr номер слота
|
||||
* @return ProfinetSlot* - указатель на слот, при успехе или nullptr есои слот в конфигурации отсутсвует
|
||||
* @return std::shared_ptr<ProfinetSlot> указатель на слот, при успехе или nullptr если слот в конфигурации отсутсвует
|
||||
*/
|
||||
std::shared_ptr<ProfinetSlot> getSlotPtr(uint16_t slot_nbr);
|
||||
|
||||
/**
|
||||
* @brief Проверяет наличие подслота в слоте и возвращает указатель на него
|
||||
*
|
||||
* @param slot_nbr номер слота
|
||||
* @param subslot_nbr номер подслота
|
||||
* @return std::shared_ptr<ProfinetSubslot> указатель на подслот, при успехе или nullptr если подслот в конфигурации отсутсвует
|
||||
*/
|
||||
std::shared_ptr<ProfinetSubslot> getSubslotPtr(uint16_t slot_nbr, uint16_t subslot_nbr);
|
||||
|
||||
/**
|
||||
* @brief Флаг подключение к контроллеру(ПЛК).
|
||||
* Реализация взята с примера стека pnet. На самом деле не понятна роль AREP.
|
||||
* Открытой информации недостаточно, нужно покупать и смотреть спецификацию. *
|
||||
*
|
||||
* @return true подключение есть
|
||||
* @return false
|
||||
*/
|
||||
bool isConnectedToController() { return m_pnet_data.arep != UINT32_MAX; };
|
||||
|
||||
void initDataAndIoxs();
|
||||
|
@ -78,6 +78,8 @@ bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr,
|
||||
uint16_t slot_nbr,
|
||||
uint16_t subslot_nbr )
|
||||
{
|
||||
bool out = true;
|
||||
|
||||
/// Существуют подмодули без данных, например DAP
|
||||
if ((pnet_ptr == nullptr) || (out_data_ptr_ == nullptr))
|
||||
{
|
||||
@ -104,19 +106,25 @@ bool ProfinetSubmodule::outputGetData( pnet_t * pnet_ptr,
|
||||
|
||||
if ((!data_updated_) && (updated == true))
|
||||
{
|
||||
data_updated_ = updated; /// Сбрасывается после прочтения данных устройством
|
||||
/**
|
||||
* @brief Устанавливаем флаг новых данных (данные смогут быть такие-же, но флаг все равно установится)
|
||||
* Флаг сбрасывается в функции getDataFromPlc после прочтения данных устройством
|
||||
*/
|
||||
data_updated_ = updated;
|
||||
}
|
||||
|
||||
if (m_data_cfg.outsize != outdata_length)
|
||||
{
|
||||
/// Неправильная длина данных
|
||||
out = false;
|
||||
}
|
||||
else if (outdata_iops == PNET_IOXS_BAD)
|
||||
{
|
||||
/// Что-то не так с данными от контроллера
|
||||
out = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
return out;
|
||||
}
|
||||
|
||||
bool ProfinetSubmodule::getDataFromPlc(uint8_t * data_ptr)
|
||||
|
Loading…
Reference in New Issue
Block a user