copy member from void * array

本文介绍了一个使用C语言编写的内存复制函数copy_element。该函数可以将多个不同来源的固定大小的数据块复制到一块连续的内存区域中,并提供了一个简单的示例程序来展示其用法。
void *copy_element(const void *src[], int cnt, size_t size)
{
	void *result = 0;
	char *p;
	size_t num = 0;
	for(int i = 0;i < cnt;i++)
	{
		num += size;
		result = realloc(result, num);
		if(!result) break;
		if(!i) p = (char *)result;
		memcpy(p, (const char *)src[i], size);
		p += size;
	}
	return result;
}
int main() 
{
	const void *p[2] = {"abc", "123"};
	void *result = copy_element(p, 2, 3);
	char *q = (char *)result;
	for(int i = 0;i < 6;i++) printf("%c", q[i]);
	free(result);
	cout << endl;

	return 0;
}

// Copyright 2017 ~ 2022 Critical Failure Studio Ltd. All rights reserved. #pragma once #include "CoreMinimal.h" #include "Notifies/PaperZDAnimNotify_Base.h" #include "PaperZDAnimSequence.generated.h" DECLARE_DELEGATE(FOnPostEditUndo) DECLARE_MULTICAST_DELEGATE(FOnNotifyChangeSignature); class UCG_UPaperFlipbook; class UPaperZDAnimBP; class UPaperZDAnimNotify_Base; class UPaperZDPlaybackHandle; class UPaperZDAnimationSource; /** * Stores the meta-information of a track used to display AnimNotify information in an orderly manner. */ USTRUCT() struct FPaperZDAnimTrackMetadata { GENERATED_BODY() /* Color used to display the track visually. */ UPROPERTY() FLinearColor Color; /* Editor name for the track. */ UPROPERTY() FName DisplayName; public: FPaperZDAnimTrackMetadata() : Color(FLinearColor::Gray) , DisplayName(NAME_None) {} }; /** * Simple structure to be passed when requesting an animation track, which is an Editor-Only data object used to encapsulate the AnimNotifies for later display. * The track is valid up until either the notifies or the track itself get modified and should only be used during the scope in which the track was obtained. */ struct FPaperZDAnimTrack { /* Array of notifies assigned to the track. */ TArray<UPaperZDAnimNotify_Base*> AnimNotifies; /* Extra data used to display the track. */ FPaperZDAnimTrackMetadata Metadata; public: //ctor FPaperZDAnimTrack() {} FPaperZDAnimTrack(const TArray<UPaperZDAnimNotify_Base*>& InAnimNotifies, const FPaperZDAnimTrackMetadata& InMetadata) : AnimNotifies(InAnimNotifies) , Metadata(InMetadata) {} }; /** * The AnimSequence is the class responsible of handling how a given Animation source plays on the registered RenderComponent and handling meta info like AnimNotifies. */ UCLASS(abstract, BlueprintType) class PAPERZD_API UPaperZDAnimSequence : public UObject { GENERATED_UCLASS_BODY() #if WITH_EDITOR //Added for version update to AnimSequence only friend class FPaperZDRuntimeEditorProxy; #endif private: /* Default category name when creating an AnimSequence */ static const FName DefaultCategory; /* Name of the AnimSource owner member name. */ static const FName AnimSourceMemberName; /* Animation source that owns this sequence. */ UPROPERTY(VisibleAnywhere, AssetRegistrySearchable, Category = Animation) TObjectPtr<UPaperZDAnimationSource> AnimSource; /* The list of the AnimNotifies linked to this animation. */ UPROPERTY() TArray<TObjectPtr<UPaperZDAnimNotify_Base>> AnimNotifies; #if WITH_EDITORONLY_DATA /* DEPRECATED: Points to the AnimBP that owned this AnimSequence before the creation of AnimSources. */ UPROPERTY(AssetRegistrySearchable) UPaperZDAnimBP* AnimBP_DEPRECATED; /* Track meta information for editor display. */ UPROPERTY() TArray<FPaperZDAnimTrackMetadata> AnimTrackData; /* Called when the list of notifies changes somehow. */ FOnNotifyChangeSignature OnNotifyChange; #endif /* Cached DataSource property for faster lookup. */ FArrayProperty* CachedAnimDataSourceProperty; public: UPROPERTY() FName DisplayName_DEPRECATED; //@Deprecated UPROPERTY() UCG_UPaperFlipbook* PaperFlipbook_DEPRECATED; //@Deprecated /** * If true, multiple animations sources can be added to this sequence at different angles. * Used for when the sequence needs to represent multiple rotations of the same animation (i.e. top-down and isometric games). */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AnimSequence", meta = (DisplayName = "Multi-Directional Sequence")) bool bDirectionalSequence; /** * Offset applied to all the animations on the directional map. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "AnimSequence", meta = (UIMin = "-45.0", ClampMin = "-45.0", UIMax = "45.0", ClampMax = "45.0")) float DirectionalAngleOffset; /** * Index to use while previewing a directional animation sequence */ int32 DirectionalPreviewIndex; /* The category of this sequence, displayed on the tree view on the AnimSequence editor. */ UPROPERTY(EditAnywhere, BlueprintReadOnly, AssetRegistrySearchable, Category = "AnimSequence") FName Category; //Delegate for PostEditChanges - Needed for the editor undo support FOnPostEditUndo OnPostEditUndo; //@TODO: SHOULD WE REMOVE THIS? public: //Required for version support virtual void PostLoad() override; virtual void Serialize(FArchive& Ar) override; /* Called after initializing the properties, but before serialization. */ virtual void PostInitProperties() override; /* Helper to get the AnimSource member name for the editor and others property windows */ static FName GetAnimSourceMemberName() { return UPaperZDAnimSequence::AnimSourceMemberName; } /* Obtains the Animation Source linked to this Sequence */ FORCEINLINE UPaperZDAnimationSource* GetAnimSource() const { return AnimSource; } /* Set the Animation source that owns this sequence. */ void SetAnimSource(class UPaperZDAnimationSource* InAnimSource); /* Get the AnimNotifies linked to this sequence. */ const TArray<UPaperZDAnimNotify_Base*>& GetAnimNotifies() const; /* Originally meant to hold the Display name, can be overridden if you don't want the default FName to be used when referring to this sequence. */ virtual FName GetSequenceName() const; /* Total duration of this Sequence, should be overridden */ UFUNCTION(BlueprintPure, Category = "AnimSequence") virtual float GetTotalDuration() const; /* Frames per second, used to show the grid on the AnimSequence editor */ UFUNCTION(BlueprintPure, Category = "AnimSequence") virtual float GetFramesPerSecond() const; /* Obtains the number of frames on this animation. */ virtual int32 GetNumberOfFrames() const; /* Obtain the frame number, given the playback time. */ int32 GetFrameAtTime(const float Time) const; /* Obtain the playback time, given the frame number. */ float GetTimeAtFrame(const int32 Frame) const; /** * Returns true if the given data source entry is considered as "set". * Override this entry if the AnimSequence supports Directional AnimDataSources to help it understand when a value is not set. */ virtual bool IsDataSourceEntrySet(int32 EntryIndex) const { return false; } /* Obtains the property that points to the array that serves as data source for this sequence. */ FArrayProperty* GetAnimDataSourceProperty() const; /** * Agnostic getter implementation for the internal AnimationData Source array. * For better performance, one should code a specialization. */ template<typename T> T GetAnimationDataByIndex(int32 DirectionalIndex = 0) const { FArrayProperty* ArrayProperty = GetAnimDataSourceProperty(); FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->ContainerPtrToValuePtr<uint8>(this)); const int32 Index = bDirectionalSequence ? DirectionalIndex : 0; uint8* Ptr = ArrayHelper.GetRawPtr(Index); return *reinterpret_cast<T*>(Ptr); } /** * Agnostic animation data getter. * @param DirectionalAngle The angle in degrees against the top of the animation. * @param bPreviewPlayer (Editor only) If true, the system will use the cached DirectionalPreviewIndex. * @return The animation data source object that defines the rendering for this sequence. */ template <typename T> T GetAnimationData(float DirectionalAngle = 0.0f, bool bPreviewPlayer = false) const { #if WITH_EDITOR if (bPreviewPlayer) { return GetAnimationDataByIndex<T>(DirectionalPreviewIndex); } #endif if (bDirectionalSequence) { //Obtain the directional preview index from the given angle FArrayProperty* ArrayProperty = GetAnimDataSourceProperty(); FScriptArrayHelper ArrayHelper(ArrayProperty, ArrayProperty->ContainerPtrToValuePtr<uint8>(this)); const int32 Num = ArrayHelper.Num(); const float AngleSepparation = 360.0f / Num; //We need to account for angles that are negative, for this we add a full revolution and then obtain the modulo, which will ensure we're always at a normalized range const int32 Area = (DirectionalAngle + DirectionalAngleOffset + AngleSepparation / 2.0f + 360.0f) / AngleSepparation; return GetAnimationDataByIndex<T>(Area % Num); } else { //Non-directional sequences will always use the first index return GetAnimationDataByIndex<T>(); } } /* True if this sequence is currently being used as a "Directional Sequence" */ FORCEINLINE bool IsDirectionalSequence() const { return bDirectionalSequence; } /* Angle to offset the "Directional Sequence" */ FORCEINLINE float GetDirectionalAngleOffset() const { return DirectionalAngleOffset; } #if WITH_EDITOR void PostEditUndo() override; /* Initializes the AnimTracks, making sure that we have enough metadata for any AnimNotify that we have stored. */ void InitTracks(); /* Get the delegate called when a notify changes internally. */ FOnNotifyChangeSignature& GetOnNotifyChange() { return OnNotifyChange; } /** * Creates a track data object. * @param InsertInto The index in which to insert the track, or INDEX_NONE to append it to the end * @return The track index. */ int32 CreateTrack(int32 InsertInto = INDEX_NONE); /* Removes the track with the given index, deleting any and all notifies that are stored on it. */ void RemoveTrack(int32 TrackIndex); /* Creates a notify of the given class and adds it to the given track. */ void AddNotifyToTrack(TSubclassOf<class UPaperZDAnimNotify_Base> NotifyClass, int32 TrackIndex, FName NotifyName, float InitTime = 0.0f); /* Removes the notify. */ void RemoveNotify(class UPaperZDAnimNotify_Base* Notify); /* Moves the notify to the given track. */ void MoveNotify(class UPaperZDAnimNotify_Base* Notify, int32 ToTrack); /* Imports the given notifies into the sequence, usually due to copy/paste operations. */ void ImportNotifies(TArray<UPaperZDAnimNotify_Base*> Notifies); /* Return the number of tracks currently stored on the sequence. */ int32 GetNumTracks() const; /* Obtain the metadata of the track on the given index, returns whether the track was found or not. */ bool GetTrackMetadata(int32 Index, FPaperZDAnimTrackMetadata& OutMetadata) const; /* Obtain the metadata of the track on the given index, assumes the index is correct or asserts if not. */ const FPaperZDAnimTrackMetadata& GetTrackMetadataChecked(int32 Index) const; FPaperZDAnimTrackMetadata& GetMutableTrackMetadataChecked(int32 Index); /* Obtain the track on the given index, returns whether the track was found or not. */ bool GetTrack(int32 Index, FPaperZDAnimTrack& OutTrack) const; /* Obtain the track on the given index, assumes the index is correct or asserts if not. */ FPaperZDAnimTrack GetTrackChecked(int32 Index) const; /* Purge any custom notify that's currently referencing a function that isn't registered. */ void PurgeInvalidCustomNotifies(const TArray<FName>& ValidRegisteredNames); #endif protected: /* Requests the name of the array property to be used as the "AnimDataSource". */ virtual FName GetDataSourcePropertyName() const; private: /* Initializes the Animation Data Source and makes sure its correctly configured for later use. */ void InitDataSource(); }; 详细白话注释各个变量的重要功能作用意义
07-01
[{ "resource": "/F:/文档/PlatformIO/Projects/spi1032/src/main.cpp", "owner": "C/C++: IntelliSense", "code": "1455", "severity": 8, "message": "使用“override”声明的成员函数不能重写基类成员", "source": "C/C++", "startLineNumber": 58, "startColumn": 10, "endLineNumber": 58, "endColumn": 19, "origin": "extHost1" },{ "resource": "/F:/文档/PlatformIO/Projects/spi1032/src/main.cpp", "owner": "C/C++: IntelliSense", "code": "1455", "severity": 8, "message": "使用“override”声明的成员函数不能重写基类成员", "source": "C/C++", "startLineNumber": 63, "startColumn": 10, "endLineNumber": 63, "endColumn": 22, "origin": "extHost1" },{ "resource": "/F:/文档/PlatformIO/Projects/spi1032/src/main.cpp", "owner": "C/C++: IntelliSense", "code": "1455", "severity": 8, "message": "使用“override”声明的成员函数不能重写基类成员", "source": "C/C++", "startLineNumber": 71, "startColumn": 10, "endLineNumber": 71, "endColumn": 17, "origin": "extHost1" },{ "resource": "/F:/文档/PlatformIO/Projects/spi1032/src/main.cpp", "owner": "C/C++: IntelliSense", "code": "135", "severity": 8, "message": "类 \"NimBLEAdvertising\" 没有成员 \"setScanResponse\"", "source": "C/C++", "startLineNumber": 347, "startColumn": 19, "endLineNumber": 347, "endColumn": 34, "origin": "extHost1" }] /* * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and * esp-nimble-cpp, NimBLE-Arduino contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef NIMBLE_CPP_CHARACTERISTIC_H_ #define NIMBLE_CPP_CHARACTERISTIC_H_ #include "nimconfig.h" #if CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL class NimBLECharacteristicCallbacks; class NimBLEService; class NimBLECharacteristic; class NimBLEDescriptor; class NimBLE2904; # include "NimBLELocalValueAttribute.h" # include <string> # include <vector> /** * @brief The model of a BLE Characteristic. * * A BLE Characteristic is an identified value container that manages a value. It is exposed by a BLE service and * can be read and written to by a BLE client. */ class NimBLECharacteristic : public NimBLELocalValueAttribute { public: NimBLECharacteristic(const char* uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN, NimBLEService* pService = nullptr); NimBLECharacteristic(const NimBLEUUID& uuid, uint16_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN, NimBLEService* pService = nullptr); ~NimBLECharacteristic(); std::string toString() const; void addDescriptor(NimBLEDescriptor* pDescriptor); void removeDescriptor(NimBLEDescriptor* pDescriptor, bool deleteDsc = false); uint16_t getProperties() const; void setCallbacks(NimBLECharacteristicCallbacks* pCallbacks); bool indicate(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const; bool indicate(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const; bool notify(uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const; bool notify(const uint8_t* value, size_t length, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const; NimBLEDescriptor* createDescriptor(const char* uuid, uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN); NimBLEDescriptor* createDescriptor(const NimBLEUUID& uuid, uint32_t properties = NIMBLE_PROPERTY::READ | NIMBLE_PROPERTY::WRITE, uint16_t maxLen = BLE_ATT_ATTR_MAX_LEN); NimBLE2904* create2904(); NimBLEDescriptor* getDescriptorByUUID(const char* uuid) const; NimBLEDescriptor* getDescriptorByUUID(const NimBLEUUID& uuid) const; NimBLEDescriptor* getDescriptorByHandle(uint16_t handle) const; NimBLEService* getService() const; NimBLECharacteristicCallbacks* getCallbacks() const; /*********************** Template Functions ************************/ # if __cplusplus < 201703L /** * @brief Template to send a notification with a value from a struct or array. * @param [in] v The value to send. * @param [in] connHandle Optional, a connection handle to send the notification to. * @details <type\> size must be evaluatable by `sizeof()`. */ template <typename T> # ifdef _DOXYGEN_ bool # else typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type # endif notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { return notify(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle); } /** * @brief Template to send a notification with a value from a class that has a c_str() and length() method. * @param [in] s The value to send. * @param [in] connHandle Optional, a connection handle to send the notification to. */ template <typename T> # ifdef _DOXYGEN_ bool # else typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type # endif notify(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { return notify(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle); } /** * @brief Template to send a notification with a value from a class that has a data() and size() method. * @param [in] v The value to send. * @param [in] connHandle Optional, a connection handle to send the notification to. */ template <typename T> # ifdef _DOXYGEN_ bool # else typename std::enable_if<Has_data_size<T>::value, bool>::type # endif notify(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { return notify(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle); } /** * @brief Template to send an indication with a value from a struct or array. * @param [in] v The value to send. * @param [in] connHandle Optional, a connection handle to send the notification to. * @details <type\> size must be evaluatable by `sizeof()`. */ template <typename T> # ifdef _DOXYGEN_ bool # else typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value && !Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type # endif indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { return indicate(reinterpret_cast<const uint8_t*>(&v), sizeof(T), connHandle); } /** * @brief Template to send a indication with a value from a class that has a c_str() and length() method. * @param [in] s The value to send. * @param [in] connHandle Optional, a connection handle to send the notification to. */ template <typename T> # ifdef _DOXYGEN_ bool # else typename std::enable_if<Has_c_str_length<T>::value && !Has_data_size<T>::value, bool>::type # endif indicate(const T& s, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { return indicate(reinterpret_cast<const uint8_t*>(s.c_str()), s.length(), connHandle); } /** * @brief Template to send a indication with a value from a class that has a data() and size() method. * @param [in] v The value to send. * @param [in] connHandle Optional, a connection handle to send the notification to. */ template <typename T> # ifdef _DOXYGEN_ bool # else typename std::enable_if<Has_data_size<T>::value, bool>::type # endif indicate(const T& v, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { return indicate(reinterpret_cast<const uint8_t*>(v.data()), v.size(), connHandle); } # else /** * @brief Template to send a notification for classes which may have * data()/size() or c_str()/length() methods. Falls back to sending * the data by casting the first element of the array to a uint8_t * pointer and getting the length of the array using sizeof. * @tparam T The a reference to a class containing the data to send. * @param[in] value The <type\>value to set. * @param[in] connHandle The connection handle to send the notification to. * @note This function is only available if the type T is not a pointer. */ template <typename T> typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value, bool>::type notify( const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { if constexpr (Has_data_size<T>::value) { return notify(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle); } else if constexpr (Has_c_str_length<T>::value) { return notify(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle); } else { return notify(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle); } } /** * @brief Template to send an indication for classes which may have * data()/size() or c_str()/length() methods. Falls back to sending * the data by casting the first element of the array to a uint8_t * pointer and getting the length of the array using sizeof. * @tparam T The a reference to a class containing the data to send. * @param[in] value The <type\>value to set. * @param[in] connHandle The connection handle to send the indication to. * @note This function is only available if the type T is not a pointer. */ template <typename T> typename std::enable_if<!std::is_pointer<T>::value && !std::is_array<T>::value, bool>::type indicate( const T& value, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const { if constexpr (Has_data_size<T>::value) { return indicate(reinterpret_cast<const uint8_t*>(value.data()), value.size(), connHandle); } else if constexpr (Has_c_str_length<T>::value) { return indicate(reinterpret_cast<const uint8_t*>(value.c_str()), value.length(), connHandle); } else { return indicate(reinterpret_cast<const uint8_t*>(&value), sizeof(value), connHandle); } } # endif private: friend class NimBLEServer; friend class NimBLEService; void setService(NimBLEService* pService); void readEvent(NimBLEConnInfo& connInfo) override; void writeEvent(const uint8_t* val, uint16_t len, NimBLEConnInfo& connInfo) override; bool sendValue(const uint8_t* value, size_t length, bool is_notification = true, uint16_t connHandle = BLE_HS_CONN_HANDLE_NONE) const; NimBLECharacteristicCallbacks* m_pCallbacks{nullptr}; NimBLEService* m_pService{nullptr}; std::vector<NimBLEDescriptor*> m_vDescriptors{}; }; // NimBLECharacteristic /** * @brief Callbacks that can be associated with a %BLE characteristic to inform of events. * * When a server application creates a %BLE characteristic, we may wish to be informed when there is either * a read or write request to the characteristic's value. An application can register a * sub-classed instance of this class and will be notified when such an event happens. */ class NimBLECharacteristicCallbacks { public: virtual ~NimBLECharacteristicCallbacks() {} virtual void onRead(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo); virtual void onWrite(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo); virtual void onStatus(NimBLECharacteristic* pCharacteristic, int code); virtual void onSubscribe(NimBLECharacteristic* pCharacteristic, NimBLEConnInfo& connInfo, uint16_t subValue); }; #endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL #endif // NIMBLE_CPP_CHARACTERISTIC_H_ /* * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and * esp-nimble-cpp, NimBLE-Arduino contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef NIMBLE_CPP_ADVERTISING_H_ #define NIMBLE_CPP_ADVERTISING_H_ #include "nimconfig.h" #if (CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_) # if defined(CONFIG_NIMBLE_CPP_IDF) # include "host/ble_gap.h" # else # include "nimble/nimble/host/include/host/ble_gap.h" # endif /**** FIX COMPILATION ****/ # undef min # undef max /**************************/ # include "NimBLEUUID.h" # include "NimBLEAddress.h" # include "NimBLEAdvertisementData.h" # include <functional> # include <string> # include <vector> class NimBLEAdvertising; typedef std::function<void(NimBLEAdvertising*)> advCompleteCB_t; /** * @brief Perform and manage BLE advertising. * * A BLE server will want to perform advertising in order to make itself known to BLE clients. */ class NimBLEAdvertising { public: NimBLEAdvertising(); bool start(uint32_t duration = 0, const NimBLEAddress* dirAddr = nullptr); void setAdvertisingCompleteCallback(advCompleteCB_t callback); bool stop(); bool setConnectableMode(uint8_t mode); bool setDiscoverableMode(uint8_t mode); bool reset(); bool isAdvertising(); void setScanFilter(bool scanRequestWhitelistOnly, bool connectWhitelistOnly); void enableScanResponse(bool enable); void setAdvertisingInterval(uint16_t interval); void setMaxInterval(uint16_t maxInterval); void setMinInterval(uint16_t minInterval); bool setAdvertisementData(const NimBLEAdvertisementData& advertisementData); bool setScanResponseData(const NimBLEAdvertisementData& advertisementData); const NimBLEAdvertisementData& getAdvertisementData(); const NimBLEAdvertisementData& getScanData(); void clearData(); bool refreshAdvertisingData(); bool addServiceUUID(const NimBLEUUID& serviceUUID); bool addServiceUUID(const char* serviceUUID); bool removeServiceUUID(const NimBLEUUID& serviceUUID); bool removeServiceUUID(const char* serviceUUID); bool removeServices(); bool setAppearance(uint16_t appearance); bool setPreferredParams(uint16_t minInterval, uint16_t maxInterval); bool addTxPower(); bool setName(const std::string& name); bool setManufacturerData(const uint8_t* data, size_t length); bool setManufacturerData(const std::string& data); bool setManufacturerData(const std::vector<uint8_t>& data); bool setURI(const std::string& uri); bool setServiceData(const NimBLEUUID& uuid, const uint8_t* data, size_t length); bool setServiceData(const NimBLEUUID& uuid, const std::string& data); bool setServiceData(const NimBLEUUID& uuid, const std::vector<uint8_t>& data); private: friend class NimBLEDevice; friend class NimBLEServer; void onHostSync(); static int handleGapEvent(ble_gap_event* event, void* arg); NimBLEAdvertisementData m_advData; NimBLEAdvertisementData m_scanData; ble_gap_adv_params m_advParams; advCompleteCB_t m_advCompCb; uint8_t m_slaveItvl[4]; uint32_t m_duration; bool m_scanResp : 1; bool m_advDataSet : 1; }; #endif // (CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_BROADCASTER && !CONFIG_BT_NIMBLE_EXT_ADV) || defined(_DOXYGEN_) #endif // NIMBLE_CPP_ADVERTISING_H_ /* * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and * esp-nimble-cpp, NimBLE-Arduino contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef NIMBLE_CPP_SERVER_H_ #define NIMBLE_CPP_SERVER_H_ #include "nimconfig.h" #if CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL # if defined(CONFIG_NIMBLE_CPP_IDF) # include "host/ble_gap.h" # else # include "nimble/nimble/host/include/host/ble_gap.h" # endif /**** FIX COMPILATION ****/ # undef min # undef max /**************************/ # include <vector> # include <array> # define NIMBLE_ATT_REMOVE_HIDE 1 # define NIMBLE_ATT_REMOVE_DELETE 2 class NimBLEService; class NimBLEServerCallbacks; class NimBLEUUID; class NimBLEConnInfo; class NimBLEAddress; class NimBLEService; class NimBLECharacteristic; # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV class NimBLEExtAdvertising; # else class NimBLEAdvertising; # endif # endif # if CONFIG_BT_NIMBLE_ROLE_CENTRAL class NimBLEClient; # endif /** * @brief The model of a BLE server. */ class NimBLEServer { public: void start(); uint8_t getConnectedCount() const; bool disconnect(uint16_t connHandle, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const; bool disconnect(const NimBLEConnInfo& connInfo, uint8_t reason = BLE_ERR_REM_USER_CONN_TERM) const; void setCallbacks(NimBLEServerCallbacks* pCallbacks, bool deleteCallbacks = true); void updateConnParams(uint16_t connHandle, uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout) const; NimBLEService* createService(const char* uuid); NimBLEService* createService(const NimBLEUUID& uuid); NimBLEService* getServiceByUUID(const char* uuid, uint16_t instanceId = 0) const; NimBLEService* getServiceByUUID(const NimBLEUUID& uuid, uint16_t instanceId = 0) const; NimBLEService* getServiceByHandle(uint16_t handle) const; void removeService(NimBLEService* service, bool deleteSvc = false); void addService(NimBLEService* service); uint16_t getPeerMTU(uint16_t connHandle) const; std::vector<uint16_t> getPeerDevices() const; NimBLEConnInfo getPeerInfo(uint8_t index) const; NimBLEConnInfo getPeerInfo(const NimBLEAddress& address) const; NimBLEConnInfo getPeerInfoByHandle(uint16_t connHandle) const; void advertiseOnDisconnect(bool enable); void setDataLen(uint16_t connHandle, uint16_t tx_octets) const; bool updatePhy(uint16_t connHandle, uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions); bool getPhy(uint16_t connHandle, uint8_t* txPhy, uint8_t* rxPhy); # if CONFIG_BT_NIMBLE_ROLE_CENTRAL NimBLEClient* getClient(uint16_t connHandle); NimBLEClient* getClient(const NimBLEConnInfo& connInfo); void deleteClient(); # endif # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV NimBLEExtAdvertising* getAdvertising() const; bool startAdvertising(uint8_t instanceId, int duration = 0, int maxEvents = 0) const; bool stopAdvertising(uint8_t instanceId) const; # endif # if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) NimBLEAdvertising* getAdvertising() const; bool startAdvertising(uint32_t duration = 0) const; bool stopAdvertising() const; # endif # endif private: friend class NimBLEDevice; friend class NimBLEService; friend class NimBLECharacteristic; # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV friend class NimBLEExtAdvertising; # else friend class NimBLEAdvertising; # endif # endif NimBLEServer(); ~NimBLEServer(); bool m_gattsStarted : 1; bool m_svcChanged : 1; bool m_deleteCallbacks : 1; # if !CONFIG_BT_NIMBLE_EXT_ADV bool m_advertiseOnDisconnect : 1; # endif NimBLEServerCallbacks* m_pServerCallbacks; std::vector<NimBLEService*> m_svcVec; std::array<uint16_t, CONFIG_BT_NIMBLE_MAX_CONNECTIONS> m_connectedPeers; # if CONFIG_BT_NIMBLE_ROLE_CENTRAL NimBLEClient* m_pClient{nullptr}; # endif static int handleGapEvent(struct ble_gap_event* event, void* arg); static int handleGattEvent(uint16_t connHandle, uint16_t attrHandle, ble_gatt_access_ctxt* ctxt, void* arg); void serviceChanged(); void resetGATT(); }; // NimBLEServer /** * @brief Callbacks associated with the operation of a BLE server. */ class NimBLEServerCallbacks { public: virtual ~NimBLEServerCallbacks() {}; /** * @brief Handle a client connection. * This is called when a client connects. * @param [in] pServer A pointer to the BLE server that received the client connection. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information. * about the peer connection parameters. */ virtual void onConnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo); /** * @brief Handle a client disconnection. * This is called when a client disconnects. * @param [in] pServer A pointer to the BLE server that received the client disconnection. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information * about the peer connection parameters. * @param [in] reason The reason code for the disconnection. */ virtual void onDisconnect(NimBLEServer* pServer, NimBLEConnInfo& connInfo, int reason); /** * @brief Called when the connection MTU changes. * @param [in] MTU The new MTU value. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information * about the peer connection parameters. */ virtual void onMTUChange(uint16_t MTU, NimBLEConnInfo& connInfo); /** * @brief Called when a client requests a passkey for pairing (display). * @return The passkey to be sent to the client. */ virtual uint32_t onPassKeyDisplay(); /** * @brief Called when using numeric comparision for pairing. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information * Should be passed back to NimBLEDevice::injectConfirmPasskey * @param [in] pin The pin to compare with the client. */ virtual void onConfirmPassKey(NimBLEConnInfo& connInfo, uint32_t pin); /** * @brief Called when the pairing procedure is complete. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information * about the peer connection parameters. */ virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo); /** * @brief Called when the peer identity address is resolved. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information */ virtual void onIdentity(NimBLEConnInfo& connInfo); /** * @brief Called when connection parameters are updated following a request to * update via NimBLEServer::updateConnParams * @param [in] connInfo A reference to a NimBLEConnInfo instance containing the * updated connection parameters. */ virtual void onConnParamsUpdate(NimBLEConnInfo& connInfo); /** * @brief Called when the PHY update procedure is complete. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information * about the peer connection parameters. * @param [in] txPhy The transmit PHY. * @param [in] rxPhy The receive PHY. * Possible values: * * BLE_GAP_LE_PHY_1M * * BLE_GAP_LE_PHY_2M * * BLE_GAP_LE_PHY_CODED */ virtual void onPhyUpdate(NimBLEConnInfo& connInfo, uint8_t txPhy, uint8_t rxPhy); }; // NimBLEServerCallbacks #endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_PERIPHERAL #endif // NIMBLE_CPP_SERVER_H_
最新发布
10-14
[{ "resource": "/e:/esp32/esp32_spi_slave_transfer_Prj (3)/src/BLE_master.cpp", "owner": "cpp", "severity": 8, "message": "'clearAllBonds' is not a member of 'NimBLEDevice'", "startLineNumber": 21, "startColumn": 19, "endLineNumber": 21, "endColumn": 19 },{ "resource": "/e:/esp32/esp32_spi_slave_transfer_Prj (3)/src/BLE_master.cpp", "owner": "cpp", "severity": 8, "message": "'class NimBLEClient' has no member named 'setConnParams'; did you mean 'm_connParams'?", "startLineNumber": 48, "startColumn": 18, "endLineNumber": 48, "endColumn": 18 }] /* * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and * esp-nimble-cpp, NimBLE-Arduino contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef NIMBLE_CPP_DEVICE_H_ #define NIMBLE_CPP_DEVICE_H_ #include "nimconfig.h" #if CONFIG_BT_ENABLED # ifdef ESP_PLATFORM # ifndef CONFIG_IDF_TARGET_ESP32P4 # include <esp_bt.h> # endif # endif # if defined(CONFIG_NIMBLE_CPP_IDF) # include <host/ble_gap.h> # else # include <nimble/nimble/host/include/host/ble_gap.h> # endif /**** FIX COMPILATION ****/ # undef min # undef max /**************************/ # include <string> # include <vector> # if CONFIG_BT_NIMBLE_ROLE_CENTRAL # include <array> class NimBLEClient; # endif # if CONFIG_BT_NIMBLE_ROLE_OBSERVER class NimBLEScan; # endif # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV class NimBLEExtAdvertising; # else class NimBLEAdvertising; # endif # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL class NimBLEServer; # if CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM > 0 class NimBLEL2CAPServer; # endif # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL || CONFIG_BT_NIMBLE_ROLE_CENTRAL class NimBLEConnInfo; # endif class NimBLEAddress; class NimBLEDeviceCallbacks; # define BLEDevice NimBLEDevice # define BLEClient NimBLEClient # define BLERemoteService NimBLERemoteService # define BLERemoteCharacteristic NimBLERemoteCharacteristic # define BLERemoteDescriptor NimBLERemoteDescriptor # define BLEAdvertisedDevice NimBLEAdvertisedDevice # define BLEScan NimBLEScan # define BLEUUID NimBLEUUID # define BLEAddress NimBLEAddress # define BLEUtils NimBLEUtils # define BLEClientCallbacks NimBLEClientCallbacks # define BLEAdvertisedDeviceCallbacks NimBLEScanCallbacks # define BLEScanResults NimBLEScanResults # define BLEServer NimBLEServer # define BLEService NimBLEService # define BLECharacteristic NimBLECharacteristic # define BLEAdvertising NimBLEAdvertising # define BLEServerCallbacks NimBLEServerCallbacks # define BLECharacteristicCallbacks NimBLECharacteristicCallbacks # define BLEAdvertisementData NimBLEAdvertisementData # define BLEDescriptor NimBLEDescriptor # define BLE2904 NimBLE2904 # define BLEDescriptorCallbacks NimBLEDescriptorCallbacks # define BLEBeacon NimBLEBeacon # define BLEEddystoneTLM NimBLEEddystoneTLM # define BLEEddystoneURL NimBLEEddystoneURL # define BLEConnInfo NimBLEConnInfo # define BLEL2CAPServer NimBLEL2CAPServer # define BLEL2CAPService NimBLEL2CAPService # define BLEL2CAPServiceCallbacks NimBLEL2CAPServiceCallbacks # define BLEL2CAPClient NimBLEL2CAPClient # define BLEL2CAPClientCallbacks NimBLEL2CAPClientCallbacks # define BLEL2CAPChannel NimBLEL2CAPChannel # define BLEL2CAPChannelCallbacks NimBLEL2CAPChannelCallbacks # ifdef CONFIG_BT_NIMBLE_MAX_CONNECTIONS # define NIMBLE_MAX_CONNECTIONS CONFIG_BT_NIMBLE_MAX_CONNECTIONS # else # define NIMBLE_MAX_CONNECTIONS CONFIG_NIMBLE_MAX_CONNECTIONS # endif enum class NimBLETxPowerType { All = 0, Advertise = 1, Scan = 2, Connection = 3 }; typedef int (*gap_event_handler)(ble_gap_event* event, void* arg); /** * @brief A model of a BLE Device from which all the BLE roles are created. */ class NimBLEDevice { public: static bool init(const std::string& deviceName); static bool deinit(bool clearAll = false); static bool setDeviceName(const std::string& deviceName); static bool isInitialized(); static NimBLEAddress getAddress(); static std::string toString(); static bool whiteListAdd(const NimBLEAddress& address); static bool whiteListRemove(const NimBLEAddress& address); static bool onWhiteList(const NimBLEAddress& address); static size_t getWhiteListCount(); static NimBLEAddress getWhiteListAddress(size_t index); static bool setOwnAddrType(uint8_t type); static bool setOwnAddr(const NimBLEAddress& addr); static bool setOwnAddr(const uint8_t* addr); static void setDeviceCallbacks(NimBLEDeviceCallbacks* cb); static void setScanDuplicateCacheSize(uint16_t cacheSize); static void setScanFilterMode(uint8_t type); static void setScanDuplicateCacheResetTime(uint16_t time); static bool setCustomGapHandler(gap_event_handler handler); static void setSecurityAuth(bool bonding, bool mitm, bool sc); static void setSecurityAuth(uint8_t auth); static void setSecurityIOCap(uint8_t iocap); static void setSecurityInitKey(uint8_t initKey); static void setSecurityRespKey(uint8_t respKey); static void setSecurityPasskey(uint32_t passKey); static uint32_t getSecurityPasskey(); static bool startSecurity(uint16_t connHandle, int* rcPtr = nullptr); static bool setMTU(uint16_t mtu); static uint16_t getMTU(); static void onReset(int reason); static void onSync(void); static void host_task(void* param); static int getPower(NimBLETxPowerType type = NimBLETxPowerType::All); static bool setPower(int8_t dbm, NimBLETxPowerType type = NimBLETxPowerType::All); static bool setDefaultPhy(uint8_t txPhyMask, uint8_t rxPhyMask); # ifdef ESP_PLATFORM # ifndef CONFIG_IDF_TARGET_ESP32P4 static esp_power_level_t getPowerLevel(esp_ble_power_type_t powerType = ESP_BLE_PWR_TYPE_DEFAULT); static bool setPowerLevel(esp_power_level_t powerLevel, esp_ble_power_type_t powerType = ESP_BLE_PWR_TYPE_DEFAULT); # endif # endif # if CONFIG_BT_NIMBLE_ROLE_OBSERVER static NimBLEScan* getScan(); # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL static NimBLEServer* createServer(); static NimBLEServer* getServer(); # if CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM > 0 static NimBLEL2CAPServer* createL2CAPServer(); static NimBLEL2CAPServer* getL2CAPServer(); # endif # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL || CONFIG_BT_NIMBLE_ROLE_CENTRAL static bool injectConfirmPasskey(const NimBLEConnInfo& peerInfo, bool accept); static bool injectPassKey(const NimBLEConnInfo& peerInfo, uint32_t pin); # endif # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV static NimBLEExtAdvertising* getAdvertising(); static bool startAdvertising(uint8_t instId, int duration = 0, int maxEvents = 0); static bool stopAdvertising(uint8_t instId); static bool stopAdvertising(); # endif # if !CONFIG_BT_NIMBLE_EXT_ADV || defined(_DOXYGEN_) static NimBLEAdvertising* getAdvertising(); static bool startAdvertising(uint32_t duration = 0); static bool stopAdvertising(); # endif # endif # if CONFIG_BT_NIMBLE_ROLE_CENTRAL static NimBLEClient* createClient(); static NimBLEClient* createClient(const NimBLEAddress& peerAddress); static bool deleteClient(NimBLEClient* pClient); static NimBLEClient* getClientByHandle(uint16_t connHandle); static NimBLEClient* getClientByPeerAddress(const NimBLEAddress& peerAddress); static NimBLEClient* getDisconnectedClient(); static size_t getCreatedClientCount(); static std::vector<NimBLEClient*> getConnectedClients(); # endif # if CONFIG_BT_NIMBLE_ROLE_CENTRAL || CONFIG_BT_NIMBLE_ROLE_PERIPHERAL static bool deleteBond(const NimBLEAddress& address); static int getNumBonds(); static bool isBonded(const NimBLEAddress& address); static bool deleteAllBonds(); static NimBLEAddress getBondedAddress(int index); # endif private: static bool m_synced; static bool m_initialized; static uint32_t m_passkey; static ble_gap_event_listener m_listener; static uint8_t m_ownAddrType; static std::vector<NimBLEAddress> m_whiteList; static NimBLEDeviceCallbacks* m_pDeviceCallbacks; static NimBLEDeviceCallbacks defaultDeviceCallbacks; # if CONFIG_BT_NIMBLE_ROLE_OBSERVER static NimBLEScan* m_pScan; # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL static NimBLEServer* m_pServer; # if CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM > 0 static NimBLEL2CAPServer* m_pL2CAPServer; # endif # endif # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV static NimBLEExtAdvertising* m_bleAdvertising; # else static NimBLEAdvertising* m_bleAdvertising; # endif # endif # if CONFIG_BT_NIMBLE_ROLE_CENTRAL static std::array<NimBLEClient*, NIMBLE_MAX_CONNECTIONS> m_pClients; # endif # ifdef ESP_PLATFORM # if CONFIG_BTDM_BLE_SCAN_DUPL || CONFIG_BT_LE_SCAN_DUPL static uint16_t m_scanDuplicateSize; static uint8_t m_scanFilterMode; static uint16_t m_scanDuplicateResetTime; # endif # endif # if CONFIG_BT_NIMBLE_ROLE_CENTRAL friend class NimBLEClient; # endif # if CONFIG_BT_NIMBLE_ROLE_OBSERVER friend class NimBLEScan; # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL friend class NimBLEServer; friend class NimBLECharacteristic; # endif # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER friend class NimBLEAdvertising; # if CONFIG_BT_NIMBLE_EXT_ADV friend class NimBLEExtAdvertising; friend class NimBLEExtAdvertisement; # endif # endif }; # if CONFIG_BT_NIMBLE_ROLE_CENTRAL # include "NimBLEClient.h" # include "NimBLERemoteService.h" # include "NimBLERemoteCharacteristic.h" # include "NimBLERemoteDescriptor.h" # endif # if CONFIG_BT_NIMBLE_ROLE_OBSERVER # include "NimBLEScan.h" # endif # if CONFIG_BT_NIMBLE_ROLE_PERIPHERAL # include "NimBLEServer.h" # include "NimBLEService.h" # include "NimBLECharacteristic.h" # include "NimBLEDescriptor.h" # if CONFIG_BT_NIMBLE_L2CAP_COC_MAX_NUM # include "NimBLEL2CAPServer.h" # include "NimBLEL2CAPChannel.h" # endif # endif # if CONFIG_BT_NIMBLE_ROLE_BROADCASTER # if CONFIG_BT_NIMBLE_EXT_ADV # include "NimBLEExtAdvertising.h" # else # include "NimBLEAdvertising.h" # endif # endif # if CONFIG_BT_NIMBLE_ROLE_CENTRAL || CONFIG_BT_NIMBLE_ROLE_PERIPHERAL # include "NimBLEConnInfo.h" # endif # include "NimBLEAddress.h" # include "NimBLEUtils.h" /** * @brief Callbacks associated with a BLE device. */ class NimBLEDeviceCallbacks { public: virtual ~NimBLEDeviceCallbacks() {}; /** * @brief Indicates an inability to perform a store operation. * This callback should do one of two things: * -Address the problem and return 0, indicating that the store operation * should proceed. * -Return nonzero to indicate that the store operation should be aborted. * @param event Describes the store event being reported. * BLE_STORE_EVENT_FULL; or * BLE_STORE_EVENT_OVERFLOW * @return 0 if the store operation should proceed; * nonzero if the store operation should be aborted. */ virtual int onStoreStatus(struct ble_store_status_event* event, void* arg); }; #endif // CONFIG_BT_ENABLED #endif // NIMBLE_CPP_DEVICE_H_ /* * Copyright 2020-2025 Ryan Powell <ryan@nable-embedded.io> and * esp-nimble-cpp, NimBLE-Arduino contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef NIMBLE_CPP_CLIENT_H_ #define NIMBLE_CPP_CLIENT_H_ #include "nimconfig.h" #if CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL # if defined(CONFIG_NIMBLE_CPP_IDF) # include "host/ble_gap.h" # else # include "nimble/nimble/host/include/host/ble_gap.h" # endif # include "NimBLEAddress.h" # include <stdint.h> # include <vector> # include <string> class NimBLEAddress; class NimBLEUUID; class NimBLERemoteService; class NimBLERemoteCharacteristic; class NimBLEAdvertisedDevice; class NimBLEAttValue; class NimBLEClientCallbacks; class NimBLEConnInfo; struct NimBLETaskData; /** * @brief A model of a BLE client. */ class NimBLEClient { public: # if CONFIG_BT_NIMBLE_ROLE_OBSERVER bool connect(const NimBLEAdvertisedDevice* device, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true); # endif bool connect(const NimBLEAddress& address, bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true); bool connect(bool deleteAttributes = true, bool asyncConnect = false, bool exchangeMTU = true); bool disconnect(uint8_t reason = BLE_ERR_REM_USER_CONN_TERM); bool cancelConnect() const; void setSelfDelete(bool deleteOnDisconnect, bool deleteOnConnectFail); NimBLEAddress getPeerAddress() const; bool setPeerAddress(const NimBLEAddress& address); int getRssi() const; bool isConnected() const; void setClientCallbacks(NimBLEClientCallbacks* pClientCallbacks, bool deleteCallbacks = true); std::string toString() const; uint16_t getConnHandle() const; uint16_t getMTU() const; bool exchangeMTU(); bool secureConnection(bool async = false) const; void setConnectTimeout(uint32_t timeout); bool setDataLen(uint16_t txOctets); bool discoverAttributes(); NimBLEConnInfo getConnInfo() const; int getLastError() const; bool updateConnParams(uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout); void setConnectionParams(uint16_t minInterval, uint16_t maxInterval, uint16_t latency, uint16_t timeout, uint16_t scanInterval = 16, uint16_t scanWindow = 16); const std::vector<NimBLERemoteService*>& getServices(bool refresh = false); std::vector<NimBLERemoteService*>::iterator begin(); std::vector<NimBLERemoteService*>::iterator end(); NimBLERemoteCharacteristic* getCharacteristic(uint16_t handle); NimBLERemoteService* getService(const char* uuid); NimBLERemoteService* getService(const NimBLEUUID& uuid); void deleteServices(); size_t deleteService(const NimBLEUUID& uuid); NimBLEAttValue getValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID); bool setValue(const NimBLEUUID& serviceUUID, const NimBLEUUID& characteristicUUID, const NimBLEAttValue& value, bool response = false); # if CONFIG_BT_NIMBLE_EXT_ADV void setConnectPhy(uint8_t phyMask); # endif bool updatePhy(uint8_t txPhysMask, uint8_t rxPhysMask, uint16_t phyOptions = 0); bool getPhy(uint8_t* txPhy, uint8_t* rxPhy); struct Config { uint8_t deleteCallbacks : 1; // Delete the callback object when the client is deleted. uint8_t deleteOnDisconnect : 1; // Delete the client when disconnected. uint8_t deleteOnConnectFail : 1; // Delete the client when a connection attempt fails. uint8_t asyncConnect : 1; // Connect asynchronously. uint8_t exchangeMTU : 1; // Exchange MTU after connection. }; Config getConfig() const; void setConfig(Config config); private: NimBLEClient(const NimBLEAddress& peerAddress); ~NimBLEClient(); NimBLEClient(const NimBLEClient&) = delete; NimBLEClient& operator=(const NimBLEClient&) = delete; bool retrieveServices(const NimBLEUUID* uuidFilter = nullptr); static int handleGapEvent(struct ble_gap_event* event, void* arg); static int exchangeMTUCb(uint16_t conn_handle, const ble_gatt_error* error, uint16_t mtu, void* arg); static int serviceDiscoveredCB(uint16_t connHandle, const struct ble_gatt_error* error, const struct ble_gatt_svc* service, void* arg); NimBLEAddress m_peerAddress; mutable int m_lastErr; int32_t m_connectTimeout; mutable NimBLETaskData* m_pTaskData; std::vector<NimBLERemoteService*> m_svcVec; NimBLEClientCallbacks* m_pClientCallbacks; uint16_t m_connHandle; uint8_t m_terminateFailCount; mutable uint8_t m_asyncSecureAttempt; Config m_config; # if CONFIG_BT_NIMBLE_EXT_ADV uint8_t m_phyMask; # endif ble_gap_conn_params m_connParams; friend class NimBLEDevice; friend class NimBLEServer; }; // class NimBLEClient /** * @brief Callbacks associated with a %BLE client. */ class NimBLEClientCallbacks { public: virtual ~NimBLEClientCallbacks() {}; /** * @brief Called after client connects. * @param [in] pClient A pointer to the connecting client object. */ virtual void onConnect(NimBLEClient* pClient); /** * @brief Called when a connection attempt fails. * @param [in] pClient A pointer to the connecting client object. * @param [in] reason Contains the reason code for the connection failure. */ virtual void onConnectFail(NimBLEClient* pClient, int reason); /** * @brief Called when disconnected from the server. * @param [in] pClient A pointer to the calling client object. * @param [in] reason Contains the reason code for the disconnection. */ virtual void onDisconnect(NimBLEClient* pClient, int reason); /** * @brief Called when server requests to update the connection parameters. * @param [in] pClient A pointer to the calling client object. * @param [in] params A pointer to the struct containing the connection parameters requested. * @return True to accept the parameters. */ virtual bool onConnParamsUpdateRequest(NimBLEClient* pClient, const ble_gap_upd_params* params); /** * @brief Called when server requests a passkey for pairing. * @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info. */ virtual void onPassKeyEntry(NimBLEConnInfo& connInfo); /** * @brief Called when the pairing procedure is complete. * @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info.\n * This can be used to check the status of the connection encryption/pairing. */ virtual void onAuthenticationComplete(NimBLEConnInfo& connInfo); /** * @brief Called when using numeric comparision for pairing. * @param [in] connInfo A reference to a NimBLEConnInfo instance containing the peer info. * @param [in] pin The pin to compare with the server. */ virtual void onConfirmPasskey(NimBLEConnInfo& connInfo, uint32_t pin); /** * @brief Called when the peer identity address is resolved. * @param [in] connInfo A reference to a NimBLEConnInfo instance with information */ virtual void onIdentity(NimBLEConnInfo& connInfo); /** * @brief Called when the connection MTU changes. * @param [in] pClient A pointer to the client that the MTU change is associated with. * @param [in] MTU The new MTU value. * about the peer connection parameters. */ virtual void onMTUChange(NimBLEClient* pClient, uint16_t MTU); /** * @brief Called when the PHY update procedure is complete. * @param [in] pClient A pointer to the client whose PHY was updated. * about the peer connection parameters. * @param [in] txPhy The transmit PHY. * @param [in] rxPhy The receive PHY. * Possible values: * * BLE_GAP_LE_PHY_1M * * BLE_GAP_LE_PHY_2M * * BLE_GAP_LE_PHY_CODED */ virtual void onPhyUpdate(NimBLEClient* pClient, uint8_t txPhy, uint8_t rxPhy); }; #endif // CONFIG_BT_ENABLED && CONFIG_BT_NIMBLE_ROLE_CENTRAL #endif // NIMBLE_CPP_CLIENT_H_
10-12
#pragma once #include "SERializableClassTest.h" #include <QJsonObject> #include <QJsonDocument> #include "MTFDataDefine.h" #include <QCoreApplication> #include <QDebug> #include "LogTools.h" extern Loger m_gLog; class ConfigItem : public SerializableAssist { Q_OBJECT Q_PROPERTY(QString Alias MEMBER m_alias) Q_PROPERTY(QString Description MEMBER m_description) Q_PROPERTY(QString Value MEMBER m_value) public: explicit ConfigItem(QObject* parent = nullptr) : SerializableAssist(parent) {} // 添加 bool 值转换方法 bool toBool() const { return stringToBool(m_value); } void setValue(bool value) { m_value = value ? "true" : "false"; } // 安全的字符串到 bool 转换 static bool stringToBool(const QString& str) { QString cleanStr = str.trimmed().toLower(); if (cleanStr == "true" || cleanStr == "1" || cleanStr == "on" || cleanStr == "yes") { return true; } if (cleanStr == "false" || cleanStr == "0" || cleanStr == "off" || cleanStr == "no") { return false; } qWarning() << "Invalid boolean string:" << str << "Using default value (false)"; return false; } public: QString m_alias; QString m_description; QString m_value; }; // 基础树形结构类 class BasicTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* Time MEMBER m_time) Q_PROPERTY(ConfigItem* TrayName MEMBER m_trayName) Q_PROPERTY(ConfigItem* ConfigFile MEMBER m_configFile) Q_PROPERTY(ConfigItem* ThroughFocusData MEMBER m_throughFocusData) Q_PROPERTY(ConfigItem* Position MEMBER m_position) Q_PROPERTY(ConfigItem* DriverPos MEMBER m_driverPos) Q_PROPERTY(ConfigItem* Defocus MEMBER m_defocus) public: explicit BasicTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } // 深拷贝构造函数 BasicTree(const BasicTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } BasicTree& operator=(const BasicTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~BasicTree() { clearItems(); } private: void initItems() { m_time = new ConfigItem(this); m_trayName = new ConfigItem(this); m_configFile = new ConfigItem(this); m_throughFocusData = new ConfigItem(this); m_position = new ConfigItem(this); m_driverPos = new ConfigItem(this); m_defocus = new ConfigItem(this); } void clearItems() { // 对象由父对象管理,不需要手动删除 } void copyFrom(const BasicTree& other) { m_time->m_value = other.m_time->m_value; m_trayName->m_value = other.m_trayName->m_value; m_configFile->m_value = other.m_configFile->m_value; m_throughFocusData->m_value = other.m_throughFocusData->m_value; m_position->m_value = other.m_position->m_value; m_driverPos->m_value = other.m_driverPos->m_value; m_defocus->m_value = other.m_defocus->m_value; } public: ConfigItem* m_configFile; ConfigItem* m_defocus; ConfigItem* m_driverPos; ConfigItem* m_position; ConfigItem* m_throughFocusData; ConfigItem* m_time; ConfigItem* m_trayName; }; // 结果树形结构类 class ResultTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* Final MEMBER m_final) Q_PROPERTY(ConfigItem* MTF MEMBER m_mtf) Q_PROPERTY(ConfigItem* DOF MEMBER m_dof) Q_PROPERTY(ConfigItem* FocalShift MEMBER m_focalShift) Q_PROPERTY(ConfigItem* Astigmatism MEMBER m_astigmatism) Q_PROPERTY(ConfigItem* FOV MEMBER m_fov) Q_PROPERTY(ConfigItem* Average MEMBER m_average) Q_PROPERTY(ConfigItem* Aggregate MEMBER m_aggregate) Q_PROPERTY(ConfigItem* MultiFrqMTF MEMBER m_multiFrqMtf) Q_PROPERTY(ConfigItem* Defocus MEMBER m_defocus) Q_PROPERTY(ConfigItem* FailReason MEMBER m_failReason) public: explicit ResultTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } ResultTree(const ResultTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } ResultTree& operator=(const ResultTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~ResultTree() { clearItems(); } private: void initItems() { m_final = new ConfigItem(this); m_mtf = new ConfigItem(this); m_dof = new ConfigItem(this); m_focalShift = new ConfigItem(this); m_astigmatism = new ConfigItem(this); m_fov = new ConfigItem(this); m_average = new ConfigItem(this); m_aggregate = new ConfigItem(this); m_multiFrqMtf = new ConfigItem(this); m_defocus = new ConfigItem(this); m_failReason = new ConfigItem(this); } void clearItems() { // 对象由父对象管理 } void copyFrom(const ResultTree& other) { m_final->m_value = other.m_final->m_value; m_mtf->m_value = other.m_mtf->m_value; m_dof->m_value = other.m_dof->m_value; m_focalShift->m_value = other.m_focalShift->m_value; m_astigmatism->m_value = other.m_astigmatism->m_value; m_fov->m_value = other.m_fov->m_value; m_average->m_value = other.m_average->m_value; m_aggregate->m_value = other.m_aggregate->m_value; m_multiFrqMtf->m_value = other.m_multiFrqMtf->m_value; m_defocus->m_value = other.m_defocus->m_value; m_failReason->m_value = other.m_failReason->m_value; } public: ConfigItem* m_final; ConfigItem* m_mtf; ConfigItem* m_dof; ConfigItem* m_focalShift; ConfigItem* m_astigmatism; ConfigItem* m_fov; ConfigItem* m_average; ConfigItem* m_aggregate; ConfigItem* m_multiFrqMtf; ConfigItem* m_defocus; ConfigItem* m_failReason; }; // 倾斜树形结构类 class TiltTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* Azimuth MEMBER m_azimuth) Q_PROPERTY(ConfigItem* Angle MEMBER m_angle) Q_PROPERTY(ConfigItem* Type MEMBER m_type) public: explicit TiltTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } TiltTree(const TiltTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } TiltTree& operator=(const TiltTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~TiltTree() { clearItems(); } private: void initItems() { m_azimuth = new ConfigItem(this); m_angle = new ConfigItem(this); m_type = new ConfigItem(this); } void clearItems() { // 对象由父对象管理 } void copyFrom(const TiltTree& other) { m_azimuth->m_value = other.m_azimuth->m_value; m_angle->m_value = other.m_angle->m_value; m_type->m_value = other.m_type->m_value; } public: ConfigItem* m_azimuth; ConfigItem* m_angle; ConfigItem* m_type; }; // 焦点偏移数据树 class FocalShiftDataTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* Negative MEMBER m_negative) Q_PROPERTY(ConfigItem* Positive MEMBER m_positive) Q_PROPERTY(ConfigItem* Group MEMBER m_group) Q_PROPERTY(ConfigItem* Cameras MEMBER m_cameras) public: explicit FocalShiftDataTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } FocalShiftDataTree(const FocalShiftDataTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } FocalShiftDataTree& operator=(const FocalShiftDataTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~FocalShiftDataTree() { clearItems(); } private: void initItems() { m_negative = new ConfigItem(this); m_positive = new ConfigItem(this); m_group = new ConfigItem(this); m_cameras = new ConfigItem(this); } void clearItems() { // 对象由父对象管理 } void copyFrom(const FocalShiftDataTree& other) { m_negative->m_value = other.m_negative->m_value; m_positive->m_value = other.m_positive->m_value; m_group->m_value = other.m_group->m_value; m_cameras->m_value = other.m_cameras->m_value; } public: ConfigItem* m_negative; ConfigItem* m_positive; ConfigItem* m_group; ConfigItem* m_cameras; }; // 景深数据树 class DOFDataTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* DOF MEMBER m_dof) Q_PROPERTY(ConfigItem* Minus MEMBER m_minus) Q_PROPERTY(ConfigItem* Plus MEMBER m_plus) Q_PROPERTY(ConfigItem* Cameras MEMBER m_cameras) Q_PROPERTY(ConfigItem* Group MEMBER m_group) public: explicit DOFDataTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } DOFDataTree(const DOFDataTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } DOFDataTree& operator=(const DOFDataTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~DOFDataTree() { clearItems(); } private: void initItems() { m_dof = new ConfigItem(this); m_minus = new ConfigItem(this); m_plus = new ConfigItem(this); m_cameras = new ConfigItem(this); m_group = new ConfigItem(this); } void clearItems() { // 对象由父对象管理 } void copyFrom(const DOFDataTree& other) { m_dof->m_value = other.m_dof->m_value; m_minus->m_value = other.m_minus->m_value; m_plus->m_value = other.m_plus->m_value; m_cameras->m_value = other.m_cameras->m_value; m_group->m_value = other.m_group->m_value; } public: ConfigItem* m_dof; ConfigItem* m_minus; ConfigItem* m_plus; ConfigItem* m_cameras; ConfigItem* m_group; }; // A2景深数据树 class A2DOFDataTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* A2DOF MEMBER m_a2dof) Q_PROPERTY(ConfigItem* Minus MEMBER m_minus) Q_PROPERTY(ConfigItem* Plus MEMBER m_plus) Q_PROPERTY(ConfigItem* OnAxis MEMBER m_onAxis) Q_PROPERTY(ConfigItem* OffAxis MEMBER m_offAxis) Q_PROPERTY(ConfigItem* A2DOFAvg MEMBER m_a2dofAvg) Q_PROPERTY(ConfigItem* AvgMinus MEMBER m_avgMinus) Q_PROPERTY(ConfigItem* AvgPlus MEMBER m_avgPlus) Q_PROPERTY(ConfigItem* OnAxisAvg MEMBER m_onAxisAvg) Q_PROPERTY(ConfigItem* OffAxisAvg MEMBER m_offAxisAvg) public: explicit A2DOFDataTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } A2DOFDataTree(const A2DOFDataTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } A2DOFDataTree& operator=(const A2DOFDataTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~A2DOFDataTree() { clearItems(); } private: void initItems() { m_a2dof = new ConfigItem(this); m_minus = new ConfigItem(this); m_plus = new ConfigItem(this); m_onAxis = new ConfigItem(this); m_offAxis = new ConfigItem(this); m_a2dofAvg = new ConfigItem(this); m_avgMinus = new ConfigItem(this); m_avgPlus = new ConfigItem(this); m_onAxisAvg = new ConfigItem(this); m_offAxisAvg = new ConfigItem(this); } void clearItems() { // 对象由父对象管理 } void copyFrom(const A2DOFDataTree& other) { m_a2dof->m_value = other.m_a2dof->m_value; m_minus->m_value = other.m_minus->m_value; m_plus->m_value = other.m_plus->m_value; m_onAxis->m_value = other.m_onAxis->m_value; m_offAxis->m_value = other.m_offAxis->m_value; m_a2dofAvg->m_value = other.m_a2dofAvg->m_value; m_avgMinus->m_value = other.m_avgMinus->m_value; m_avgPlus->m_value = other.m_avgPlus->m_value; m_onAxisAvg->m_value = other.m_onAxisAvg->m_value; m_offAxisAvg->m_value = other.m_offAxisAvg->m_value; } public: ConfigItem* m_a2dof; ConfigItem* m_minus; ConfigItem* m_plus; ConfigItem* m_onAxis; ConfigItem* m_offAxis; ConfigItem* m_a2dofAvg; ConfigItem* m_avgMinus; ConfigItem* m_avgPlus; ConfigItem* m_onAxisAvg; ConfigItem* m_offAxisAvg; }; // 标准树形结构 class NormaltTree : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* EFL MEMBER m_efl) Q_PROPERTY(ConfigItem* FFL MEMBER m_ffl) Q_PROPERTY(ConfigItem* MTF MEMBER m_mtf) Q_PROPERTY(ConfigItem* MultiFrqMTF MEMBER m_multiFrqMtf) Q_PROPERTY(ConfigItem* MTFPeaks MEMBER m_mtfPeaks) Q_PROPERTY(ConfigItem* HalfFOV MEMBER m_halfFov) Q_PROPERTY(ConfigItem* FullFOV MEMBER m_fullFov) Q_PROPERTY(TiltTree* Tilt MEMBER m_tilt) Q_PROPERTY(FocalShiftDataTree* FocalShift MEMBER m_focalShift) Q_PROPERTY(ConfigItem* Astigmatism MEMBER m_astigmatism) Q_PROPERTY(ConfigItem* LSFPeaks MEMBER m_lsfPeaks) Q_PROPERTY(DOFDataTree* DOF MEMBER m_dof) Q_PROPERTY(A2DOFDataTree* A2DOF MEMBER m_a2dof) Q_PROPERTY(ConfigItem* SymmetricalGroupMTF MEMBER m_symmetricalGroupMtf) Q_PROPERTY(ConfigItem* SymmetricalFieldMTF MEMBER m_symmetricalFieldMtf) Q_PROPERTY(ConfigItem* MTFAverageAllCameras MEMBER m_mtfAverageAllCameras) Q_PROPERTY(ConfigItem* FieldPositionMTF MEMBER m_fieldPositionMtf) Q_PROPERTY(ConfigItem* FocalShiftSingle MEMBER m_focalShiftSingle) Q_PROPERTY(ConfigItem* FocalShiftGroup MEMBER m_focalShiftGroup) Q_PROPERTY(ConfigItem* FocalShiftAverage MEMBER m_focalShiftAverage) Q_PROPERTY(ConfigItem* PeakRange MEMBER m_peakRange) Q_PROPERTY(ConfigItem* PeakMTF MEMBER m_peakMtf) Q_PROPERTY(ConfigItem* PeakMTFAverage MEMBER m_peakMtfAverage) Q_PROPERTY(ConfigItem* MTFRatio MEMBER m_mtfRatio) public: NormaltTree(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } NormaltTree(const NormaltTree& other, QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); copyFrom(other); } NormaltTree& operator=(const NormaltTree& other) { if (this != &other) { copyFrom(other); } return *this; } ~NormaltTree() { clearItems(); } private: void initItems() { m_efl = new ConfigItem(this); m_ffl = new ConfigItem(this); m_mtf = new ConfigItem(this); m_multiFrqMtf = new ConfigItem(this); m_mtfPeaks = new ConfigItem(this); m_halfFov = new ConfigItem(this); m_fullFov = new ConfigItem(this); m_tilt = new TiltTree(this); m_focalShift = new FocalShiftDataTree(this); m_astigmatism = new ConfigItem(this); m_lsfPeaks = new ConfigItem(this); m_dof = new DOFDataTree(this); m_a2dof = new A2DOFDataTree(this); m_symmetricalGroupMtf = new ConfigItem(this); m_symmetricalFieldMtf = new ConfigItem(this); m_mtfAverageAllCameras = new ConfigItem(this); m_fieldPositionMtf = new ConfigItem(this); m_focalShiftSingle = new ConfigItem(this); m_focalShiftGroup = new ConfigItem(this); m_focalShiftAverage = new ConfigItem(this); m_peakRange = new ConfigItem(this); m_peakMtf = new ConfigItem(this); m_peakMtfAverage = new ConfigItem(this); m_mtfRatio = new ConfigItem(this); } void clearItems() { // 所有对象由父对象管理 } void copyFrom(const NormaltTree& other) { // 复制所有简单值 m_efl->m_value = other.m_efl->m_value; m_ffl->m_value = other.m_ffl->m_value; m_mtf->m_value = other.m_mtf->m_value; m_multiFrqMtf->m_value = other.m_multiFrqMtf->m_value; m_mtfPeaks->m_value = other.m_mtfPeaks->m_value; m_halfFov->m_value = other.m_halfFov->m_value; m_fullFov->m_value = other.m_fullFov->m_value; m_astigmatism->m_value = other.m_astigmatism->m_value; m_lsfPeaks->m_value = other.m_lsfPeaks->m_value; m_symmetricalGroupMtf->m_value = other.m_symmetricalGroupMtf->m_value; m_symmetricalFieldMtf->m_value = other.m_symmetricalFieldMtf->m_value; m_mtfAverageAllCameras->m_value = other.m_mtfAverageAllCameras->m_value; m_fieldPositionMtf->m_value = other.m_fieldPositionMtf->m_value; m_focalShiftSingle->m_value = other.m_focalShiftSingle->m_value; m_focalShiftGroup->m_value = other.m_focalShiftGroup->m_value; m_focalShiftAverage->m_value = other.m_focalShiftAverage->m_value; m_peakRange->m_value = other.m_peakRange->m_value; m_peakMtf->m_value = other.m_peakMtf->m_value; m_peakMtfAverage->m_value = other.m_peakMtfAverage->m_value; m_mtfRatio->m_value = other.m_mtfRatio->m_value; // 复制嵌套对象 *m_tilt = *other.m_tilt; *m_focalShift = *other.m_focalShift; *m_dof = *other.m_dof; *m_a2dof = *other.m_a2dof; } public: ConfigItem* m_efl; ConfigItem* m_ffl; ConfigItem* m_mtf; ConfigItem* m_multiFrqMtf; ConfigItem* m_mtfPeaks; ConfigItem* m_halfFov; ConfigItem* m_fullFov; TiltTree* m_tilt; FocalShiftDataTree* m_focalShift; ConfigItem* m_astigmatism; ConfigItem* m_lsfPeaks; DOFDataTree* m_dof; A2DOFDataTree* m_a2dof; ConfigItem* m_symmetricalGroupMtf; ConfigItem* m_symmetricalFieldMtf; ConfigItem* m_mtfAverageAllCameras; ConfigItem* m_fieldPositionMtf; ConfigItem* m_focalShiftSingle; ConfigItem* m_focalShiftGroup; ConfigItem* m_focalShiftAverage; ConfigItem* m_peakRange; ConfigItem* m_peakMtf; ConfigItem* m_peakMtfAverage; ConfigItem* m_mtfRatio; }; // 配置文件项类 class ConfigFileItem : public SerializableAssist { Q_OBJECT Q_PROPERTY(ConfigItem* Barcode MEMBER m_barcode) Q_PROPERTY(ConfigItem* CameraCounts MEMBER m_cameraCounts) Q_PROPERTY(ConfigItem* GroupDefine MEMBER m_groupDefine) Q_PROPERTY(BasicTree* Basic MEMBER m_basic) Q_PROPERTY(ResultTree* Result MEMBER m_result) Q_PROPERTY(NormaltTree* Normal MEMBER m_normal) Q_PROPERTY(ConfigItem* Defocus MEMBER m_defocus) public: ConfigFileItem(QObject* parent = nullptr) : SerializableAssist(parent) { initItems(); } ConfigFileItem(const ConfigFileItem& other) : SerializableAssist(other.parent()) { initItems(); copyFrom(other); } ConfigFileItem& operator=(const ConfigFileItem& other) { if (this != &other) { copyFrom(other); } return *this; } ~ConfigFileItem() { clearItems(); } void serializeToFile(const QString& filePath = "") { QString path = filePath.isEmpty() ? QCoreApplication::applicationDirPath() + "/config.json" : filePath; QJsonObject jsonObject = QJsonObject::fromVariantMap(this->toVariantMap()); QJsonDocument jsonDoc(jsonObject); QByteArray jsonData = jsonDoc.toJson(); QFile file(path); if (file.open(QIODevice::WriteOnly | QIODevice::Text)) { file.write(jsonData); file.close(); } else { qWarning() << "Failed to open file for writing:" << path; m_gLog.RecordLogError("Failed to open file for writing:" + path); } } void deserializeFromFile(const QString& filePath = "") { QString path = filePath.isEmpty() ? QCoreApplication::applicationDirPath() + "/config.json" : filePath; QFile file(path); if (file.open(QIODevice::ReadOnly | QIODevice::Text)) { QByteArray jsonData = file.readAll(); file.close(); QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); if (jsonDoc.isNull()) { qWarning() << "Invalid JSON document"; m_gLog.RecordLogError("Invalid JSON document"); return; } QJsonObject jsonObject = jsonDoc.object(); this->fromVariantMap(jsonObject.toVariantMap()); } else { qWarning() << "Failed to open file for reading:" << path; m_gLog.RecordLogError("Failed to open file for reading:" + path); } } void copyToTestData(TestData& testData) { testData.m_bBarcode = m_barcode->toBool(); testData.m_keyBarcode = m_barcode->m_alias; // 复制 BasicTree 数据 testData.Basic.m_bConfigFile = m_basic->m_configFile->toBool(); testData.Basic.m_keyConfigFile = m_basic->m_configFile->m_alias; testData.Basic.m_bDefocus = m_basic->m_defocus->toBool(); testData.Basic.m_keyDefocus = m_basic->m_defocus->m_alias; testData.Basic.m_bDriverPos = m_basic->m_driverPos->toBool(); testData.Basic.m_keyDriverPos = m_basic->m_driverPos->m_alias; testData.Basic.m_bPosition = m_basic->m_position->toBool(); testData.Basic.m_keyPosition = m_basic->m_position->m_alias; testData.Basic.m_bThroughFocusData = m_basic->m_throughFocusData->toBool(); testData.Basic.m_keyThroughFocusData = m_basic->m_throughFocusData->m_alias; testData.Basic.m_bTime = m_basic->m_time->toBool(); testData.Basic.m_keyTime = m_basic->m_time->m_alias; testData.Basic.m_bTrayName = m_basic->m_trayName->toBool(); testData.Basic.m_keyTrayName = m_basic->m_trayName->m_alias; testData.m_bCameraCounts = m_cameraCounts->toBool(); testData.m_keyCameraCounts = m_cameraCounts->m_alias; testData.m_bDefocus = m_defocus->toBool(); testData.m_keyDefocus = m_defocus->m_alias; testData.m_bGroupDefine = m_groupDefine->toBool(); testData.m_keyGroupDefine = m_groupDefine->m_alias; // 复制 NormalTree 数据 testData.Normal.A2DOF.m_bA2DOF = m_normal->m_a2dof->m_a2dof->toBool(); testData.Normal.A2DOF.m_keyA2DOF = m_normal->m_a2dof->m_a2dof->m_alias; testData.Normal.A2DOF.m_bMinus = m_normal->m_a2dof->m_minus->toBool(); testData.Normal.A2DOF.m_keyMinus = m_normal->m_a2dof->m_minus->m_alias; testData.Normal.A2DOF.m_bPlus = m_normal->m_a2dof->m_plus->toBool(); testData.Normal.A2DOF.m_keyPlus = m_normal->m_a2dof->m_plus->m_alias; testData.Normal.A2DOF.m_bOnAxis = m_normal->m_a2dof->m_onAxis->toBool(); testData.Normal.A2DOF.m_keyOnAxis = m_normal->m_a2dof->m_onAxis->m_alias; testData.Normal.A2DOF.m_bOffAxis = m_normal->m_a2dof->m_offAxis->toBool(); testData.Normal.A2DOF.m_keyOffAxis = m_normal->m_a2dof->m_offAxis->m_alias; testData.Normal.A2DOF.m_bA2DOFAvg = m_normal->m_a2dof->m_a2dofAvg->toBool(); testData.Normal.A2DOF.m_keyA2DOFAvg = m_normal->m_a2dof->m_a2dofAvg->m_alias; testData.Normal.A2DOF.m_bAvgMinus = m_normal->m_a2dof->m_avgMinus->toBool(); testData.Normal.A2DOF.m_keyAvgMinus = m_normal->m_a2dof->m_avgMinus->m_alias; testData.Normal.A2DOF.m_bAvgPlus = m_normal->m_a2dof->m_avgPlus->toBool(); testData.Normal.A2DOF.m_keyAvgPlus = m_normal->m_a2dof->m_avgPlus->m_alias; testData.Normal.A2DOF.m_bOnAxisAvg = m_normal->m_a2dof->m_onAxisAvg->toBool(); testData.Normal.A2DOF.m_keyOnAxisAvg = m_normal->m_a2dof->m_onAxisAvg->m_alias; testData.Normal.A2DOF.m_bOffAxisAvg = m_normal->m_a2dof->m_offAxisAvg->toBool(); testData.Normal.A2DOF.m_keyOffAxisAvg = m_normal->m_a2dof->m_offAxisAvg->m_alias; testData.Normal.m_bAstigmatism = m_normal->m_astigmatism->toBool(); testData.Normal.m_keyAstigmatism = m_normal->m_astigmatism->m_alias; testData.Normal.DOF.m_bCameras = m_normal->m_dof->m_cameras->toBool(); testData.Normal.DOF.m_keyCameras = m_normal->m_dof->m_cameras->m_alias; testData.Normal.DOF.m_bDOF = m_normal->m_dof->m_dof->toBool(); testData.Normal.DOF.m_keyDOF = m_normal->m_dof->m_dof->m_alias; testData.Normal.DOF.m_bGroup = m_normal->m_dof->m_group->toBool(); testData.Normal.DOF.m_keyGroup = m_normal->m_dof->m_group->m_alias; testData.Normal.DOF.m_bMinus = m_normal->m_dof->m_minus->toBool(); testData.Normal.DOF.m_keyMinus = m_normal->m_dof->m_minus->m_alias; testData.Normal.DOF.m_bPlus = m_normal->m_dof->m_plus->toBool(); testData.Normal.DOF.m_keyPlus = m_normal->m_dof->m_plus->m_alias; testData.Normal.m_bEFL = m_normal->m_efl->toBool(); testData.Normal.m_keyEFL = m_normal->m_efl->m_alias; testData.Normal.m_bFFL = m_normal->m_ffl->toBool(); testData.Normal.m_keyFFL = m_normal->m_ffl->m_alias; testData.Normal.m_bFieldPositionMTF = m_normal->m_fieldPositionMtf->toBool(); testData.Normal.m_keyFieldPositionMTF = m_normal->m_fieldPositionMtf->m_alias; testData.Normal.FocalShift.m_bCameras = m_normal->m_focalShift->m_cameras->toBool(); testData.Normal.FocalShift.m_keyCameras = m_normal->m_focalShift->m_cameras->m_alias; testData.Normal.FocalShift.m_bGroup = m_normal->m_focalShift->m_group->toBool(); testData.Normal.FocalShift.m_keyGroup = m_normal->m_focalShift->m_group->m_alias; testData.Normal.FocalShift.m_bNegative = m_normal->m_focalShift->m_negative->toBool(); testData.Normal.FocalShift.m_keyNegative = m_normal->m_focalShift->m_negative->m_alias; testData.Normal.FocalShift.m_bPositive = m_normal->m_focalShift->m_positive->toBool(); testData.Normal.FocalShift.m_keyPositive = m_normal->m_focalShift->m_positive->m_alias; testData.Normal.m_bFocalShiftAverage = m_normal->m_focalShiftAverage->toBool(); testData.Normal.m_keyFocalShiftAverage = m_normal->m_focalShiftAverage->m_alias; testData.Normal.m_bFocalShiftGroup = m_normal->m_focalShiftGroup->toBool(); testData.Normal.m_keyFocalShiftGroup = m_normal->m_focalShiftGroup->m_alias; testData.Normal.m_bFocalShiftSingle = m_normal->m_focalShiftSingle->toBool(); testData.Normal.m_keyFocalShiftSingle = m_normal->m_focalShiftSingle->m_alias; testData.Normal.m_bHalfFOV = m_normal->m_halfFov->toBool(); testData.Normal.m_keyHalfFOV = m_normal->m_halfFov->m_alias; testData.Normal.m_bFullFOV = m_normal->m_fullFov->toBool(); testData.Normal.m_keyFullFOV = m_normal->m_fullFov->m_alias; testData.Normal.m_bLSFPeaks = m_normal->m_lsfPeaks->toBool(); testData.Normal.m_keyLSFPeaks = m_normal->m_lsfPeaks->m_alias; testData.Normal.m_bMTF = m_normal->m_mtf->toBool(); testData.Normal.m_keyMTF = m_normal->m_mtf->m_alias; testData.Normal.m_bMTFAverageAllCameras = m_normal->m_mtfAverageAllCameras->toBool(); testData.Normal.m_keyMTFAverageAllCameras = m_normal->m_mtfAverageAllCameras->m_alias; testData.Normal.m_bMTFPeaks = m_normal->m_mtfPeaks->toBool(); testData.Normal.m_keyMTFPeaks = m_normal->m_mtfPeaks->m_alias; testData.Normal.m_bMTFRatio = m_normal->m_mtfRatio->toBool(); testData.Normal.m_keyMTFRatio = m_normal->m_mtfRatio->m_alias; testData.Normal.m_bMultiFrqMTF = m_normal->m_multiFrqMtf->toBool(); testData.Normal.m_keyMultiFrqMTF = m_normal->m_multiFrqMtf->m_alias; testData.Normal.m_bPeakMTF = m_normal->m_peakMtf->toBool(); testData.Normal.m_keyPeakMTF = m_normal->m_peakMtf->m_alias; testData.Normal.m_bPeakMTFAverage = m_normal->m_peakMtfAverage->toBool(); testData.Normal.m_keyPeakMTFAverage = m_normal->m_peakMtfAverage->m_alias; testData.Normal.m_bPeakRange = m_normal->m_peakRange->toBool(); testData.Normal.m_keyPeakRange = m_normal->m_peakRange->m_alias; testData.Normal.m_bSymmetricalFieldMTF = m_normal->m_symmetricalFieldMtf->toBool(); testData.Normal.m_keySymmetricalFieldMTF = m_normal->m_symmetricalFieldMtf->m_alias; testData.Normal.m_bSymmetricalGroupMTF = m_normal->m_symmetricalGroupMtf->toBool(); testData.Normal.m_keySymmetricalGroupMTF = m_normal->m_symmetricalGroupMtf->m_alias; testData.Normal.Tilt.m_bAngle = m_normal->m_tilt->m_angle->toBool(); testData.Normal.Tilt.m_keyAngle = m_normal->m_tilt->m_angle->m_alias; testData.Normal.Tilt.m_bAzimuth = m_normal->m_tilt->m_azimuth->toBool(); testData.Normal.Tilt.m_keyAzimuth = m_normal->m_tilt->m_azimuth->m_alias; testData.Normal.Tilt.m_bType = m_normal->m_tilt->m_type->toBool(); testData.Normal.Tilt.m_keyType = m_normal->m_tilt->m_type->m_alias; // 复制 ResultTree 数据 testData.Result.m_bAggregate = m_result->m_aggregate->toBool(); testData.Result.m_keyAggregate = m_result->m_aggregate->m_alias; testData.Result.m_bAstigmatism = m_result->m_astigmatism->toBool(); testData.Result.m_keyAstigmatism = m_result->m_astigmatism->m_alias; testData.Result.m_bAverage = m_result->m_average->toBool(); testData.Result.m_keyAverage = m_result->m_average->m_alias; testData.Result.m_bDOF = m_result->m_dof->toBool(); testData.Result.m_keyDOF = m_result->m_dof->m_alias; testData.Result.m_bFOV = m_result->m_fov->toBool(); testData.Result.m_keyFOV = m_result->m_fov->m_alias; testData.Result.m_bFailReason = m_result->m_failReason->toBool(); testData.Result.m_keyFailReason = m_result->m_failReason->m_alias; testData.Result.m_bFinal = m_result->m_final->toBool(); testData.Result.m_keyFinal = m_result->m_final->m_alias; testData.Result.m_bFocalShift = m_result->m_focalShift->toBool(); testData.Result.m_keyFocalShift = m_result->m_focalShift->m_alias; testData.Result.m_bMTF = m_result->m_mtf->toBool(); testData.Result.m_keyMTF = m_result->m_mtf->m_alias; testData.Result.m_bMultiFrqMTF = m_result->m_multiFrqMtf->toBool(); testData.Result.m_keyMultiFrqMTF = m_result->m_multiFrqMtf->m_alias; testData.Result.m_bDefocus = m_result->m_defocus->toBool(); testData.Result.m_keyDefocus = m_result->m_defocus->m_alias; } private: void initItems() { m_barcode = new ConfigItem(this); m_cameraCounts = new ConfigItem(this); m_groupDefine = new ConfigItem(this); m_basic = new BasicTree(this); m_result = new ResultTree(this); m_normal = new NormaltTree(this); m_defocus = new ConfigItem(this); } void clearItems() { // 所有对象由父对象管理 } void copyFrom(const ConfigFileItem& other) { // 复制简单值 m_barcode->m_value = other.m_barcode->m_value; m_cameraCounts->m_value = other.m_cameraCounts->m_value; m_groupDefine->m_value = other.m_groupDefine->m_value; m_defocus->m_value = other.m_defocus->m_value; // 复制嵌套对象 *m_basic = *other.m_basic; *m_result = *other.m_result; *m_normal = *other.m_normal; } public: ConfigItem* m_barcode; ConfigItem* m_cameraCounts; ConfigItem* m_groupDefine; BasicTree* m_basic; ResultTree* m_result; NormaltTree* m_normal; ConfigItem* m_defocus; }; #pragma once #include <QObject> #include <QVector> #include <QMap> #include <QJsonValue> #include <QFile> #include <QVariant> #include <QMetaObject> #include <QJsonArray> #include <QMetaProperty> class SerializableAssist : public QObject { Q_OBJECT public: explicit SerializableAssist(QObject *parent = nullptr) : QObject(parent) {} virtual QVariantMap toVariantMap() const { QVariantMap map; const QMetaObject *metaObject = this->metaObject(); for (int i = 0; i < metaObject->propertyCount(); ++i) { QMetaProperty property = metaObject->property(i); QString propName = property.name(); if (propName == "objectName") { continue; // Skip objectName property } QVariant propValue = this->property(property.name()); if (propValue.canConvert<SerializableAssist *>()) { SerializableAssist *serializableProp = propValue.value<SerializableAssist *>(); if (serializableProp) { map[propName] = serializableProp->toVariantMap(); } } else if (propValue.canConvert<QVector<SerializableAssist *>>()) { QVector<SerializableAssist *> serializableList = propValue.value<QVector<SerializableAssist *>>(); QVariantList variantList; for (SerializableAssist *item : serializableList) { if (item) { variantList.append(item->toVariantMap()); } } map[propName] = variantList; } else { map[propName] = propValue; } } return map; } virtual void fromVariantMap(const QVariantMap &map) { const QMetaObject *metaObject = this->metaObject(); for (int i = 0; i < metaObject->propertyCount(); ++i) { QMetaProperty property = metaObject->property(i); QString propName = property.name(); if (map.contains(propName)) { QVariant propValue = map[propName]; if (property.isWritable()) { int f = propValue.type(); if (propValue.type() == QVariant::Map) { SerializableAssist *child = qvariant_cast<SerializableAssist*>(this->property(property.name())); if (!child) { const QMetaObject *childMetaObject = QMetaType::metaObjectForType(property.userType()); if (childMetaObject) { child = qobject_cast<SerializableAssist*>(childMetaObject->newInstance(Q_ARG(QObject*, this))); this->setProperty(property.name(), QVariant::fromValue(child)); } } if (child) { child->fromVariantMap(propValue.toMap()); } } else if (propValue.type() == QVariant::List) { QVariantList list = propValue.toList(); QVariantList newList; for (const QVariant &item : list) { int tempType = item.type(); if (item.type() == QVariant::Map) { SerializableAssist *child = qvariant_cast<SerializableAssist*>(this->property(property.name())); const QMetaObject *childMetaObject = QMetaType::metaObjectForType(property.userType()); if (childMetaObject) { SerializableAssist *child = qobject_cast<SerializableAssist*>(childMetaObject->newInstance(Q_ARG(QObject*, this))); if (child) { child->fromVariantMap(item.toMap()); //newList.append(child); } } } else if (item.type() == QVariant::List) { newList.append(item); } else { // Assuming the item is already a SerializableAssist object newList.append(item); } } //this->setProperty(property.name(), QVariant::fromValue(newList)); property.write(this, newList); } else { this->setProperty(property.name(), propValue); } } } } } template<typename T> static T* fromJsonFile(const QString &filePath, QObject *parent = nullptr) { static_assert(std::is_base_of<SerializableAssist, T>::value, "T must inherit from Serializable"); QFile file(filePath); if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { qWarning() << "Failed to open file for reading:" << file.errorString(); return nullptr; } QByteArray jsonData = file.readAll(); file.close(); QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData); if (jsonDoc.isNull() || !jsonDoc.isObject()) { qWarning() << "Invalid JSON format"; return nullptr; } QJsonObject jsonObject = jsonDoc.object(); T* object = new T(parent); QVariantMap tempMap = jsonObject.toVariantMap(); object->fromVariantMap(jsonObject.toVariantMap()); return object; } template<typename T> static bool toJsonFile(const QString &filePath,T object, QObject *parent = nullptr) { static_assert(std::is_base_of<SerializableAssist, T>::value, "T must inherit from Serializable"); QJsonObject jsonObj; QVariantMap variantMap = object.toVariantMap(); // 特殊处理容器类型和嵌套对象 for (const QString& key : variantMap.keys()) { QVariant variant = variantMap[key]; if (variant.type() == QMetaType::QVariantList) { QVariantList list = variant.toList(); jsonObj[key] = QJsonValue::fromVariant(variantListToJsonArrayN(list)); } else if (variant.canConvert<QVariantMap>()) { QVariantMap nestedMap = variant.toMap(); jsonObj[key] = QJsonObject::fromVariantMap(nestedMap); } else { jsonObj[key] = QJsonValue::fromVariant(variant); } } QJsonDocument jsonDoc(jsonObj); QFile file(filePath); if (!file.open(QIODevice::WriteOnly)) { qCritical() << "Failed to open file for writing:" << file.errorString(); return false; } qint64 bytesWritten = file.write(jsonDoc.toJson()); if (bytesWritten == -1) { qCritical() << "Failed to write JSON data to file:" << file.errorString(); file.close(); return false; } else if (bytesWritten != jsonDoc.toJson().size()) { qWarning() << "Failed to write all JSON data to file, only" << bytesWritten << "bytes were written"; } if (!file.flush()) { qCritical() << "Failed to flush data to file:" << file.errorString(); file.close(); return false; } file.close(); return true; } static QJsonArray variantListToJsonArrayN(const QVariantList& list) { QJsonArray array; for (const QVariant& v : list) { array.append(QJsonValue::fromVariant(v)); } return array; } private: SerializableAssist *createSerializableInstance(const QString &typeName) { const QMetaObject *metaObject = QMetaType::metaObjectForType(QMetaType::type(typeName.toUtf8().constData())); if (metaObject) { return qobject_cast<SerializableAssist *>(metaObject->newInstance()); } return nullptr; } }; // 宏定义用于快速定义可序列化的类 #define DECLARE_SERIALIZABLE_CLASS(ClassName) \ class ClassName : public Serializable { \ Q_OBJECT \ Q_PROPERTY(QString name MEMBER m_name) \ Q_PROPERTY(int age MEMBER m_age) \ Q_PROPERTY(QStringList hobbies MEMBER m_hobbies) \ public: \ explicit ClassName(QObject *parent = nullptr) : Serializable(parent) {} \ private: \ QString m_name; \ int m_age; \ QStringList m_hobbies; \ }; // 定义数据类 改写不用Q_OBJECT
09-23
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值