### Initialize and Configure P-Net Profinet Device Stack Source: https://context7.com/rtlabs-com/p-net/llms.txt This snippet demonstrates the initialization of the P-Net Profinet device stack. It includes setting up configuration parameters such as tick intervals, mandatory callbacks, identification data (I&M0), network settings, and plugging the Device Access Point (DAP) module. The main loop continuously calls `pnet_handle_periodic` for protocol operation. Dependencies include 'pnet_api.h'. ```c #include "pnet_api.h" #include #include #include // Placeholder for application data and callbacks void *app_data = NULL; int (*app_state_callback)(void *, int) = NULL; int (*app_exp_module_callback)(void *, int, int) = NULL; int (*app_exp_submodule_callback)(void *, int, int, int) = NULL; int (*app_connect_callback)(void *) = NULL; int (*app_release_callback)(void *) = NULL; int (*app_read_callback)(void *, int, unsigned char *, int) = NULL; int (*app_write_callback)(void *, int, unsigned char *, int) = NULL; int running = 1; // Example control flag for the main loop int main() { // Configure stack pnet_cfg_t cfg = {0}; cfg.tick_us = 1000; // 1 ms tick interval // Set mandatory callbacks cfg.state_cb = app_state_callback; cfg.exp_module_cb = app_exp_module_callback; cfg.exp_submodule_cb = app_exp_submodule_callback; cfg.connect_cb = app_connect_callback; cfg.release_cb = app_release_callback; cfg.read_cb = app_read_callback; cfg.write_cb = app_write_callback; cfg.cb_arg = &app_data; // Configure I&M0 identification cfg.im_0_data.im_vendor_id_hi = 0x01; cfg.im_0_data.im_vendor_id_lo = 0x23; strncpy(cfg.im_0_data.im_order_id, "PNET-DEVICE-001", sizeof(cfg.im_0_data.im_order_id)); strncpy(cfg.im_0_data.im_serial_number, "SN-12345", sizeof(cfg.im_0_data.im_serial_number)); cfg.im_0_data.im_hardware_revision = 1; cfg.im_0_data.im_sw_revision_prefix = 'V'; cfg.im_0_data.im_sw_revision_functional_enhancement = 1; cfg.im_0_data.im_sw_revision_bug_fix = 0; cfg.im_0_data.im_sw_revision_internal_change = 0; // Network configuration strncpy(cfg.station_name, "profinet-device", sizeof(cfg.station_name)); strncpy(cfg.product_name, "Industrial Sensor", sizeof(cfg.product_name)); cfg.if_cfg.ip_cfg.ip_addr.a = 192; cfg.if_cfg.ip_cfg.ip_addr.b = 168; cfg.if_cfg.ip_cfg.ip_addr.c = 1; cfg.if_cfg.ip_cfg.ip_addr.d = 50; cfg.if_cfg.ip_cfg.ip_mask.a = 255; cfg.if_cfg.ip_cfg.ip_mask.b = 255; cfg.if_cfg.ip_cfg.ip_mask.c = 255; cfg.if_cfg.ip_cfg.ip_mask.d = 0; cfg.if_cfg.ip_gateway.a = 192; cfg.if_cfg.ip_gateway.b = 168; cfg.if_cfg.ip_gateway.c = 1; cfg.if_cfg.ip_gateway.d = 1; strncpy(cfg.if_cfg.main_port.if_name, "eth0", sizeof(cfg.if_cfg.main_port.if_name)); cfg.num_physical_ports = 1; cfg.min_device_interval = 32; // 1 ms in 31.25 us units strncpy(cfg.file_directory, "/var/lib/pnet/", sizeof(cfg.file_directory)); // Initialize stack pnet_t *net = pnet_init(&cfg); if (net == NULL) { fprintf(stderr, "Failed to initialize P-Net stack\n"); return -1; } // Plug DAP (Device Access Point) module pnet_plug_module(net, 0, 0, PNET_MOD_DAP_IDENT); pnet_plug_submodule(net, 0, 0, PNET_SUBSLOT_DAP_IDENT, PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_IDENT, PNET_DIR_NO_IO, 0, 0); pnet_plug_submodule(net, 0, 0, PNET_SUBSLOT_DAP_INTERFACE_1_IDENT, PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_INTERFACE_1_IDENT, PNET_DIR_NO_IO, 0, 0); pnet_plug_submodule(net, 0, 0, PNET_SUBSLOT_DAP_INTERFACE_1_PORT_1_IDENT, PNET_MOD_DAP_IDENT, PNET_SUBMOD_DAP_INTERFACE_1_PORT_1_IDENT, PNET_DIR_NO_IO, 0, 0); // Main loop while (running) { pnet_handle_periodic(net); // Must be called every tick_us microseconds usleep(1000); } // Cleanup (optional, not shown in original snippet) // pnet_free(net); return 0; } ``` -------------------------------- ### Clone Profinet Device Stack with Submodules Source: https://github.com/rtlabs-com/p-net/blob/public/README.md This command clones the P-Net Profinet device stack repository, ensuring that all submodules are also downloaded. This is a prerequisite for building and running the sample application. ```bash git clone --recurse-submodules https://github.com/rtlabs-com/p-net.git ``` -------------------------------- ### C: Handle PLC Parameter Read/Write Operations Source: https://context7.com/rtlabs-com/p-net/llms.txt Implements callback functions for PROFINET parameter access. Handles reading device configuration and calibration data, and writing device configuration and sensor settings. Includes error handling for invalid requests. Requires PROFINET library functions and data structures. ```c #define PARAM_IDX_DEVICE_CONFIG 0x1000 #define PARAM_IDX_CALIBRATION 0x1001 #define PARAM_IDX_SENSOR_SETTINGS 0x1002 typedef struct { uint8_t mode; uint8_t sensitivity; uint16_t threshold; uint32_t reserved; } device_params_t; static device_params_t g_device_params = { .mode = 1, .sensitivity = 50, .threshold = 1000 }; int app_read_callback(pnet_t *net, void *arg, uint32_t arep, uint32_t api, uint16_t slot, uint16_t subslot, uint16_t idx, uint16_t sequence_number, uint8_t **pp_read_data, uint16_t *p_read_length, pnet_result_t *p_result) { printf("PLC read request: idx=0x%04X, slot=%u.%u\n", idx, slot, subslot); // Clear error status memset(p_result, 0, sizeof(*p_result)); switch (idx) { case PARAM_IDX_DEVICE_CONFIG: *pp_read_data = (uint8_t *)&g_device_params; *p_read_length = sizeof(g_device_params); printf(" Returning device configuration (%u bytes)\n", *p_read_length); return 0; case PARAM_IDX_CALIBRATION: // Return calibration data *pp_read_data = get_calibration_data(); *p_read_length = get_calibration_size(); return 0; default: fprintf(stderr, " Unsupported parameter index 0x%04X\n", idx); p_result->pnio_status.error_code = PNET_ERROR_CODE_READ; p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW; p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_ACC_INVALID_INDEX; return -1; } } int app_write_callback(pnet_t *net, void *arg, uint32_t arep, uint32_t api, uint16_t slot, uint16_t subslot, uint16_t idx, uint16_t sequence_number, uint16_t write_length, const uint8_t *p_write_data, pnet_result_t *p_result) { printf("PLC write request: idx=0x%04X, slot=%u.%u, length=%u\n", idx, slot, subslot, write_length); memset(p_result, 0, sizeof(*p_result)); switch (idx) { case PARAM_IDX_DEVICE_CONFIG: if (write_length != sizeof(g_device_params)) { fprintf(stderr, " Invalid data length\n"); p_result->pnio_status.error_code = PNET_ERROR_CODE_WRITE; p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW; p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_ACC_WRITE_LENGTH_ERROR; return -1; } memcpy(&g_device_params, p_write_data, sizeof(g_device_params)); printf(" Device configuration updated: mode=%u, sensitivity=%u\n", g_device_params.mode, g_device_params.sensitivity); // Save to persistent storage save_device_config(&g_device_params); return 0; case PARAM_IDX_SENSOR_SETTINGS: if (!validate_sensor_settings(p_write_data, write_length)) { p_result->pnio_status.error_code = PNET_ERROR_CODE_WRITE; p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW; p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_ACC_INVALID_PARAMETER; return -1; } apply_sensor_settings(p_write_data, write_length); return 0; default: fprintf(stderr, " Unsupported parameter index 0x%04X\n", idx); p_result->pnio_status.error_code = PNET_ERROR_CODE_WRITE; p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIORW; p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_ACC_INVALID_INDEX; return -1; } } ``` -------------------------------- ### C: Manage PLC Connection State with Callbacks Source: https://context7.com/rtlabs-com/p-net/llms.txt Handles various PLC connection lifecycle events using a state callback function. It manages connection status, initializes I/O data, and signals application readiness. Dependencies include the pnet library. ```c int app_state_callback(pnet_t *net, void *arg, uint32_t arep, pnet_event_values_t state) { app_data_t *app = (app_data_t *)arg; switch (state) { case PNET_EVENT_STARTUP: printf("PLC connection starting (AREP: %u)\n", arep); app->connected = false; break; case PNET_EVENT_PRMEND: printf("Parameters received from PLC\n"); // Initialize all input data and provider status (IOPS) uint8_t init_data[8] = {0}; pnet_input_set_data_and_iops(net, 0, 1, 1, init_data, sizeof(init_data), PNET_IOXS_GOOD); pnet_input_set_data_and_iops(net, 0, 2, 1, init_data, 4, PNET_IOXS_GOOD); // Initialize all output consumer status (IOCS) pnet_output_set_iocs(net, 0, 3, 1, PNET_IOXS_GOOD); pnet_output_set_iocs(net, 0, 4, 1, PNET_IOXS_GOOD); // Set provider state to RUN pnet_set_provider_state(net, true); // Signal application ready - this must be called after PRMEND if (pnet_application_ready(net, arep) != 0) { fprintf(stderr, "Failed to signal application ready\n"); return -1; } break; case PNET_EVENT_APPLRDY: printf("Application ready confirmed by PLC\n"); break; case PNET_EVENT_DATA: printf("Cyclic data exchange active\n"); app->connected = true; app->arep = arep; break; case PNET_EVENT_ABORT: printf("Connection aborted\n"); app->connected = false; break; } return 0; } ``` -------------------------------- ### C: Configure PLC Modules and Submodules Source: https://context7.com/rtlabs-com/p-net/llms.txt Responds to PLC module and submodule configuration requests by plugging in the appropriate hardware definitions. This function validates requested modules and submodules, returning errors for unsupported types. It uses predefined module and submodule identifiers. ```c #define MY_MODULE_ID_INPUT 0x00000032 #define MY_MODULE_ID_OUTPUT 0x00000033 #define MY_SUBMOD_ID_8DI 0x00000001 // 8 digital inputs #define MY_SUBMOD_ID_8DO 0x00000002 // 8 digital outputs #define MY_SUBMOD_ID_ANALOG 0x00000003 // 4 analog inputs int app_exp_module_callback(pnet_t *net, void *arg, uint32_t api, uint16_t slot, uint32_t module_ident) { printf("PLC expects module 0x%08X in slot %u\n", module_ident, slot); // Validate requested module if (module_ident == MY_MODULE_ID_INPUT || module_ident == MY_MODULE_ID_OUTPUT) { int ret = pnet_plug_module(net, api, slot, module_ident); if (ret != 0) { fprintf(stderr, "Failed to plug module in slot %u\n", slot); } return ret; } fprintf(stderr, "Unsupported module 0x%08X\n", module_ident); return -1; // Reject unsupported modules } int app_exp_submodule_callback(pnet_t *net, void *arg, uint32_t api, uint16_t slot, uint16_t subslot, uint32_t module_ident, uint32_t submodule_ident, const pnet_data_cfg_t *p_exp_data) { printf("PLC expects submodule 0x%08X in slot %u.%u\n", submodule_ident, slot, subslot); printf(" Expected direction: %u, input size: %u, output size: %u\n", p_exp_data->data_dir, p_exp_data->insize, p_exp_data->outsize); int ret = -1; // Configure based on submodule type if (submodule_ident == MY_SUBMOD_ID_8DI) { // 8 digital inputs = 1 byte to PLC ret = pnet_plug_submodule(net, api, slot, subslot, module_ident, submodule_ident, PNET_DIR_INPUT, 1, 0); } else if (submodule_ident == MY_SUBMOD_ID_8DO) { // 8 digital outputs = 1 byte from PLC ret = pnet_plug_submodule(net, api, slot, subslot, module_ident, submodule_ident, PNET_DIR_OUTPUT, 0, 1); } else if (submodule_ident == MY_SUBMOD_ID_ANALOG) { // 4 analog inputs = 8 bytes to PLC (16-bit values) ret = pnet_plug_submodule(net, api, slot, subslot, module_ident, submodule_ident, PNET_DIR_INPUT, 8, 0); } else { fprintf(stderr, "Unsupported submodule 0x%08X\n", submodule_ident); } return ret; } ``` -------------------------------- ### P-Net Connection Callbacks (C) Source: https://context7.com/rtlabs-com/p-net/llms.txt Callback functions for managing Profinet PLC connections. This includes accepting/rejecting connections, handling release requests, and processing device control commands. These callbacks are essential for integrating Profinet device connectivity into embedded systems. Dependencies include the P-Net library and standard C libraries. ```c int app_connect_callback(pnet_t *net, void *arg, uint32_t arep, pnet_result_t *p_result) { app_data_t *app = (app_data_t *)arg; printf("PLC connection request (AREP: %u)\n", arep); // Check if we can accept this connection if (app->connected && app->arep != arep) { fprintf(stderr, "Already connected to different controller\n"); p_result->pnio_status.error_code = PNET_ERROR_CODE_CONNECT; p_result->pnio_status.error_decode = PNET_ERROR_DECODE_PNIO; p_result->pnio_status.error_code_1 = PNET_ERROR_CODE_1_CONN_FAULTY_AR_BLOCK_REQ; return -1; // Reject connection } // Accept connection memset(p_result, 0, sizeof(*p_result)); printf("Connection accepted\n"); return 0; } int app_release_callback(pnet_t *net, void *arg, uint32_t arep, pnet_result_t *p_result) { app_data_t *app = (app_data_t *)arg; printf("PLC release request (AREP: %u)\n", arep); app->connected = false; memset(p_result, 0, sizeof(*p_result)); return 0; // Connection will be released regardless of return value } int app_dcontrol_callback(pnet_t *net, void *arg, uint32_t arep, pnet_control_command_t control_command, pnet_result_t *p_result) { const char *cmd_names[] = { "PRM_BEGIN", "PRM_END", "APP_RDY", "RELEASE", "RDY_FOR_COMPANION", "RDY_FOR_RTC3" }; printf("DControl command: %s (AREP: %u)\n", cmd_names[control_command], arep); memset(p_result, 0, sizeof(*p_result)); switch (control_command) { case PNET_CONTROL_COMMAND_PRM_BEGIN: printf(" Parameter transfer starting\n"); break; case PNET_CONTROL_COMMAND_PRM_END: printf(" Parameter transfer complete\n"); break; case PNET_CONTROL_COMMAND_APP_RDY: printf(" PLC application ready\n"); break; case PNET_CONTROL_COMMAND_RELEASE: printf(" PLC releasing connection\n"); break; default: break; } return 0; } int app_ccontrol_callback(pnet_t *net, void *arg, uint32_t arep, pnet_result_t *p_result) { printf("CControl confirmation (AREP: %u)\n", arep); if (p_result->pnio_status.error_code != PNET_ERROR_CODE_NOERROR) { fprintf(stderr, "CControl error: code=0x%02X, code_1=0x%02X\n", p_result->pnio_status.error_code, p_result->pnio_status.error_code_1); } return 0; } ``` -------------------------------- ### P-NET Cyclic Data Exchange in C Source: https://context7.com/rtlabs-com/p-net/llms.txt This C function facilitates cyclic data exchange with a PLC using the P-NET library. It reads output data, processes it, and sends input data back to the PLC, while also checking the status of IOPS and IOCCs. It requires the pnet_t and app_data_t structures, and relies on external functions for hardware interaction like set_physical_outputs, read_digital_inputs, read_analog_inputs, and sensor_health_ok. ```c void process_io_data(pnet_t *net, app_data_t *app) { if (!app->connected) { return; } // Read output data from PLC (slot 3, subslot 1) uint8_t output_data[4]; uint16_t output_len = sizeof(output_data); uint8_t iops; bool new_flag; int ret = pnet_output_get_data_and_iops(net, 0, 3, 1, &new_flag, output_data, &output_len, &iops); if (ret == 0) { if (new_flag) { printf("New output data from PLC: %u bytes\n", output_len); } if (iops == PNET_IOXS_GOOD && output_len > 0) { // Process valid data app->digital_outputs = output_data[0]; set_physical_outputs(output_data[0]); // Acknowledge good reception pnet_output_set_iocs(net, 0, 3, 1, PNET_IOXS_GOOD); } else { fprintf(stderr, "Bad IOPS from PLC\n"); pnet_output_set_iocs(net, 0, 3, 1, PNET_IOXS_BAD); } } // Send input data to PLC (slot 1, subslot 1) uint8_t input_data[8]; input_data[0] = read_digital_inputs(); // Read from hardware // Read analog sensors (4 channels, 16-bit each) uint16_t analog_values[4]; read_analog_inputs(analog_values); memcpy(&input_data[1], analog_values, sizeof(analog_values)); // Check for sensor errors uint8_t iops_status = sensor_health_ok() ? PNET_IOXS_GOOD : PNET_IOXS_BAD; ret = pnet_input_set_data_and_iops(net, 0, 1, 1, input_data, sizeof(input_data), iops_status); if (ret != 0) { fprintf(stderr, "Failed to set input data\n"); } // Check consumer status for our input data uint8_t iocs; if (pnet_input_get_iocs(net, 0, 1, 1, &iocs) == 0) { if (iocs != PNET_IOXS_GOOD) { fprintf(stderr, "PLC not accepting our input data\n"); } } } ``` -------------------------------- ### C: Handle Incoming PLC Alarms using P-Net Source: https://context7.com/rtlabs-com/p-net/llms.txt This callback function processes alarm indications received from the PLC. It logs details about the incoming alarm, such as type, slot, subslot, and payload size. Crucially, it always sends an acknowledgment back to the PLC using `pnet_alarm_send_ack` to confirm receipt of the alarm, regardless of whether the alarm payload is processed. ```c int app_alarm_ind_callback(pnet_t *net, void *arg, uint32_t arep, const pnet_alarm_argument_t *p_alarm_arg, uint16_t data_len, uint16_t data_usi, const uint8_t *p_data) { printf("Received alarm from PLC: type=0x%04X, slot=%u, subslot=%u, USI=0x%04X\n", p_alarm_arg->alarm_type, p_alarm_arg->slot_nbr, p_alarm_arg->subslot_nbr, data_usi); // Process alarm payload if (data_len > 0 && p_data != NULL) { printf(" Alarm payload: %u bytes\n", data_len); // Handle alarm data... } // Always send acknowledgment pnet_pnio_status_t pnio_status = { .error_code = PNET_ERROR_CODE_NOERROR, .error_decode = PNET_ERROR_DECODE_NOERROR, .error_code_1 = 0, .error_code_2 = 0 }; int ret = pnet_alarm_send_ack(net, arep, p_alarm_arg, &pnio_status); if (ret != 0) { fprintf(stderr, "Failed to send alarm acknowledgment\n"); } return 0; } ``` -------------------------------- ### C: Handle PLC Alarm Acknowledgment using P-Net Source: https://context7.com/rtlabs-com/p-net/llms.txt This callback function is invoked when the PLC acknowledges a sent process alarm. It resets the `alarm_in_progress` flag, indicating that the system is ready to send another alarm. The function logs whether the acknowledgment was successful or reports any error codes received from the PLC. ```c int app_alarm_cnf_callback(pnet_t *net, void *arg, uint32_t arep, const pnet_pnio_status_t *p_pnio_status) { alarm_in_progress = false; if (p_pnio_status->error_code == PNET_ERROR_CODE_NOERROR) { printf("PLC acknowledged alarm successfully\n"); } else { printf("PLC alarm response: error_code=0x%02X, error_code_1=0x%02X\n", p_pnio_status->error_code, p_pnio_status->error_code_1); } return 0; } ``` -------------------------------- ### C: Send Process Alarm to PLC using P-Net Source: https://context7.com/rtlabs-com/p-net/llms.txt This function sends a process alarm to the PLC via the P-Net library. It checks if an alarm is already in progress to prevent concurrent operations. The function prepares an alarm payload with type, error code, and timestamp, then uses `pnet_alarm_send_process_alarm` to transmit it. It manages a global flag `alarm_in_progress` to track the alarm state. ```c // Global flag to track alarm state static bool alarm_in_progress = false; void send_process_alarm(pnet_t *net, uint32_t arep) { if (alarm_in_progress) { printf("Alarm already in progress, waiting for confirmation\n"); return; } // Prepare alarm payload uint8_t alarm_payload[20]; alarm_payload[0] = 0x01; // Alarm type alarm_payload[1] = 0x05; // Error code uint32_t timestamp = get_timestamp(); memcpy(&alarm_payload[2], ×tamp, sizeof(timestamp)); // ... additional alarm data int ret = pnet_alarm_send_process_alarm( net, arep, 0, // API 1, // Slot 1, // Subslot 0x8000, // Payload USI sizeof(alarm_payload), alarm_payload ); if (ret == 0) { alarm_in_progress = true; printf("Process alarm sent, waiting for PLC acknowledgment\n"); } else { fprintf(stderr, "Failed to send process alarm\n"); } } ``` -------------------------------- ### Update Temperature Diagnosis (C) Source: https://context7.com/rtlabs-com/p-net/llms.txt Updates the diagnosis information with the current temperature value for a submodule. It uses `pnet_diag_std_update` and specifies an over-temperature error type. The function is intended for a maximum update rate of 1 Hz and takes the Profinet network, slot, subslot, and temperature as input. ```c void update_temperature_diagnosis(pnet_t *net, uint16_t slot, uint16_t subslot, int16_t temp) { pnet_diag_source_t diag_source = { .api = 0, .slot = slot, .subslot = subslot, .ch = 0x8000, // Whole submodule .ch_grouping = PNET_DIAG_CH_INDIVIDUAL_CHANNEL, .ch_direction = PNET_DIAG_CH_PROP_DIR_INPUT }; // Update diagnosis with current temperature value (max 1 Hz update rate) pnet_diag_std_update(net, &diag_source, 0x8000, // Temperature error type 0x0001, // Extended type: over temperature temp); // Current temperature in 0.1°C units } ``` -------------------------------- ### Report Sensor Failure Diagnosis (C) Source: https://context7.com/rtlabs-com/p-net/llms.txt Adds a standard format diagnosis for a specific sensor failure. It defines the diagnosis source location and uses `pnet_diag_std_add` to report a fault. The function takes the Profinet network structure, slot, subslot, and channel as input. ```c void report_sensor_failure(pnet_t *net, uint16_t slot, uint16_t subslot, uint16_t channel) { // Define diagnosis source location pnet_diag_source_t diag_source = { .api = 0, .slot = slot, .subslot = subslot, .ch = channel, // Specific channel, or 0x8000 for whole submodule .ch_grouping = PNET_DIAG_CH_INDIVIDUAL_CHANNEL, .ch_direction = PNET_DIAG_CH_PROP_DIR_INPUT }; // Add standard format diagnosis int ret = pnet_diag_std_add( net, &diag_source, PNET_DIAG_CH_PROP_TYPE_16_BIT, // Channel data type PNET_DIAG_CH_PROP_MAINT_FAULT, // Severity: FAULT 0x0001, // Error type: short circuit 0x0000, // Extended error type (none) 0, // Additional value 0 // Qualifier (not used for FAULT) ); if (ret == 0) { printf("Diagnosis alarm sent for channel %u\n", channel); } } ``` -------------------------------- ### Report Manufacturer Diagnosis (C) Source: https://context7.com/rtlabs-com/p-net/llms.txt Reports manufacturer-specific diagnosis information using the USI (Universal Station Identifier) format. It allows for custom error codes and status flags. The `pnet_diag_usi_add` function is used for this purpose, requiring the Profinet network, API, slot, subslot, USI identifier, data length, and the manufacturer data itself. ```c void report_manufacturer_diagnosis(pnet_t *net) { // Use USI format for manufacturer-specific diagnosis uint8_t manuf_data[10]; manuf_data[0] = 0x01; // Error code manuf_data[1] = 0xFF; // Status flags // ... fill remaining manufacturer-specific data int ret = pnet_diag_usi_add(net, 0, 1, 1, 0x1234, // USI identifier sizeof(manuf_data), manuf_data); if (ret == 0) { printf("Manufacturer diagnosis sent (USI: 0x1234)\n"); } // Later, to remove: // pnet_diag_usi_remove(net, 0, 1, 1, 0x1234); } ``` -------------------------------- ### Clear Sensor Failure Diagnosis (C) Source: https://context7.com/rtlabs-com/p-net/llms.txt Removes a previously reported sensor failure diagnosis. It uses `pnet_diag_std_remove` to send a 'disappears alarm'. The function requires the Profinet network structure, slot, subslot, and channel to identify the diagnosis to be cleared. ```c void clear_sensor_failure(pnet_t *net, uint16_t slot, uint16_t subslot, uint16_t channel) { pnet_diag_source_t diag_source = { .api = 0, .slot = slot, .subslot = subslot, .ch = channel, .ch_grouping = PNET_DIAG_CH_INDIVIDUAL_CHANNEL, .ch_direction = PNET_DIAG_CH_PROP_DIR_INPUT }; // Remove diagnosis (sends disappears alarm) int ret = pnet_diag_std_remove(net, &diag_source, 0x0001, 0x0000); if (ret == 0) { printf("Diagnosis cleared for channel %u\n", channel); } } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.