Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions core/src/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ add_executable(plc_main
${CMAKE_SOURCE_DIR}/core/src/plc_app/scan_cycle_manager.c
${CMAKE_SOURCE_DIR}/core/src/drivers/plugin_driver.c
${CMAKE_SOURCE_DIR}/core/src/drivers/plugin_config.c
${CMAKE_SOURCE_DIR}/core/src/drivers/plugin_utils.c
${CMAKE_SOURCE_DIR}/core/src/plc_app/unix_socket.c
${CMAKE_SOURCE_DIR}/core/src/plc_app/debug_handler.c
)
Expand Down
4 changes: 4 additions & 0 deletions core/src/drivers/plugin_driver.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include "../plc_app/image_tables.h"
#include "plugin_config.h"
#include "plugin_driver.h"
#include "plugin_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
Expand Down Expand Up @@ -469,6 +470,9 @@ void *generate_structured_args_with_driver(plugin_type_t type, plugin_driver_t *
// Initialize mutex functions
args->mutex_take = plugin_mutex_take;
args->mutex_give = plugin_mutex_give;
args->get_var_list = get_var_list;
args->get_var_size = get_var_size;
args->get_var_count = get_var_count;
// Set buffer mutex from driver
args->buffer_mutex = &driver->buffer_mutex;

Expand Down
4 changes: 4 additions & 0 deletions core/src/drivers/plugin_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "plugin_config.h"
#include "python_plugin_bridge.h"
#include <pthread.h>
#include <stdint.h>

// Maximum number of plugins
#define MAX_PLUGINS 16
Expand Down Expand Up @@ -55,6 +56,9 @@ typedef struct
// Mutex functions
int (*mutex_take)(pthread_mutex_t *mutex);
int (*mutex_give)(pthread_mutex_t *mutex);
void (*get_var_list)(size_t num_vars, size_t *indexes, void **result);
size_t (*get_var_size)(size_t idx);
uint16_t (*get_var_count)(void);
pthread_mutex_t *buffer_mutex;
char plugin_specific_config_file_path[256];

Expand Down
28 changes: 28 additions & 0 deletions core/src/drivers/plugin_utils.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
#include "plugin_utils.h"
#include "../plc_app/image_tables.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// Wrapper function to get list of variable addresses
void get_var_list(size_t num_vars, size_t *indexes, void **result)
{
for (size_t i = 0; i < num_vars; i++) {
size_t idx = indexes[i];
if (idx >= ext_get_var_count()) {
result[i] = NULL;
} else {
result[i] = ext_get_var_addr(idx);
}
}
}

size_t get_var_size(size_t idx)
{
return ext_get_var_size(idx);
}

uint16_t get_var_count(void)
{
return ext_get_var_count();
}
11 changes: 11 additions & 0 deletions core/src/drivers/plugin_utils.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
#ifndef PLUGIN_UTILS_H
#define PLUGIN_UTILS_H

#include <stddef.h>
#include <stdint.h>

void get_var_list(size_t num_vars, size_t *indexes, void **result);
size_t get_var_size(size_t idx);
uint16_t get_var_count(void);

#endif // PLUGIN_UTILS_H
154 changes: 154 additions & 0 deletions core/src/drivers/plugins/python/shared/API_SPECIFICATION.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
# SafeBufferAccess API Specification

## Overview
This document specifies the complete public API of the `SafeBufferAccess` class that must be maintained for backward compatibility during refactoring.

## Class Structure

### Constructor
```python
SafeBufferAccess(runtime_args: PluginRuntimeArgs)
```

**Parameters:**
- `runtime_args`: `PluginRuntimeArgs` instance

**Attributes:**
- `is_valid: bool` - Whether the instance is properly initialized
- `error_msg: str` - Error message if initialization failed

### Public Methods

#### Mutex Management
```python
acquire_mutex() -> (bool, str)
release_mutex() -> (bool, str)
```

#### Boolean Buffer Operations
```python
read_bool_input(buffer_idx: int, bit_idx: int, thread_safe: bool = True) -> (bool, str)
read_bool_output(buffer_idx: int, bit_idx: int, thread_safe: bool = True) -> (bool, str)
write_bool_output(buffer_idx: int, bit_idx: int, value: bool, thread_safe: bool = True) -> (bool, str)
```

#### Byte Buffer Operations
```python
read_byte_input(buffer_idx: int, thread_safe: bool = True) -> (int, str)
read_byte_output(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_byte_output(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
```

#### Integer Buffer Operations (16-bit)
```python
read_int_input(buffer_idx: int, thread_safe: bool = True) -> (int, str)
read_int_output(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_int_output(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
read_int_memory(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_int_memory(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
```

#### Double Integer Buffer Operations (32-bit)
```python
read_dint_input(buffer_idx: int, thread_safe: bool = True) -> (int, str)
read_dint_output(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_dint_output(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
read_dint_memory(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_dint_memory(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
```

#### Long Integer Buffer Operations (64-bit)
```python
read_lint_input(buffer_idx: int, thread_safe: bool = True) -> (int, str)
read_lint_output(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_lint_output(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
read_lint_memory(buffer_idx: int, thread_safe: bool = True) -> (int, str)
write_lint_memory(buffer_idx: int, value: int, thread_safe: bool = True) -> (bool, str)
```

#### Batch Operations
```python
batch_read_values(operations: List[Tuple]) -> (List[Tuple], str)
batch_write_values(operations: List[Tuple]) -> (List[Tuple], str)
batch_mixed_operations(read_operations: List[Tuple], write_operations: List[Tuple]) -> (Dict, str)
```

#### Debug/Variable Operations
```python
get_var_list(indexes: List[int]) -> (List[int], str)
get_var_size(index: int) -> (int, str)
get_var_value(index: int) -> (Any, str)
set_var_value(index: int, value: Any) -> (bool, str)
get_var_count() -> (int, str)
get_var_info(index: int) -> (Dict, str)
```

#### Configuration Operations
```python
get_config_path() -> (str, str)
get_config_file_args_as_map() -> (Dict, str)
```

## Parameter Details

### Common Parameters
- `buffer_idx: int` - Buffer index (0-based)
- `bit_idx: int` - Bit index within buffer (for boolean operations)
- `value: int/bool` - Value to write
- `thread_safe: bool = True` - Whether to use mutex for thread-safe access

### Value Ranges
- `bool`: `True`/`False`
- `byte`: `0-255`
- `int`: `0-65535` (16-bit unsigned)
- `dint`: `0-4294967295` (32-bit unsigned)
- `lint`: `0-18446744073709551615` (64-bit unsigned)

### Return Values
- **Read operations**: `(value, error_message: str)`
- **Write operations**: `(success: bool, error_message: str)`
- **Batch operations**: `(results: List/Dict, error_message: str)`

## Error Handling
- Invalid buffer/bit indices return appropriate error messages
- Out-of-range values return validation errors
- Mutex acquisition failures return error messages
- All operations return consistent `(result, message)` tuples

## Thread Safety
- Default behavior uses mutex for thread-safe access
- `thread_safe=False` bypasses mutex (for manual control)
- Mutex operations: `acquire_mutex()`/`release_mutex()`

## Batch Operations Format

### Read Operations
```python
[
('buffer_type', buffer_idx, bit_idx), # for bool operations
('buffer_type', buffer_idx), # for other types
# ...
]
```

### Write Operations
```python
[
('buffer_type', buffer_idx, value, bit_idx), # for bool operations
('buffer_type', buffer_idx, value), # for other types
# ...
]
```

### Buffer Types
- `'bool_input'`, `'bool_output'`
- `'byte_input'`, `'byte_output'`
- `'int_input'`, `'int_output'`, `'int_memory'`
- `'dint_input'`, `'dint_output'`, `'dint_memory'`
- `'lint_input'`, `'lint_output'`, `'lint_memory'`

## Compatibility Requirements
- All existing tests must pass without modification
- All existing plugins must continue to work
- API signatures must remain identical
- Behavior must be preserved exactly
42 changes: 37 additions & 5 deletions core/src/drivers/plugins/python/shared/__init__.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,50 @@
"""
OpenPLC Python Plugin Configuration Package
OpenPLC Python Plugin Shared Components Package

This package provides shared components for OpenPLC Python plugins, including
buffer access utilities, configuration handling, and type definitions.
"""

# Core buffer access functionality (refactored modular architecture)
from .safe_buffer_access_refactored import SafeBufferAccess

# Legacy compatibility - import from original implementation if needed
from .python_plugin_types import (
PluginRuntimeArgs,
PluginStructureValidator,
safe_extract_runtime_args_from_capsule
)

# Configuration models
from .plugin_config_decode.plugin_config_contact import PluginConfigContract, PluginConfigError
from .plugin_config_decode.modbus_master_config_model import ModbusIoPointConfig, ModbusMasterConfig

# Component interfaces (for advanced users who want to extend the system)
from .component_interfaces import (
IBufferType, IMutexManager, IBufferValidator, IBufferAccessor,
IBatchProcessor, IDebugUtils, IConfigHandler, ISafeBufferAccess
)

__all__ = [
# abstract contract for each protocol config model
# Core buffer access (refactored)
'SafeBufferAccess',

# Legacy type definitions (maintained for compatibility)
'PluginRuntimeArgs',
'PluginStructureValidator',
'safe_extract_runtime_args_from_capsule',

# Configuration models
'PluginConfigContract',
# top level config instance
'PluginConfigError',
# concrete protocol config models
'PluginConfigError',
'ModbusIoPointConfig',
'ModbusMasterConfig',

# Component interfaces (for extension)
'IBufferType', 'IMutexManager', 'IBufferValidator', 'IBufferAccessor',
'IBatchProcessor', 'IDebugUtils', 'IConfigHandler', 'ISafeBufferAccess',

# Future extensions
# 'EthercatConfig',
# 'EthercatIoPointConfig',
]
Loading