Compare commits
10 Commits
d6c4b24149
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
| 47c0236129 | |||
| 56aa4a2721 | |||
| 731a00a644 | |||
| b85ff21648 | |||
| b545f9e326 | |||
| 5853eca6d5 | |||
| 6a747cb127 | |||
| da4fbd09f0 | |||
| b3eaafbbe5 | |||
| 6dda384428 |
1
.gitignore
vendored
1
.gitignore
vendored
@ -174,3 +174,4 @@ cython_debug/
|
|||||||
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
||||||
#.idea/
|
#.idea/
|
||||||
|
|
||||||
|
dummy_sender/dummy_sender
|
||||||
|
|||||||
17
README.md
17
README.md
@ -4,7 +4,7 @@
|
|||||||
- Receive data from [reHDD](https://git.mosad.xyz/localhorst/reHDD) via IPC message queue.
|
- Receive data from [reHDD](https://git.mosad.xyz/localhorst/reHDD) via IPC message queue.
|
||||||
|
|
||||||
## Example Label
|
## Example Label
|
||||||

|

|
||||||
|
|
||||||
## Install ##
|
## Install ##
|
||||||
|
|
||||||
@ -37,5 +37,20 @@ systemctl enable --now /lib/systemd/system/reHDDPrinter.service
|
|||||||
|
|
||||||
see https://github.com/pklaus/brother_ql for details for printer access
|
see https://github.com/pklaus/brother_ql for details for printer access
|
||||||
|
|
||||||
|
## Test IPC msg queue
|
||||||
|
### Dummy Sender
|
||||||
|
```
|
||||||
|
cd dummy_sender
|
||||||
|
clear && g++ -Wall main.cpp -o dummy_sender
|
||||||
|
clear && ./dummy_sender
|
||||||
|
```
|
||||||
|
|
||||||
|
### Dummy Receiver
|
||||||
|
```
|
||||||
|
clear && python ./dummy_receiver.py
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clear IPC mgs queue
|
||||||
|
```
|
||||||
|
clear && bash ./cleanup_queues.py
|
||||||
|
```
|
||||||
16
cleanup_queue.sh
Normal file
16
cleanup_queue.sh
Normal file
@ -0,0 +1,16 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
# Cleanup script to remove the IPC message queue
|
||||||
|
|
||||||
|
MSG_QUEUE_KEY="0x1b11193c0"
|
||||||
|
|
||||||
|
echo "Removing message queue with key: $MSG_QUEUE_KEY"
|
||||||
|
ipcrm -Q $MSG_QUEUE_KEY 2>/dev/null
|
||||||
|
|
||||||
|
if [ $? -eq 0 ]; then
|
||||||
|
echo "Message queue removed successfully"
|
||||||
|
else
|
||||||
|
echo "No message queue found or already removed"
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "Current message queues:"
|
||||||
|
ipcs -q
|
||||||
@ -1,53 +1,188 @@
|
|||||||
import sysv_ipc #pip install sysv-ipc
|
#!/usr/bin/env python3
|
||||||
import pycstruct #pip install pycstruct
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
"""Author: Hendrik Schutter, localhorst@mosad.xyz
|
||||||
|
Date of creation: 2025/12/05
|
||||||
|
Date of last modification: 2025/12/05
|
||||||
|
"""
|
||||||
|
|
||||||
|
import ctypes
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
# Constants
|
||||||
|
STR_BUFFER_SIZE = 64
|
||||||
|
MSG_QUEUE_KEY = 0x1B11193C0
|
||||||
|
IPC_CREAT = 0o1000
|
||||||
|
|
||||||
|
terminate = False
|
||||||
|
|
||||||
|
class TDriveData(ctypes.Structure):
|
||||||
|
_fields_ = [
|
||||||
|
("caDriveIndex", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveHours", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveCycles", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveErrors", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveShredTimestamp", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveShredDuration", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveCapacity", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveState", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveConnectionType", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveModelFamily", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveModelName", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveSerialnumber", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveReHddVersion", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
]
|
||||||
|
|
||||||
|
|
||||||
str_buffer_size = 64
|
class TMsgQueueData(ctypes.Structure):
|
||||||
msg_queue_key = 0x1B11193C0
|
_fields_ = [
|
||||||
|
("msg_queue_type", ctypes.c_long),
|
||||||
|
("driveData", TDriveData),
|
||||||
|
]
|
||||||
|
|
||||||
try:
|
|
||||||
mq = sysv_ipc.MessageQueue(msg_queue_key, sysv_ipc.IPC_CREAT)
|
|
||||||
|
|
||||||
|
# IPC bindings - enable errno support
|
||||||
|
libc = ctypes.CDLL("libc.so.6", use_errno=True)
|
||||||
|
msgget = libc.msgget
|
||||||
|
msgrcv = libc.msgrcv
|
||||||
|
|
||||||
|
msgget.argtypes = [ctypes.c_int, ctypes.c_int]
|
||||||
|
msgget.restype = ctypes.c_int
|
||||||
|
|
||||||
|
msgrcv.argtypes = [
|
||||||
|
ctypes.c_int,
|
||||||
|
ctypes.POINTER(TMsgQueueData),
|
||||||
|
ctypes.c_size_t,
|
||||||
|
ctypes.c_long,
|
||||||
|
ctypes.c_int,
|
||||||
|
]
|
||||||
|
msgrcv.restype = ctypes.c_ssize_t
|
||||||
|
|
||||||
|
|
||||||
|
def create_drive_objects(drive_info):
|
||||||
|
"""Convert dictionary to layouter-compatible DriveData and ReHddInfo objects"""
|
||||||
|
drive = layouter.DriveData(
|
||||||
|
drive_index=int(drive_info["driveIndex"]),
|
||||||
|
drive_state=drive_info["driveState"],
|
||||||
|
modelfamily=drive_info["driveModelFamily"],
|
||||||
|
modelname=drive_info["driveModelName"],
|
||||||
|
capacity=int(drive_info["driveCapacity"]),
|
||||||
|
serialnumber=drive_info["driveSerialnumber"],
|
||||||
|
power_on_hours=int(drive_info["driveHours"]),
|
||||||
|
power_cycle=int(drive_info["driveCycles"]),
|
||||||
|
smart_error_count=int(drive_info["driveErrors"]),
|
||||||
|
shred_timestamp=int(drive_info["driveShredTimestamp"]),
|
||||||
|
shred_duration=int(drive_info["driveShredDuration"]),
|
||||||
|
connection_type=drive_info["driveConnectionType"],
|
||||||
|
)
|
||||||
|
|
||||||
|
rehdd_info = layouter.ReHddInfo(
|
||||||
|
link="https://git.mosad.xyz/localhorst/reHDD",
|
||||||
|
version=drive_info["driveReHddVersion"],
|
||||||
|
)
|
||||||
|
|
||||||
|
return drive, rehdd_info
|
||||||
|
|
||||||
|
|
||||||
|
def worker(queue_id, test_mode=False):
|
||||||
|
try:
|
||||||
|
while not terminate:
|
||||||
|
time.sleep(3)
|
||||||
|
if test_mode:
|
||||||
|
drive_info = {
|
||||||
|
"driveIndex": "42",
|
||||||
|
"driveHours": 44,
|
||||||
|
"driveCycles": 45,
|
||||||
|
"driveErrors": 43,
|
||||||
|
"driveShredTimestamp": int(time.time()),
|
||||||
|
"driveShredDuration": 0,
|
||||||
|
"driveCapacity": 42,
|
||||||
|
"driveState": "shredded",
|
||||||
|
"driveConnectionType": "sata",
|
||||||
|
"driveModelFamily": "modelFamily",
|
||||||
|
"driveModelName": "modelName",
|
||||||
|
"driveSerialnumber": "serial",
|
||||||
|
"driveReHddVersion": "V1.1.2",
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
msg = TMsgQueueData()
|
||||||
|
print("Waiting for message from queue...")
|
||||||
|
|
||||||
|
# Calculate message size - must match C++ side: sizeof(t_msgQueueData) - sizeof(long)
|
||||||
|
# This is the size of the data portion (excluding msg_queue_type)
|
||||||
|
msg_size = ctypes.sizeof(TMsgQueueData) - ctypes.sizeof(ctypes.c_long)
|
||||||
|
|
||||||
|
print(f"Message size to receive: {msg_size} bytes")
|
||||||
|
|
||||||
|
result = msgrcv(
|
||||||
|
queue_id,
|
||||||
|
ctypes.byref(msg),
|
||||||
|
msg_size,
|
||||||
|
0, # msg type (0 = get first message)
|
||||||
|
0, # flags (0 = blocking)
|
||||||
|
)
|
||||||
|
|
||||||
|
if result == -1:
|
||||||
|
err = ctypes.get_errno()
|
||||||
|
print(
|
||||||
|
f"Error reading from message queue: {os.strerror(err)} (errno: {err})"
|
||||||
|
)
|
||||||
|
break
|
||||||
|
|
||||||
|
print(f"Received {result} bytes from queue")
|
||||||
|
|
||||||
|
d = msg.driveData
|
||||||
|
drive_info = {
|
||||||
|
"driveIndex": d.caDriveIndex.decode().strip("\x00"),
|
||||||
|
"driveHours": int(d.caDriveHours.decode().strip("\x00")),
|
||||||
|
"driveCycles": int(d.caDriveCycles.decode().strip("\x00")),
|
||||||
|
"driveErrors": int(d.caDriveErrors.decode().strip("\x00")),
|
||||||
|
"driveShredTimestamp": int(
|
||||||
|
d.caDriveShredTimestamp.decode().strip("\x00")
|
||||||
|
),
|
||||||
|
"driveShredDuration": int(
|
||||||
|
d.caDriveShredDuration.decode().strip("\x00")
|
||||||
|
),
|
||||||
|
"driveCapacity": int(d.caDriveCapacity.decode().strip("\x00")),
|
||||||
|
"driveState": d.caDriveState.decode().strip("\x00"),
|
||||||
|
"driveConnectionType": d.caDriveConnectionType.decode().strip("\x00"),
|
||||||
|
"driveModelFamily": d.caDriveModelFamily.decode().strip("\x00"),
|
||||||
|
"driveModelName": d.caDriveModelName.decode().strip("\x00"),
|
||||||
|
"driveSerialnumber": d.caDriveSerialnumber.decode().strip("\x00"),
|
||||||
|
"driveReHddVersion": d.caDriveReHddVersion.decode().strip("\x00"),
|
||||||
|
}
|
||||||
|
|
||||||
|
print(f"Received Drive Data: {drive_info}")
|
||||||
|
except Exception as e:
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
print(f"Worker encountered an error: {e}")
|
||||||
|
traceback.print_exc()
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
while True:
|
while True:
|
||||||
message, mtype = mq.receive()
|
try:
|
||||||
print("")
|
# Create or connect to the message queue with IPC_CREAT flag
|
||||||
#print("*** New message received ***")
|
# This matches the C++ sender's flags (IPC_CREAT | 0666)
|
||||||
# print(f"Raw message: {message}")
|
queue_id = msgget(MSG_QUEUE_KEY, IPC_CREAT | 0o666)
|
||||||
|
if queue_id == -1:
|
||||||
|
err = ctypes.get_errno()
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Failed to create/connect to the message queue: {os.strerror(err)}"
|
||||||
|
)
|
||||||
|
|
||||||
#uint8_t u8DriveIndex;
|
print(f"Successfully connected to message queue (ID: {queue_id})")
|
||||||
#uint32_t u32DriveHours;
|
worker(queue_id)
|
||||||
#uint32_t u32DriveCycles;
|
except Exception as e:
|
||||||
#uint32_t u32DriveError;
|
import traceback
|
||||||
#uint64_t u64DriveShredTimestamp;
|
|
||||||
#uint64_t u64DriveShredDuration;
|
print(f"Main process encountered an error: {e}")
|
||||||
#uint64_t u64DriveCapacity;
|
traceback.print_exc()
|
||||||
#char caDriveState[STR_BUFFER_SIZE];
|
time.sleep(30)
|
||||||
#char caDriveModelFamiliy[STR_BUFFER_SIZE];
|
|
||||||
#char caDriveModelName[STR_BUFFER_SIZE];
|
|
||||||
#char caDriveSerialnumber[STR_BUFFER_SIZE];
|
|
||||||
|
|
||||||
|
|
||||||
driveData = pycstruct.StructDef()
|
|
||||||
driveData.add('utf-8', 'driveIndex', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveHours', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveCycles', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveErrors', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveShredTimestamp', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveShredDuration', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveCapacity', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveState', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveModelFamiliy', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveModelModel', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveSerialnumber', length=str_buffer_size)
|
|
||||||
driveData.add('utf-8', 'driveReHddVersion', length=str_buffer_size)
|
|
||||||
|
|
||||||
# Dictionary representation
|
|
||||||
result = driveData.deserialize(message)
|
|
||||||
print('Dictionary object:')
|
|
||||||
print(str(result))
|
|
||||||
|
|
||||||
|
|
||||||
except sysv_ipc.ExistentialError:
|
|
||||||
print("ERROR: message queue creation failed")
|
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
||||||
|
|||||||
61
dummy_sender/main.cpp
Normal file
61
dummy_sender/main.cpp
Normal file
@ -0,0 +1,61 @@
|
|||||||
|
/**
|
||||||
|
* @file main.cpp
|
||||||
|
* @brief Send drive data to printer service using ipc msg queue
|
||||||
|
* @author Hendrik Schutter
|
||||||
|
* @date 06.12.2025
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "main.h"
|
||||||
|
|
||||||
|
#define REHDD_VERSION "V99.99.99"
|
||||||
|
|
||||||
|
/**
|
||||||
|
* \brief app entry point
|
||||||
|
* \param void
|
||||||
|
* \return Status-Code
|
||||||
|
*/
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
int msqid;
|
||||||
|
std::cout << "Dummy sender for IPC queue" << std::endl;
|
||||||
|
|
||||||
|
if (-1 == (msqid = msgget((key_t)IPC_MSG_QUEUE_KEY, IPC_CREAT | 0666)))
|
||||||
|
{
|
||||||
|
std::cout << "Printer: Create msg queue failed! Error: " << strerror(errno) << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Printer: Created/connected to msg queue (ID: " << msqid << ")" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
t_msgQueueData msgQueueData;
|
||||||
|
msgQueueData.msg_queue_type = 1;
|
||||||
|
|
||||||
|
sprintf(msgQueueData.driveData.caDriveIndex, "%i", 0);
|
||||||
|
sprintf(msgQueueData.driveData.caDriveState, "shredded");
|
||||||
|
strcpy(msgQueueData.driveData.caDriveModelFamily, "Toshiba 2.5 HDD MK..65GSSX");
|
||||||
|
strcpy(msgQueueData.driveData.caDriveModelName, "TOSHIBA MK3265GSDX");
|
||||||
|
sprintf(msgQueueData.driveData.caDriveCapacity, "%li", 343597383000LU);
|
||||||
|
strcpy(msgQueueData.driveData.caDriveSerialnumber, "YG6742U56UDRL123456789ABCDEFGJKL");
|
||||||
|
sprintf(msgQueueData.driveData.caDriveHours, "%i", 7074);
|
||||||
|
sprintf(msgQueueData.driveData.caDriveCycles, "%i", 4792);
|
||||||
|
sprintf(msgQueueData.driveData.caDriveErrors, "%i", 1);
|
||||||
|
sprintf(msgQueueData.driveData.caDriveShredTimestamp, "%li", 71718LU);
|
||||||
|
sprintf(msgQueueData.driveData.caDriveShredDuration, "%li", 81718LU);
|
||||||
|
strcpy(msgQueueData.driveData.caDriveConnectionType, "sata");
|
||||||
|
sprintf(msgQueueData.driveData.caDriveReHddVersion, REHDD_VERSION);
|
||||||
|
|
||||||
|
std::cout << "Sending message to queue..." << std::endl;
|
||||||
|
if (-1 == msgsnd(msqid, &msgQueueData, sizeof(t_msgQueueData) - sizeof(long), 0))
|
||||||
|
{
|
||||||
|
std::cout << "Printer: Send msg queue failed! Error: " << strerror(errno) << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Printer: print triggered successfully" << std::endl;
|
||||||
|
}
|
||||||
|
|
||||||
|
return EXIT_SUCCESS;
|
||||||
|
}
|
||||||
45
dummy_sender/main.h
Normal file
45
dummy_sender/main.h
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/**
|
||||||
|
* @file main.h
|
||||||
|
* @brief Send drive data to printer service using ipc msg queue
|
||||||
|
* @author Hendrik Schutter
|
||||||
|
* @date 06.12.2025
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef PRINTER_H_
|
||||||
|
#define PRINTER_H_
|
||||||
|
|
||||||
|
#include <sys/ipc.h>
|
||||||
|
#include <sys/msg.h>
|
||||||
|
#include <cstring>
|
||||||
|
#include <sstream>
|
||||||
|
#include <iostream>
|
||||||
|
#include <cerrno>
|
||||||
|
|
||||||
|
#define STR_BUFFER_SIZE 64U
|
||||||
|
#define IPC_MSG_QUEUE_KEY 0x1B11193C0
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
char caDriveIndex[STR_BUFFER_SIZE];
|
||||||
|
char caDriveHours[STR_BUFFER_SIZE];
|
||||||
|
char caDriveCycles[STR_BUFFER_SIZE];
|
||||||
|
char caDriveErrors[STR_BUFFER_SIZE];
|
||||||
|
char caDriveShredTimestamp[STR_BUFFER_SIZE];
|
||||||
|
char caDriveShredDuration[STR_BUFFER_SIZE];
|
||||||
|
char caDriveCapacity[STR_BUFFER_SIZE];
|
||||||
|
char caDriveState[STR_BUFFER_SIZE];
|
||||||
|
char caDriveConnectionType[STR_BUFFER_SIZE];
|
||||||
|
char caDriveModelFamily[STR_BUFFER_SIZE];
|
||||||
|
char caDriveModelName[STR_BUFFER_SIZE];
|
||||||
|
char caDriveSerialnumber[STR_BUFFER_SIZE];
|
||||||
|
char caDriveReHddVersion[STR_BUFFER_SIZE];
|
||||||
|
|
||||||
|
} t_driveData;
|
||||||
|
|
||||||
|
typedef struct
|
||||||
|
{
|
||||||
|
long msg_queue_type;
|
||||||
|
t_driveData driveData;
|
||||||
|
} t_msgQueueData;
|
||||||
|
|
||||||
|
#endif // PRINTER_H_
|
||||||
59
layouter.py
59
layouter.py
@ -34,6 +34,7 @@ logging.basicConfig(
|
|||||||
class DriveData:
|
class DriveData:
|
||||||
drive_index: int
|
drive_index: int
|
||||||
drive_state: str
|
drive_state: str
|
||||||
|
drive_connection_type: str
|
||||||
modelfamily: str
|
modelfamily: str
|
||||||
modelname: str
|
modelname: str
|
||||||
capacity: int
|
capacity: int
|
||||||
@ -48,6 +49,7 @@ class DriveData:
|
|||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class DriveDataJson:
|
class DriveDataJson:
|
||||||
state: str
|
state: str
|
||||||
|
contype: str
|
||||||
fam: str
|
fam: str
|
||||||
name: str
|
name: str
|
||||||
cap: int
|
cap: int
|
||||||
@ -61,6 +63,7 @@ class DriveDataJson:
|
|||||||
|
|
||||||
@dataclasses.dataclass
|
@dataclasses.dataclass
|
||||||
class DriveDataPrintable:
|
class DriveDataPrintable:
|
||||||
|
connectiontype: str
|
||||||
modelfamily: str
|
modelfamily: str
|
||||||
modelname: str
|
modelname: str
|
||||||
capacity: str
|
capacity: str
|
||||||
@ -132,6 +135,7 @@ def cut_string(max_length, data, direction="end"):
|
|||||||
|
|
||||||
def format_to_printable(drive):
|
def format_to_printable(drive):
|
||||||
return DriveDataPrintable(
|
return DriveDataPrintable(
|
||||||
|
drive.drive_connection_type,
|
||||||
cut_string(20, re.sub(r"[^a-zA-Z0-9. ]", "", drive.modelfamily), "end"),
|
cut_string(20, re.sub(r"[^a-zA-Z0-9. ]", "", drive.modelfamily), "end"),
|
||||||
cut_string(20, re.sub(r"[^a-zA-Z0-9. ]", "", drive.modelname), "end"),
|
cut_string(20, re.sub(r"[^a-zA-Z0-9. ]", "", drive.modelname), "end"),
|
||||||
cut_string(20, human_readable_capacity(drive.capacity), "end"),
|
cut_string(20, human_readable_capacity(drive.capacity), "end"),
|
||||||
@ -149,17 +153,19 @@ def format_to_printable(drive):
|
|||||||
cut_string(30, str(datetime.timedelta(seconds=drive.shred_duration)), "end"),
|
cut_string(30, str(datetime.timedelta(seconds=drive.shred_duration)), "end"),
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
def draw_text(drawable, printable_data, font_regular, font_bold, font_bold_bigger):
|
def draw_text(drawable, printable_data, font_regular, font_bold, font_bold_bigger):
|
||||||
"""Draws formatted text with Cycles and Errors on one row."""
|
"""Draws formatted text with Cycles and Errors on one row."""
|
||||||
|
y_start = 4
|
||||||
line_height = 26
|
line_height = 26
|
||||||
label_x = TEXT_X_OFFSET
|
label_x = TEXT_X_OFFSET
|
||||||
value_offset = 115
|
value_offset = 115
|
||||||
right_field_spacing = 200 # Horizontal gap between Cycles and Errors
|
right_field_spacing = 200 # Horizontal gap between Cycles and Errors
|
||||||
x_capacity = 520
|
x_capacity = 520
|
||||||
y_capacity = 142
|
y_capacity = 142
|
||||||
y_start = 4
|
x_connection_type = 600
|
||||||
|
y_connection_type = y_start
|
||||||
|
y_spacing_connection_type = 25
|
||||||
|
|
||||||
|
|
||||||
# Serial Number
|
# Serial Number
|
||||||
drawable.text((label_x, y_start), "Serial:", fill=0, font=font_bold)
|
drawable.text((label_x, y_start), "Serial:", fill=0, font=font_bold)
|
||||||
@ -246,6 +252,49 @@ def draw_text(drawable, printable_data, font_regular, font_bold, font_bold_bigge
|
|||||||
font=font_bold_bigger,
|
font=font_bold_bigger,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
if (printable_data.connectiontype == "sata"):
|
||||||
|
drawable.text(
|
||||||
|
(x_connection_type, y_connection_type),
|
||||||
|
"⬤ SATA",
|
||||||
|
fill=0,
|
||||||
|
font=font_regular,
|
||||||
|
)
|
||||||
|
|
||||||
|
drawable.text(
|
||||||
|
(x_connection_type, y_connection_type+y_spacing_connection_type),
|
||||||
|
"◯ NVME",
|
||||||
|
fill=0,
|
||||||
|
font=font_regular,
|
||||||
|
)
|
||||||
|
elif (printable_data.connectiontype == "nvme"):
|
||||||
|
drawable.text(
|
||||||
|
(x_connection_type, y_connection_type),
|
||||||
|
"◯ SATA",
|
||||||
|
fill=0,
|
||||||
|
font=font_regular,
|
||||||
|
)
|
||||||
|
|
||||||
|
drawable.text(
|
||||||
|
(x_connection_type, y_connection_type+y_spacing_connection_type),
|
||||||
|
"⬤ NVME",
|
||||||
|
fill=0,
|
||||||
|
font=font_regular,
|
||||||
|
)
|
||||||
|
else:
|
||||||
|
drawable.text(
|
||||||
|
(x_connection_type, y_connection_type),
|
||||||
|
"◯ SATA",
|
||||||
|
fill=0,
|
||||||
|
font=font_regular,
|
||||||
|
)
|
||||||
|
|
||||||
|
drawable.text(
|
||||||
|
(x_connection_type, y_connection_type+y_spacing_connection_type),
|
||||||
|
"◯ NVME",
|
||||||
|
fill=0,
|
||||||
|
font=font_regular,
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def draw_qr_code(image, data):
|
def draw_qr_code(image, data):
|
||||||
"""
|
"""
|
||||||
@ -270,7 +319,6 @@ def draw_qr_code(image, data):
|
|||||||
region = (5, 5, 5 + QR_CODE_SIZE, 5 + QR_CODE_SIZE)
|
region = (5, 5, 5 + QR_CODE_SIZE, 5 + QR_CODE_SIZE)
|
||||||
image.paste(qr_img, box=region)
|
image.paste(qr_img, box=region)
|
||||||
|
|
||||||
|
|
||||||
def draw_outline(drawable, margin, width, output_width, output_height):
|
def draw_outline(drawable, margin, width, output_width, output_height):
|
||||||
"""
|
"""
|
||||||
Draws a rectangular outline on the drawable canvas.
|
Draws a rectangular outline on the drawable canvas.
|
||||||
@ -299,13 +347,13 @@ def draw_outline(drawable, margin, width, output_width, output_height):
|
|||||||
for line in lines:
|
for line in lines:
|
||||||
drawable.line(line, fill=0, width=width)
|
drawable.line(line, fill=0, width=width)
|
||||||
|
|
||||||
|
|
||||||
def generate_image(drive, rehdd_info, output_file):
|
def generate_image(drive, rehdd_info, output_file):
|
||||||
"""Generates an image containing drive data and a QR code."""
|
"""Generates an image containing drive data and a QR code."""
|
||||||
try:
|
try:
|
||||||
|
|
||||||
drive_json = DriveDataJson(
|
drive_json = DriveDataJson(
|
||||||
state=drive.drive_state,
|
state=drive.drive_state,
|
||||||
|
contype=drive.drive_connection_type,
|
||||||
fam=drive.modelfamily,
|
fam=drive.modelfamily,
|
||||||
name=drive.modelname,
|
name=drive.modelname,
|
||||||
cap=drive.capacity,
|
cap=drive.capacity,
|
||||||
@ -346,6 +394,7 @@ def main():
|
|||||||
|
|
||||||
temp_drive = DriveData(
|
temp_drive = DriveData(
|
||||||
drive_index=0,
|
drive_index=0,
|
||||||
|
drive_connection_type="sata",
|
||||||
drive_state="shredded",
|
drive_state="shredded",
|
||||||
modelfamily='Toshiba 2.5" HDD MK..65GSSX',
|
modelfamily='Toshiba 2.5" HDD MK..65GSSX',
|
||||||
modelname="TOSHIBA MK3265GSDX",
|
modelname="TOSHIBA MK3265GSDX",
|
||||||
|
|||||||
BIN
output.png
BIN
output.png
Binary file not shown.
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 4.6 KiB |
@ -1,9 +1,9 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
""" Author: Hendrik Schutter, localhorst@mosad.xyz
|
"""Author: Hendrik Schutter, localhorst@mosad.xyz
|
||||||
Date of creation: 2022/11/23
|
Date of creation: 2022/11/23
|
||||||
Date of last modification: 2025/06/15
|
Date of last modification: 2025/06/15
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import ctypes
|
import ctypes
|
||||||
@ -43,6 +43,7 @@ class TDriveData(ctypes.Structure):
|
|||||||
("caDriveShredDuration", ctypes.c_char * STR_BUFFER_SIZE),
|
("caDriveShredDuration", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
("caDriveCapacity", ctypes.c_char * STR_BUFFER_SIZE),
|
("caDriveCapacity", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
("caDriveState", ctypes.c_char * STR_BUFFER_SIZE),
|
("caDriveState", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
|
("caDriveConnectionType", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
("caDriveModelFamily", ctypes.c_char * STR_BUFFER_SIZE),
|
("caDriveModelFamily", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
("caDriveModelName", ctypes.c_char * STR_BUFFER_SIZE),
|
("caDriveModelName", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
("caDriveSerialnumber", ctypes.c_char * STR_BUFFER_SIZE),
|
("caDriveSerialnumber", ctypes.c_char * STR_BUFFER_SIZE),
|
||||||
@ -106,6 +107,7 @@ def create_drive_objects(drive_info):
|
|||||||
smart_error_count=int(drive_info["driveErrors"]),
|
smart_error_count=int(drive_info["driveErrors"]),
|
||||||
shred_timestamp=int(drive_info["driveShredTimestamp"]),
|
shred_timestamp=int(drive_info["driveShredTimestamp"]),
|
||||||
shred_duration=int(drive_info["driveShredDuration"]),
|
shred_duration=int(drive_info["driveShredDuration"]),
|
||||||
|
drive_connection_type=drive_info["driveConnectionType"],
|
||||||
)
|
)
|
||||||
|
|
||||||
rehdd_info = layouter.ReHddInfo(
|
rehdd_info = layouter.ReHddInfo(
|
||||||
@ -119,6 +121,7 @@ def create_drive_objects(drive_info):
|
|||||||
def worker(queue_id, test_mode=False):
|
def worker(queue_id, test_mode=False):
|
||||||
try:
|
try:
|
||||||
while not terminate:
|
while not terminate:
|
||||||
|
time.sleep(3)
|
||||||
if test_mode:
|
if test_mode:
|
||||||
drive_info = {
|
drive_info = {
|
||||||
"driveIndex": "42",
|
"driveIndex": "42",
|
||||||
@ -129,9 +132,11 @@ def worker(queue_id, test_mode=False):
|
|||||||
"driveShredDuration": 0,
|
"driveShredDuration": 0,
|
||||||
"driveCapacity": 42,
|
"driveCapacity": 42,
|
||||||
"driveState": "shredded",
|
"driveState": "shredded",
|
||||||
|
"driveConnectionType": "sata",
|
||||||
"driveModelFamily": "modelFamily",
|
"driveModelFamily": "modelFamily",
|
||||||
"driveModelName": "modelName",
|
"driveModelName": "modelName",
|
||||||
"driveSerialnumber": "serial",
|
"driveSerialnumber": "serial",
|
||||||
|
"driveConnectionType": "sata",
|
||||||
"driveReHddVersion": "V1.1.2",
|
"driveReHddVersion": "V1.1.2",
|
||||||
}
|
}
|
||||||
else:
|
else:
|
||||||
@ -162,12 +167,17 @@ def worker(queue_id, test_mode=False):
|
|||||||
),
|
),
|
||||||
"driveCapacity": int(d.caDriveCapacity.decode().strip("\x00")),
|
"driveCapacity": int(d.caDriveCapacity.decode().strip("\x00")),
|
||||||
"driveState": d.caDriveState.decode().strip("\x00"),
|
"driveState": d.caDriveState.decode().strip("\x00"),
|
||||||
|
"driveConnectionType": d.caDriveConnectionType.decode().strip(
|
||||||
|
"\x00"
|
||||||
|
),
|
||||||
"driveModelFamily": d.caDriveModelFamily.decode().strip("\x00"),
|
"driveModelFamily": d.caDriveModelFamily.decode().strip("\x00"),
|
||||||
"driveModelName": d.caDriveModelName.decode().strip("\x00"),
|
"driveModelName": d.caDriveModelName.decode().strip("\x00"),
|
||||||
"driveSerialnumber": d.caDriveSerialnumber.decode().strip("\x00"),
|
"driveSerialnumber": d.caDriveSerialnumber.decode().strip("\x00"),
|
||||||
|
"driveConnectionType": d.caDriveConnectionType.decode().strip(
|
||||||
|
"\x00"
|
||||||
|
),
|
||||||
"driveReHddVersion": d.caDriveReHddVersion.decode().strip("\x00"),
|
"driveReHddVersion": d.caDriveReHddVersion.decode().strip("\x00"),
|
||||||
}
|
}
|
||||||
time.sleep(3)
|
|
||||||
|
|
||||||
print(f"Received Drive Data: {drive_info}")
|
print(f"Received Drive Data: {drive_info}")
|
||||||
|
|
||||||
@ -204,9 +214,16 @@ def main():
|
|||||||
return
|
return
|
||||||
while True:
|
while True:
|
||||||
try:
|
try:
|
||||||
queue_id = msgget(MSG_QUEUE_KEY, 0)
|
# Create or connect to the message queue with IPC_CREAT flag
|
||||||
|
# This matches the C++ sender's flags (IPC_CREAT | 0666)
|
||||||
|
queue_id = msgget(MSG_QUEUE_KEY, IPC_CREAT | 0o666)
|
||||||
if queue_id == -1:
|
if queue_id == -1:
|
||||||
raise RuntimeError("Failed to connect to the existing message queue.")
|
err = ctypes.get_errno()
|
||||||
|
raise RuntimeError(
|
||||||
|
f"Failed to create/connect to the message queue: {os.strerror(err)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Successfully connected to message queue (ID: {queue_id})")
|
||||||
worker(queue_id)
|
worker(queue_id)
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Main process encountered an error: {e}")
|
print(f"Main process encountered an error: {e}")
|
||||||
|
|||||||
Reference in New Issue
Block a user