This MVP release provides a complete full-stack solution for managing action mappings in Geutebruck's GeViScope and GeViSoft video surveillance systems. ## Features ### Flutter Web Application (Port 8081) - Modern, responsive UI for managing action mappings - Action picker dialog with full parameter configuration - Support for both GSC (GeViScope) and G-Core server actions - Consistent UI for input and output actions with edit/delete capabilities - Real-time action mapping creation, editing, and deletion - Server categorization (GSC: prefix for GeViScope, G-Core: prefix for G-Core servers) ### FastAPI REST Backend (Port 8000) - RESTful API for action mapping CRUD operations - Action template service with comprehensive action catalog (247 actions) - Server management (G-Core and GeViScope servers) - Configuration tree reading and writing - JWT authentication with role-based access control - PostgreSQL database integration ### C# SDK Bridge (gRPC, Port 50051) - Native integration with GeViSoft SDK (GeViProcAPINET_4_0.dll) - Action mapping creation with correct binary format - Support for GSC and G-Core action types - Proper Camera parameter inclusion in action strings (fixes CrossSwitch bug) - Action ID lookup table with server-specific action IDs - Configuration reading/writing via SetupClient ## Bug Fixes - **CrossSwitch Bug**: GSC and G-Core actions now correctly display camera/PTZ head parameters in GeViSet - Action strings now include Camera parameter: `@ PanLeft (Comment: "", Camera: 101028)` - Proper filter flags and VideoInput=0 for action mappings - Correct action ID assignment (4198 for GSC, 9294 for G-Core PanLeft) ## Technical Stack - **Frontend**: Flutter Web, Dart, Dio HTTP client - **Backend**: Python FastAPI, PostgreSQL, Redis - **SDK Bridge**: C# .NET 8.0, gRPC, GeViSoft SDK - **Authentication**: JWT tokens - **Configuration**: GeViSoft .set files (binary format) ## Credentials - GeViSoft/GeViScope: username=sysadmin, password=masterkey - Default admin: username=admin, password=admin123 ## Deployment All services run on localhost: - Flutter Web: http://localhost:8081 - FastAPI: http://localhost:8000 - SDK Bridge gRPC: localhost:50051 - GeViServer: localhost (default port) Generated with Claude Code (https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
258 lines
7.1 KiB
Markdown
258 lines
7.1 KiB
Markdown
# Action Mapping Binary Structure - Complete Guide
|
|
|
|
## Summary
|
|
|
|
Based on analysis of TestMKS_original.set vs TestMKS_added_mapping.set, this document explains how action mappings are stored and how to programmatically add thousands of them.
|
|
|
|
## Binary Structure
|
|
|
|
### Overall Format
|
|
|
|
```
|
|
MARKER SECTION:
|
|
├─ 'ules' (4 bytes) - Action mapping marker
|
|
├─ Length (4 bytes, little-endian) - Length of marker name/data section
|
|
└─ Marker Name/Data Section (variable length)
|
|
├─ Metadata bytes
|
|
├─ Properties (optional, multiple)
|
|
│ └─ Each property: 01 <len> <.name> <value_marker> <value>
|
|
└─ Additional metadata
|
|
|
|
ACTION SECTION (follows marker section):
|
|
├─ Action Entry 1
|
|
│ ├─ Entry number (01 for first, 02 for second, etc.)
|
|
│ ├─ Metadata: 05 00 00 00
|
|
│ ├─ Action data: 07 01 40 <len_u16_LE> <action_string>
|
|
│ └─ Additional metadata (varies)
|
|
├─ Action Entry 2
|
|
│ └─ (same structure)
|
|
└─ ...
|
|
|
|
NEXT MARKER:
|
|
└─ 05 'Rules' or next 'ules' marker
|
|
```
|
|
|
|
### Example 1: Simple Mapping (No Parameters)
|
|
|
|
**Hex Dump (offset 0x41433):**
|
|
```
|
|
75 6C 65 73 - 'ules' marker
|
|
02 00 00 00 - Length: 2 bytes
|
|
00 01 - Marker data (2 bytes)
|
|
|
|
31 05 00 00 00 - Action entry #1 metadata
|
|
07 01 40 - Action marker
|
|
0B 00 - Length: 11 bytes (little-endian)
|
|
47 53 43 20 50 61 6E 4C 65 66 74 - "GSC PanLeft"
|
|
...
|
|
```
|
|
|
|
### Example 2: Mapping with Parameters
|
|
|
|
**Hex Dump (offset 0x3D90D):**
|
|
```
|
|
75 6C 65 73 - 'ules' marker
|
|
40 00 00 00 - Length: 64 bytes
|
|
00 01 - Start of marker data
|
|
|
|
# Properties within marker data:
|
|
01 - Property marker
|
|
0B - Name length: 11
|
|
2E 53 77 69 74 63 68 4D 6F 64 65 - ".SwitchMode"
|
|
00 - Value type: null
|
|
|
|
01 - Property marker
|
|
0C - Name length: 12
|
|
2E 56 69 64 65 6F 4F 75 74 70 75 74 - ".VideoOutput"
|
|
00 - Value type: null
|
|
|
|
# Then actions follow...
|
|
```
|
|
|
|
## Property Value Types
|
|
|
|
| Marker | Type | Structure |
|
|
|--------|------|-----------|
|
|
| `0x01` | Boolean | `01 <value>` where value is 00 or 01 |
|
|
| `0x04` | Integer | `04 <int32_LE>` (4 bytes, little-endian) |
|
|
| `0x00` | Null | Just `00` |
|
|
| `0x07` | String | `07 <len> <string_bytes>` |
|
|
|
|
## Action Entry Format
|
|
|
|
Each action entry consists of:
|
|
|
|
```
|
|
<entry_number> - 01, 02, 03, etc. (sequential)
|
|
05 00 00 00 - Metadata (always this sequence)
|
|
07 01 40 - Action marker (always this sequence)
|
|
<length> - 2 bytes, little-endian (length of action string)
|
|
<action_name> - UTF-8 encoded action name
|
|
04 02 40 21 00 00 00 00 - Additional metadata
|
|
04 02 40 40 <4 bytes> - More metadata (varies)
|
|
```
|
|
|
|
## Key Findings
|
|
|
|
### 1. File Reorganization
|
|
|
|
When you add a mapping using GeViSoft GUI:
|
|
- The entire .set file is reorganized
|
|
- All offsets change
|
|
- Mappings may be reordered
|
|
- Net result: +1 mapping but many bytes change
|
|
|
|
This means you **cannot** simply append to the end of the file!
|
|
|
|
### 2. Insertion Strategy
|
|
|
|
To programmatically add mappings:
|
|
|
|
**Option A: Parse → Modify → Rebuild**
|
|
1. Parse the entire .set file
|
|
2. Add new mapping to internal structure
|
|
3. Regenerate the entire file
|
|
4. Write back to disk
|
|
|
|
**Option B: Use GeViSoft API** (if available)
|
|
1. Use SetupClient API to modify configuration
|
|
2. Let GeViSoft handle file format
|
|
|
|
**Option C: Template-Based** (recommended for bulk)
|
|
1. Create template mappings in GUI
|
|
2. Export configuration
|
|
3. Use find/replace to duplicate with new IDs
|
|
4. Import back
|
|
|
|
### 3. Complexity Factors
|
|
|
|
- Offsets must be recalculated
|
|
- File structure is tightly packed
|
|
- No obvious "free space" to insert data
|
|
- Dependencies between sections unknown
|
|
- Checksum or validation may exist
|
|
|
|
## Programmatic Approach
|
|
|
|
### Step 1: Create Mapping Binary Data
|
|
|
|
```python
|
|
def create_action_mapping(actions, parameters=None):
|
|
"""
|
|
Generate binary data for an action mapping
|
|
|
|
Args:
|
|
actions: List of action strings
|
|
parameters: Dict of parameter_name -> value (optional)
|
|
|
|
Returns:
|
|
bytes: Complete mapping binary data
|
|
"""
|
|
import struct
|
|
|
|
# Build marker name/data section
|
|
marker_data = bytearray()
|
|
marker_data.extend(b'\x00\x01') # Base metadata
|
|
|
|
# Add parameters if any
|
|
if parameters:
|
|
for name, value in parameters.items():
|
|
# Property marker
|
|
marker_data.append(0x01)
|
|
# Name with leading dot
|
|
name_with_dot = f".{name}"
|
|
name_bytes = name_with_dot.encode('utf-8')
|
|
marker_data.append(len(name_bytes))
|
|
marker_data.extend(name_bytes)
|
|
|
|
# Value
|
|
if value is None:
|
|
marker_data.append(0x00)
|
|
elif isinstance(value, bool):
|
|
marker_data.append(0x01)
|
|
marker_data.append(0x01 if value else 0x00)
|
|
elif isinstance(value, int):
|
|
marker_data.append(0x04)
|
|
marker_data.extend(struct.pack('<i', value))
|
|
|
|
# Build complete marker section
|
|
result = bytearray()
|
|
result.extend(b'ules') # Marker
|
|
result.extend(struct.pack('<I', len(marker_data))) # Length
|
|
result.extend(marker_data) # Data
|
|
|
|
# Add actions
|
|
for i, action in enumerate(actions, 1):
|
|
# Entry number
|
|
result.append(i)
|
|
# Metadata
|
|
result.extend(b'\x05\x00\x00\x00')
|
|
# Action marker
|
|
result.extend(b'\x07\x01\x40')
|
|
# Action length and string
|
|
action_bytes = action.encode('utf-8')
|
|
result.extend(struct.pack('<H', len(action_bytes)))
|
|
result.extend(action_bytes)
|
|
# Additional metadata (simplified)
|
|
result.extend(b'\x04\x02\x40\x21\x00\x00\x00\x00')
|
|
result.extend(b'\x04\x02\x40\x40\x00\x10\x00\x00')
|
|
|
|
return bytes(result)
|
|
```
|
|
|
|
### Step 2: Insert into Configuration
|
|
|
|
The recommended approach is to:
|
|
|
|
1. **Read entire configuration** using existing parser
|
|
2. **Add new mapping** to internal structure
|
|
3. **Regenerate file** using configuration writer
|
|
|
|
## Practical Recommendations
|
|
|
|
### For Adding Thousands of Mappings
|
|
|
|
**Best Approach:**
|
|
|
|
1. **Use C# SDK + Configuration API**
|
|
```csharp
|
|
// Pseudo-code
|
|
var config = parser.Parse(file);
|
|
for (int i = 0; i < 1000; i++) {
|
|
var mapping = new ActionMapping {
|
|
Actions = new[] { $"Action_{i}" },
|
|
Parameters = new Dictionary<string, object>()
|
|
};
|
|
config.AddMapping(mapping);
|
|
}
|
|
writer.Write(config, outputFile);
|
|
```
|
|
|
|
2. **Batch Process via GUI Templates**
|
|
- Create 1 mapping template in GUI
|
|
- Export configuration as JSON/XML (if supported)
|
|
- Programmatically duplicate + modify
|
|
- Import back
|
|
|
|
3. **Direct Binary Manipulation** (risky!)
|
|
- Parse existing file completely
|
|
- Understand all section dependencies
|
|
- Insert mappings
|
|
- Rebuild file with correct offsets
|
|
|
|
## Next Steps
|
|
|
|
For your use case (adding thousands of mappings), I recommend:
|
|
|
|
1. **Extend C# Parser** to support WRITING (currently read-only)
|
|
2. **Create AddActionMapping() method** in ConfigurationService
|
|
3. **Batch add** via gRPC/REST API
|
|
4. **Write back** to .set file
|
|
|
|
Would you like me to:
|
|
- [ ] Create C# writer for .set files
|
|
- [ ] Build Python script for bulk mapping creation
|
|
- [ ] Extend the gRPC API to support CREATE operations
|
|
- [ ] Create a bulk import tool (CSV → action mappings)
|
|
|