Mercurial > public > ostc_companion
changeset 5:115cfa4a3239 default tip
Added icon upload function for OSTC 4/5
For the upload the same process as the one for the firmware update is used => CRC functionality has been copied from the ostc_pack SW
| author | Ideenmodellierer |
|---|---|
| date | Tue, 30 Dec 2025 21:41:02 +0100 |
| parents | e30f00f760d3 |
| children | |
| files | CmakeLists.txt HardwareOperations.h MainWindow.cpp OSTC3Operations.cpp OSTC4Operations.cpp OSTC4Operations.h about.txt crc_wrapper.cpp crc_wrapper.h crcmodel.c crcmodel.h ostc45_icon.cpp ostc45_icon.h |
| diffstat | 13 files changed, 811 insertions(+), 30 deletions(-) [+] |
line wrap: on
line diff
--- a/CmakeLists.txt Sun Nov 30 18:37:32 2025 +0100 +++ b/CmakeLists.txt Tue Dec 30 21:41:02 2025 +0100 @@ -1,8 +1,6 @@ cmake_minimum_required(VERSION 3.21) -project(OSTCCompanion VERSION 1.0 LANGUAGES CXX) - -project(OSTCCompanion LANGUAGES CXX) +project(OSTCCompanion VERSION 1.0 LANGUAGES CXX C) # ---------------------------------------- # C++ Standard @@ -79,6 +77,7 @@ OSTC4Operations.h OSTC_CR_Operations.h editlogdialog.h + crcmodel.h ) set(UIS @@ -102,6 +101,17 @@ set(app_icon_resource_windows "${CMAKE_CURRENT_SOURCE_DIR}/icon.rc") + +add_library(crcmodel STATIC + crcmodel.c +) +set_source_files_properties(crcmodel.c + PROPERTIES + LANGUAGE C +) +target_include_directories(crcmodel PUBLIC + ${CMAKE_CURRENT_SOURCE_DIR} +) # ---------------------------------------- # Executable erstellen # ---------------------------------------- @@ -112,6 +122,10 @@ ${RESOURCES} Utils/Export.h ${app_icon_resource_windows} + ostc45_icon.cpp + ostc45_icon.h + crc_wrapper.h + crc_wrapper.cpp ) target_include_directories(${PROJECT_NAME} PRIVATE @@ -124,7 +138,7 @@ # Qt Libraries verlinken # ---------------------------------------- target_link_libraries(${PROJECT_NAME} - PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network Qt6::Svg Qt6::Xml Qt6::SerialPort + PRIVATE Qt6::Core Qt6::Gui Qt6::Widgets Qt6::Network Qt6::Svg Qt6::Xml Qt6::SerialPort crcmodel ) # ----------------------------------------
--- a/HardwareOperations.h Sun Nov 30 18:37:32 2025 +0100 +++ b/HardwareOperations.h Tue Dec 30 21:41:02 2025 +0100 @@ -166,7 +166,7 @@ /// Each driver (instance of this class) is requested to tell *Companion* /// what are the supported command. /// - enum CompanionFeatures { + enum CompanionFeature { PARAMETERS = (1<<0), ///< Download/Edit/Upload various parameters. DATE = (1<<1), ///< Set date & time. NAME = (1<<2), ///< Set custom text displayed on main screen. @@ -179,7 +179,7 @@ VPM_MODEL = (1<<9), ///< Also propose VPM deco stops. SIGNAL_CHECK = (1<<10) ///< Echo signal quality for bluetooth computer }; - + Q_DECLARE_FLAGS(CompanionFeatures, CompanionFeature) /// \brief Tells what is supported for a given computer. virtual CompanionFeatures supported() const = 0;
--- a/MainWindow.cpp Sun Nov 30 18:37:32 2025 +0100 +++ b/MainWindow.cpp Tue Dec 30 21:41:02 2025 +0100 @@ -294,15 +294,15 @@ // ON when supported but NOT connected, OFF once connected. _ui->upgradeButton->setEnabled( ok - && (_op->supported() & HardwareOperations::FIRMWARE) + && (_op->supported() & HardwareOperations::CompanionFeatures(HardwareOperations::FIRMWARE)) && !_op->serial().isOpen()); // Only allow buttons when connected: ok &= _op->serial().isOpen(); - _ui->dateButton ->setEnabled( ok && (_op->supported() & HardwareOperations::DATE) ); - _ui->nameButton ->setEnabled( ok && (_op->supported() & HardwareOperations::NAME) ); - _ui->iconButton ->setEnabled( ok && (_op->supported() & HardwareOperations::ICON) ); - _ui->signalButton ->setEnabled( ok && (_op->supported() & HardwareOperations::SIGNAL_CHECK) ); + _ui->dateButton ->setEnabled(ok && _op->supported().testFlag(HardwareOperations::DATE)); + _ui->nameButton ->setEnabled(ok && _op->supported().testFlag(HardwareOperations::NAME)); + _ui->iconButton ->setEnabled(ok);// && _op->supported().testFlag(HardwareOperations::ICON)); + _ui->signalButton->setEnabled(ok && _op->supported().testFlag(HardwareOperations::SIGNAL_CHECK)); _ui->closeButton ->setEnabled( ok ); } @@ -411,13 +411,8 @@ QString fileName = QFileDialog::getOpenFileName(this, "Icon File...", QString(), - "Images (*.gif *.png *.tif *.tiff *.jpg *.jpeg *.ico *.svg);;" - "GIF Image (*.gif);;" - "PNG Image (*.png);;" - "TIFF Image (*.tif *.tiff);;" - "JPEG Image (*.jpg *.jpeg);;" - "Icon Image (*.ico);;" - "SVG Image (*.svg);;" + "Images (*.bmp);;" + "BMP Image (*.bmp);;" "Anything (*.*)"); if( ! fileName.isEmpty() ) _op->setIcons(fileName);
--- a/OSTC3Operations.cpp Sun Nov 30 18:37:32 2025 +0100 +++ b/OSTC3Operations.cpp Tue Dec 30 21:41:02 2025 +0100 @@ -497,9 +497,12 @@ // Also, the general acknowledge byte is changed to 0x4c 'L'. assert( _connectMode != SERVICE_MODE ); - _serial.open( Settings::port, emulatorName); - _serial.sleep(333); // Initial 1/3 sec before trying service mode... + if( _connectMode == CLOSED_MODE ) + { + _serial.open( Settings::port, emulatorName); + _serial.sleep(333); // Initial 1/3 sec before trying service mode... + } for(int retry=0; retry < 10; ++retry) { unsigned char serviceMode[] = { 0xAA, 0xAB, 0xCD, 0xEF };
--- a/OSTC4Operations.cpp Sun Nov 30 18:37:32 2025 +0100 +++ b/OSTC4Operations.cpp Tue Dec 30 21:41:02 2025 +0100 @@ -38,6 +38,7 @@ #include <QRegularExpression> #include "OSTC4Operations.h" + #include "Utils/Log.h" #include "Utils/Exception.h" #include "Utils/ProgressEvent.h" @@ -64,9 +65,21 @@ HardwareOperations::CompanionFeatures OSTC4Operations::supported() const { - // No ICON, no DUMPSCREEN - return CompanionFeatures(PARAMETERS|DATE|NAME|FIRMWARE - |HELIUM_DIVE|CCR_DIVE|BLUETOOTH|VPM_MODEL|SIGNAL_CHECK); + // No DUMPSCREEN + + CompanionFeatures features; + features |= PARAMETERS; + features |= DATE; + features |= NAME; + features |= FIRMWARE; + features |= HELIUM_DIVE; + features |= CCR_DIVE; + features |= BLUETOOTH; + features |= VPM_MODEL; + features |= SIGNAL_CHECK; + features |= ICON; + + return features; } QString OSTC4Operations::firmwareTemplate() const @@ -188,6 +201,7 @@ : fileChecksum(0,0) { emulatorName = "OSTC4/5"; + m_crcWrapper = new CrcWrapper(nullptr); } ////////////////////////////////////////////////////////////////////////////// @@ -202,18 +216,131 @@ LOG_INFO("Please wait for OSTC4/5 to complete installation..."); } +#define SWAP4BYTES(x) \ +uint( (((x) & 0x000000FF) << 24) \ + | (((x) & 0x0000FF00) << 8) \ + | (((x) & 0x00FF0000) >> 8) \ + | (((x) & 0xFF000000) >> 24)) + +void OSTC4Operations::setIcons(const QString &fileName) +{ + int size; + int blockSize; + int transferDelay; + unsigned char echo; + + FirmwareOSTC4 header; + + unsigned char buf3offset[4]; + unsigned char bufVersion[4]; + uint32_t checksum = 0; + uint32_t width = 0; + uint32_t height = 0; + + blockSize = FIRMWARE_BLOCK; + transferDelay = FIRMWARE_BLOCK_DELAY; + + try + { + bmp = std::make_unique<BmpToArray>(fileName); + } + catch (const std::exception& e) + { + std::cerr << "Fehler beim Laden: " << e.what() << '\n'; + } + + QByteArray bin = bmp->getTransferBytes(); + bmp->getImageXY(&width, &height); + + if(bin.size() < 200000) + { + buf3offset[0] = 0x20; + buf3offset[1] = 0x00; + buf3offset[2] = 0x00; + buf3offset[3] = 0x00; + bufVersion[0] = 1; + bufVersion[1] = 0; + bufVersion[2] = 0; + bufVersion[3] = 0; + + header.type = 0x20; + /* original header shallnot be modifieded => split image size information into 5 bytes */ + header.dummy5 = width; /* low byte */ + header.dummy6 = height; /* low byte */ + header.dummy7 = (width >> 8) & 0x0000000F; /* shifted high nibble */ + header.dummy7 |= (height >> 4) & 0x000000F0; /* shifted high nibble */ + + header.length = SWAP4BYTES(bin.size()); + header.checksum = bin.size() + (256*256*256*header.type) + (256*256* header.dummy5) + (256*header.dummy6) + header.dummy7; + + checksum = SWAP4BYTES(m_crcWrapper->CRC_CalcBlockCRC(reinterpret_cast<uint32_t*>(bin.data()), bin.size() / 4)); + + //---- Upload icon ----------------------------------------------- + const int steps = 3 + (bin.size()+blockSize-1) / blockSize; + int step = 0; + PROGRESS(step++, steps); + + LOG_INFO(QString(" uploading icon size %1 bytes").arg(bin.size())); + writeText( QString("Upload Icon") ); + + //---- Command + PROGRESS(step++, steps); + echo = retryCommand(_serial, 'o'); // 0x6F upload icon + if( echo != 'o' ) + LOG_THROW("Bad OSTC4/5 icon upload."); + + //---- Header + PROGRESS(step++, steps); + _serial.writeBlock((uchar*)&header, sizeof header); + _serial.sleep(500); + //---- Data + for(int len = 0x00000; len < bin.size(); len += blockSize) + { + if(transferDelay) + { + _serial.sleep(transferDelay); // 15 msec between 64B blocks... + } + PROGRESS(step++, steps); + + size = qMin(blockSize, + bin.size() - len); + + LOG_TRACE("Fill " << size); + _serial.writeBlock((uchar*)bin.data()+len, (unsigned int)size); + } + _serial.writeBlock((uchar*)&checksum, 4); + PROGRESS(steps, steps); // 100% + + //---- Wait acknowledge ---------------------------------------------- + PROGRESS_THROTTLE(); + + for(int wait=0; wait<2*60; ++wait) // Up to 2 min... + { + try { + unsigned char reply = _serial.readByte(); + if( reply == 0x4D ) + break; + } + catch( const ReadTimeout&) {} + } + + LOG_INFO(" icon uploaded."); + } + else + { + LOG_THROW("Image to large. Must be < 200k."); + } + PROGRESS_RESET(); +} + + + ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// /// FIRMWARE UPGRADE /// ////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////// -#define SWAP4BYTES(x) \ - uint( (((x) & 0x000000FF) << 24) \ - | (((x) & 0x0000FF00) << 8) \ - | (((x) & 0x00FF0000) >> 8) \ - | (((x) & 0xFF000000) >> 24)) - ////////////////////////////////////////////////////////////////////////////// void OSTC4Operations::openFirmware(const QString &fileName, bool dryRun)
--- a/OSTC4Operations.h Sun Nov 30 18:37:32 2025 +0100 +++ b/OSTC4Operations.h Tue Dec 30 21:41:02 2025 +0100 @@ -45,8 +45,11 @@ #include <QRegularExpression> #include "AES/Adler16.h" +#include "ostc45_icon.h" +#include "crc_wrapper.h" #include "Export.h" #include <QFile> +#include <QString> ////////////////////////////////////////////////////////////////////////////// /// \brief Implementing various operations for H&W OSTC4 dive computer @@ -79,6 +82,8 @@ QFile _file; + std::unique_ptr<BmpToArray> bmp; + /// \param[in] dryRun: If TRUE, do not upload FW, just check file structure. void openFirmware(const QString& fileName, bool dryRun); @@ -91,6 +96,7 @@ void writeAllHeader(unsigned char* pBuffer) override; void getAllSamples(unsigned char* pBuffer) override; void writeAllSamples(unsigned char* pBuffer) override; + void setIcons(const QString& fileName) override; EXPORT QString firmwareTemplate() const override; // EXPORT QRegExp portTemplate() const override; @@ -100,6 +106,8 @@ Adler32 fileChecksum; + CrcWrapper* m_crcWrapper; + public: EXPORT OSTC4Operations(); };
--- a/about.txt Sun Nov 30 18:37:32 2025 +0100 +++ b/about.txt Tue Dec 30 21:41:02 2025 +0100 @@ -1,1 +1,1 @@ -This repository holds the source code for the OSTC Companion program. \ No newline at end of file +This repository holds the source code for the OSTC Companion program.
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc_wrapper.cpp Tue Dec 30 21:41:02 2025 +0100 @@ -0,0 +1,77 @@ +#include "crc_wrapper.h" + +extern "C" { +#include "crcmodel.h" +} + + +CrcWrapper::CrcWrapper(QObject *parent) + : QObject(parent) +{} + + +void CrcWrapper::init(p_cm_t p_cm) +{ + cm_ini(p_cm); +} + +void CrcWrapper::cm_next(p_cm_t p_cm, int ch) +{ + cm_nxt(p_cm, ch); +} + +uint32_t CrcWrapper::CRC_CalcBlockCRC(uint32_t *buffer, uint32_t words) +{ + cm_t crc_model; + uint32_t word_to_do; + uint8_t byte_to_do; + int i; + + // Values for the STM32F generator. + + crc_model.cm_width = 32; // 32-bit CRC + crc_model.cm_poly = 0x04C11DB7; // CRC-32 polynomial + crc_model.cm_init = 0xFFFFFFFF; // CRC initialized to 1's + crc_model.cm_refin = FALSE; // CRC calculated MSB first + crc_model.cm_refot = FALSE; // Final result is not bit-reversed + crc_model.cm_xorot = 0x00000000; // Final result XOR'ed with this + + cm_ini(&crc_model); + + while (words--) + { + // The STM32F10x hardware does 32-bit words at a time!!! + + word_to_do = *buffer++; + + // Do all bytes in the 32-bit word. + + for (i = 0; i < sizeof(word_to_do); i++) + { + // We calculate a *byte* at a time. If the CRC is MSB first we + // do the next MS byte and vica-versa. + + if (crc_model.cm_refin == FALSE) + { + // MSB first. Do the next MS byte. + + byte_to_do = (uint8_t) ((word_to_do & 0xFF000000) >> 24); + word_to_do <<= 8; + } + else + { + // LSB first. Do the next LS byte. + + byte_to_do = (uint8_t) (word_to_do & 0x000000FF); + word_to_do >>= 8; + } + + cm_nxt(&crc_model, byte_to_do); + } + } + + // Return the final result. + + return (cm_crc(&crc_model)); +} +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crc_wrapper.h Tue Dec 30 21:41:02 2025 +0100 @@ -0,0 +1,23 @@ +#ifndef CRC_WRAPPER_H +#define CRC_WRAPPER_H + +extern "C" { +#include "crcmodel.h" +} +#include <QObject> + +class CrcWrapper : public QObject +{ + Q_OBJECT +public: + explicit CrcWrapper(QObject *parent = nullptr); + + void init(p_cm_t p_cm); + void cm_next(p_cm_t p_cm,int ch); + + uint32_t CRC_CalcBlockCRC(uint32_t *buffer, uint32_t words); + + +}; + +#endif // CRC_WRAPPER_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crcmodel.c Tue Dec 30 21:41:02 2025 +0100 @@ -0,0 +1,137 @@ +/******************************************************************************/ +/* Start of crcmodel.c */ +/******************************************************************************/ +/* */ +/* Author : Ross Williams (ross@guest.adelaide.edu.au.). */ +/* Date : 3 June 1993. */ +/* Status : Public domain. */ +/* */ +/* Description : This is the implementation (.c) file for the reference */ +/* implementation of the Rocksoft^tm Model CRC Algorithm. For more */ +/* information on the Rocksoft^tm Model CRC Algorithm, see the document */ +/* titled "A Painless Guide to CRC Error Detection Algorithms" by Ross */ +/* Williams (ross@guest.adelaide.edu.au.). This document is likely to be in */ +/* "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia. */ +/* */ +/******************************************************************************/ +/* */ +/* Implementation Notes */ +/* -------------------- */ +/* To avoid inconsistencies, the specification of each function is not echoed */ +/* here. See the header file for a description of these functions. */ +/* This package is light on checking because I want to keep it short and */ +/* simple and portable (i.e. it would be too messy to distribute my entire */ +/* C culture (e.g. assertions package) with this package. */ +/* */ +/******************************************************************************/ + +#include "crcmodel.h" + +/******************************************************************************/ + +/* The following definitions make the code more readable. */ + +#define BITMASK(X) (1L << (X)) +#define MASK32 0xFFFFFFFFL +#define LOCAL static + +/******************************************************************************/ + +LOCAL ulong reflect P_((ulong v,int b)); +LOCAL ulong reflect (ulong v,int b) +/* Returns the value v with the bottom b [0,32] bits reflected. */ +/* Example: reflect(0x3e23L,3) == 0x3e26 */ +{ + int i; + ulong t = v; + for (i=0; i<b; i++) + { + if (t & 1L) + v|= BITMASK((b-1)-i); + else + v&= ~BITMASK((b-1)-i); + t>>=1; + } + return v; +} + +/******************************************************************************/ + +LOCAL ulong widmask P_((p_cm_t)); +LOCAL ulong widmask (p_cm_t p_cm) +/* Returns a longword whose value is (2^p_cm->cm_width)-1. */ +/* The trick is to do this portably (e.g. without doing <<32). */ +{ + return (((1L<<(p_cm->cm_width-1))-1L)<<1)|1L; +} + +/******************************************************************************/ + +void cm_ini (p_cm_t p_cm) +{ + p_cm->cm_reg = p_cm->cm_init; +} + +/******************************************************************************/ + +void cm_nxt (p_cm_t p_cm, int ch) +{ + int i; + ulong uch = (ulong) ch; + ulong topbit = BITMASK(p_cm->cm_width-1); + + if (p_cm->cm_refin) uch = reflect(uch,8); + p_cm->cm_reg ^= (uch << (p_cm->cm_width-8)); + for (i=0; i<8; i++) + { + if (p_cm->cm_reg & topbit) + p_cm->cm_reg = (p_cm->cm_reg << 1) ^ p_cm->cm_poly; + else + p_cm->cm_reg <<= 1; + p_cm->cm_reg &= widmask(p_cm); + } +} + +/******************************************************************************/ + +void cm_blk (p_cm_t p_cm,p_ubyte_ blk_adr,ulong blk_len) +{ + while (blk_len--) cm_nxt(p_cm,*blk_adr++); +} + +/******************************************************************************/ + +ulong cm_crc (p_cm_t p_cm) +{ + if (p_cm->cm_refot) + return p_cm->cm_xorot ^ reflect(p_cm->cm_reg,p_cm->cm_width); + else + return p_cm->cm_xorot ^ p_cm->cm_reg; +} + +/******************************************************************************/ + +ulong cm_tab (p_cm_t p_cm, int index) +{ + int i; + ulong r; + ulong topbit = BITMASK(p_cm->cm_width-1); + ulong inbyte = (ulong) index; + + if (p_cm->cm_refin) inbyte = reflect(inbyte,8); + r = inbyte << (p_cm->cm_width-8); + for (i=0; i<8; i++) + if (r & topbit) + r = (r << 1) ^ p_cm->cm_poly; + else + r<<=1; + if (p_cm->cm_refin) r = reflect(r,p_cm->cm_width); + return r & widmask(p_cm); +} + +/******************************************************************************/ +/* End of crcmodel.c */ +/******************************************************************************/ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/crcmodel.h Tue Dec 30 21:41:02 2025 +0100 @@ -0,0 +1,197 @@ +/////////////////////////////////////////////////////////////////////////////// +/// -*- coding: UTF-8 -*- +/// +/// \file Discovery/Inc/crcmodel.h +/// \brief Rocksoft CRC Model Algorithm +/// \author Ross Williams (ross@guest.adelaide.edu.au.) and Heinrichs Weikamp +/// \date 3 June 1993 +/// +/// \details +/// +/// This is the header (.h) file for the reference +/// implementation of the Rocksoft^tm Model CRC Algorithm. For more +/// information on the Rocksoft^tm Model CRC Algorithm, see the document +/// titled "A Painless Guide to CRC Error Detection Algorithms" by Ross +/// Williams (ross@guest.adelaide.edu.au.). This document is likely to be in +/// "ftp.adelaide.edu.au/pub/rocksoft". +/// +/// Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia. +/// +/// $Id$ +/////////////////////////////////////////////////////////////////////////////// +/// \par Copyright (c) 2014-2018 Heinrichs Weikamp gmbh +/// +/// This program is free software: you can redistribute it and/or modify +/// it under the terms of the GNU General Public License as published by +/// the Free Software Foundation, either version 3 of the License, or +/// (at your option) any later version. +/// +/// This program is distributed in the hope that it will be useful, +/// but WITHOUT ANY WARRANTY; without even the implied warranty of +/// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +/// GNU General Public License for more details. +/// +/// You should have received a copy of the GNU General Public License +/// along with this program. If not, see <http://www.gnu.org/licenses/>. +////////////////////////////////////////////////////////////////////////////// + +/******************************************************************************/ +/* Start of crcmodel.h */ +/******************************************************************************/ +/* */ +/* Author : Ross Williams (ross@guest.adelaide.edu.au.). */ +/* Date : 3 June 1993. */ +/* Status : Public domain. */ +/* */ +/* Description : This is the header (.h) file for the reference */ +/* implementation of the Rocksoft^tm Model CRC Algorithm. For more */ +/* information on the Rocksoft^tm Model CRC Algorithm, see the document */ +/* titled "A Painless Guide to CRC Error Detection Algorithms" by Ross */ +/* Williams (ross@guest.adelaide.edu.au.). This document is likely to be in */ +/* "ftp.adelaide.edu.au/pub/rocksoft". */ +/* */ +/* Note: Rocksoft is a trademark of Rocksoft Pty Ltd, Adelaide, Australia. */ +/* */ +/******************************************************************************/ +/* */ +/* How to Use This Package */ +/* ----------------------- */ +/* Step 1: Declare a variable of type cm_t. Declare another variable */ +/* (p_cm say) of type p_cm_t and initialize it to point to the first */ +/* variable (e.g. p_cm_t p_cm = &cm_t). */ +/* */ +/* Step 2: Assign values to the parameter fields of the structure. */ +/* If you don't know what to assign, see the document cited earlier. */ +/* For example: */ +/* p_cm->cm_width = 16; */ +/* p_cm->cm_poly = 0x8005L; */ +/* p_cm->cm_init = 0L; */ +/* p_cm->cm_refin = TRUE; */ +/* p_cm->cm_refot = TRUE; */ +/* p_cm->cm_xorot = 0L; */ +/* Note: Poly is specified without its top bit (18005 becomes 8005). */ +/* Note: Width is one bit less than the raw poly width. */ +/* */ +/* Step 3: Initialize the instance with a call cm_ini(p_cm); */ +/* */ +/* Step 4: Process zero or more message bytes by placing zero or more */ +/* successive calls to cm_nxt. Example: cm_nxt(p_cm,ch); */ +/* */ +/* Step 5: Extract the CRC value at any time by calling crc = cm_crc(p_cm); */ +/* If the CRC is a 16-bit value, it will be in the bottom 16 bits. */ +/* */ +/******************************************************************************/ +/* */ +/* Design Notes */ +/* ------------ */ +/* PORTABILITY: This package has been coded very conservatively so that */ +/* it will run on as many machines as possible. For example, all external */ +/* identifiers have been restricted to 6 characters and all internal ones to */ +/* 8 characters. The prefix cm (for Crc Model) is used as an attempt to avoid */ +/* namespace collisions. This package is endian independent. */ +/* */ +/* EFFICIENCY: This package (and its interface) is not designed for */ +/* speed. The purpose of this package is to act as a well-defined reference */ +/* model for the specification of CRC algorithms. If you want speed, cook up */ +/* a specific table-driven implementation as described in the document cited */ +/* above. This package is designed for validation only; if you have found or */ +/* implemented a CRC algorithm and wish to describe it as a set of parameters */ +/* to the Rocksoft^tm Model CRC Algorithm, your CRC algorithm implementation */ +/* should behave identically to this package under those parameters. */ +/* */ +/******************************************************************************/ + + + +#ifndef CRC_MODEL_H +#define CRC_MODEL_H + + +#ifdef __cplusplus +extern "C" { +#endif +/******************************************************************************/ + +/* The following definitions are extracted from my style header file which */ +/* would be cumbersome to distribute with this package. The DONE_STYLE is the */ +/* idempotence symbol used in my style header file. */ + +#ifndef DONE_STYLE + +#include <stdbool.h> + +typedef unsigned long ulong; +typedef unsigned char * p_ubyte_; + +#ifndef TRUE +#define FALSE 0 +#define TRUE 1 +#endif + +/* Change to the second definition if you don't have prototypes. */ +#define P_(A) A +/* #define P_(A) () */ + +/* Uncomment this definition if you don't have void. */ +/* typedef int void; */ + +#endif + +/******************************************************************************/ + +/* CRC Model Abstract Type */ +/* ----------------------- */ +/* The following type stores the context of an executing instance of the */ +/* model algorithm. Most of the fields are model parameters which must be */ +/* set before the first initializing call to cm_ini. */ +typedef struct + { + int cm_width; /* Parameter: Width in bits [8,32]. */ + ulong cm_poly; /* Parameter: The algorithm's polynomial. */ + ulong cm_init; /* Parameter: Initial register value. */ + bool cm_refin; /* Parameter: Reflect input bytes? */ + bool cm_refot; /* Parameter: Reflect output CRC? */ + ulong cm_xorot; /* Parameter: XOR this to output CRC. */ + + ulong cm_reg; /* Context: Context during execution. */ + } cm_t; +typedef cm_t *p_cm_t; + +/******************************************************************************/ + +/* Functions That Implement The Model */ +/* ---------------------------------- */ +/* The following functions animate the cm_t abstraction. */ + +void cm_ini P_((p_cm_t p_cm)); +/* Initializes the argument CRC model instance. */ +/* All parameter fields must be set before calling this. */ + +void cm_nxt P_((p_cm_t p_cm,int ch)); +/* Processes a single message byte [0,255]. */ + +void cm_blk P_((p_cm_t p_cm,p_ubyte_ blk_adr,ulong blk_len)); +/* Processes a block of message bytes. */ + +ulong cm_crc P_((p_cm_t p_cm)); +/* Returns the CRC value for the message bytes processed so far. */ + +/******************************************************************************/ + +/* Functions For Table Calculation */ +/* ------------------------------- */ +/* The following function can be used to calculate a CRC lookup table. */ +/* It can also be used at run-time to create or check static tables. */ + +ulong cm_tab P_((p_cm_t p_cm,int index)); +/* Returns the i'th entry for the lookup table for the specified algorithm. */ +/* The function examines the fields cm_width, cm_poly, cm_refin, and the */ +/* argument table index in the range [0,255] and returns the table entry in */ +/* the bottom cm_width bytes of the return value. */ + +/******************************************************************************/ + +#ifdef __cplusplus +} +#endif +#endif // CRC_MODEL_H
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ostc45_icon.cpp Tue Dec 30 21:41:02 2025 +0100 @@ -0,0 +1,163 @@ +#include "ostc45_icon.h" + + +//OSTC45_Icon::OSTC45_Icon() {} + + +#pragma pack(push, 1) +struct BMPFileHeader +{ + uint16_t bfType; + uint32_t bfSize; + uint16_t bfReserved1; + uint16_t bfReserved2; + uint32_t bfOffBits; +}; + +struct BMPInfoHeader +{ + uint32_t biSize; + int32_t biWidth; + int32_t biHeight; + uint16_t biPlanes; + uint16_t biBitCount; + uint32_t biCompression; + uint32_t biSizeImage; + int32_t biXPelsPerMeter; + int32_t biYPelsPerMeter; + uint32_t biClrUsed; + uint32_t biClrImportant; +}; +#pragma pack(pop) + +BmpToArray::BmpToArray(const QString& filename) +{ + loadBMP(filename); +} + +void BmpToArray::loadBMP(const QString& filename) +{ + QFile file(filename); + int dstY; + QByteArray rowBuffer; + bool topDown = false; + BMPFileHeader fileHeader; + BMPInfoHeader infoHeader; + + if (!file.open(QIODevice::ReadOnly)) + throw std::runtime_error("Cannot open BMP file"); + + if (file.read(reinterpret_cast<char*>(&fileHeader), + sizeof(BMPFileHeader)) != sizeof(BMPFileHeader)) + throw std::runtime_error("Failed to read BMP file header"); + + if (file.read(reinterpret_cast<char*>(&infoHeader), + sizeof(BMPInfoHeader)) != sizeof(BMPInfoHeader)) + throw std::runtime_error("Failed to read BMP info header"); + + if (fileHeader.bfType != 0x4D42) + throw std::runtime_error("Not a valid BMP file"); + + if (infoHeader.biBitCount != 8) + throw std::runtime_error("Only 8-bit BMP supported"); + if (infoHeader.biCompression != 0) + throw std::runtime_error("Compressed BMP not supported"); + + if(infoHeader.biWidth > 800) + throw std::runtime_error("Only BMP with 800 or less horizontal pixels supported"); + + if(infoHeader.biHeight > 480) + throw std::runtime_error("Only BMP with 480 or less vertical pixels supported"); + + // Width / Height + width = infoHeader.biWidth; + height = infoHeader.biHeight; + + if ((int32_t)height < 0) { + height = -((int32_t)height); + topDown = true; + } + + // Palette + uint32_t colorCount = infoHeader.biClrUsed; + if (colorCount == 0) colorCount = 256; + if (colorCount > 256) colorCount = 256; + + clut.resize(colorCount); + + for (uint32_t i = 0; i < colorCount; ++i) + file.read(reinterpret_cast<char*>(&clut[i]), 4); + + // CLUT in 32-Bit transform 0x00RRGGBB + clut32.resize(255, 0); + + for (uint32_t i = 0; i < colorCount && i < 255; ++i) + { + clut32[i] = + (clut[i].r << 16) | + (clut[i].g << 8) | + (clut[i].b); + } + + // Pixel-Data + if (!file.seek(fileHeader.bfOffBits)) + throw std::runtime_error("Failed to seek to pixel data"); + + pixelData.resize(width * height); + + size_t rowSize = (width + 3) & ~3; // 4-Byte alignment + + rowBuffer.resize(rowSize); + + for (int y = 0; y < height; ++y) + { + if (file.read(rowBuffer.data(), rowSize) != rowSize) + throw std::runtime_error("Failed to read BMP pixel row"); + + if (topDown) + { + dstY = height - 1 - y; + } + else + { + dstY = y; + } + + for (int x = 0; x < width; ++x) + { + pixelData[x * height + dstY] = + static_cast<uint8_t>(rowBuffer[x]); + } + } + + +} +QByteArray BmpToArray::getTransferBytes() const +{ + QByteArray out; + + out.reserve(clut32.size() * 4 + pixelData.size()); + + // CLUT (32 Bit, Little Endian) + for (uint32_t color : clut32) + { + out.append(static_cast<char>( color & 0xFF)); + out.append(static_cast<char>((color >> 8) & 0xFF)); + out.append(static_cast<char>((color >> 16) & 0xFF)); + out.append(static_cast<char>((color >> 24) & 0xFF)); + } + + // Pixel (8 Bit) + out.append(reinterpret_cast<const char*>(pixelData.data()), + pixelData.size()); + + return out; +} + +void BmpToArray::getImageXY(uint32_t* x, uint32_t* y) +{ + *x = width; + *y = height; +} + +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ostc45_icon.h Tue Dec 30 21:41:02 2025 +0100 @@ -0,0 +1,37 @@ +#ifndef OSTC45_ICON_H +#define OSTC45_ICON_H + +#include <cstdint> +#include <vector> +#include <stdexcept> +#include <iostream> +#include <QString> +#include <QVector> +#include <QIODevice> +#include <QFile> +#include <QByteArray> + +class BmpToArray +{ +public: + struct CLUTEntry { + uint8_t b; + uint8_t g; + uint8_t r; + uint8_t a; // BMP setzt meist 0 + }; + + QByteArray getTransferBytes() const; + void getImageXY(uint32_t* x, uint32_t* y); + BmpToArray(const QString& fileName); + +private: + void loadBMP(const QString& filename); + + QVector<CLUTEntry> clut; + QVector<uint8_t> pixelData; // Pixel-Indizes + QVector<uint32_t> clut32; // 32-Bit Palette + uint32_t width = 0; + uint32_t height = 0; +}; +#endif // OSTC45_ICON_H
