From cbb785424855bfc6ce554e193d28db0f83ccdbae Mon Sep 17 00:00:00 2001 From: Markus Kalkbrenner Date: Mon, 1 Jan 2024 18:24:25 +0100 Subject: [PATCH] applyed clang format, same as LISY --- .clang-format | 191 ++++++ src/ZeDMD.cpp | 1526 +++++++++++++++++++++++---------------------- src/ZeDMD.h | 248 ++++---- src/ZeDMDComm.cpp | 862 ++++++++++++------------- src/ZeDMDComm.h | 227 ++++--- src/ZeDMDWiFi.cpp | 133 ++-- src/ZeDMDWiFi.h | 32 +- 7 files changed, 1674 insertions(+), 1545 deletions(-) create mode 100644 .clang-format diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..0eae268 --- /dev/null +++ b/.clang-format @@ -0,0 +1,191 @@ +--- +Language: Cpp +BasedOnStyle: LLVM +AccessModifierOffset: -2 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveMacros: AcrossEmptyLinesAndComments +AlignConsecutiveAssignments: None +AlignConsecutiveBitFields: AcrossEmptyLinesAndComments +AlignConsecutiveDeclarations: None +AlignEscapedNewlines: Right +AlignOperands: Align +#InsertBraces: true # Control statements must have curly brackets, requires clang-format 15 +AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Empty +AllowShortCaseLabelsOnASingleLine: false +AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: Never +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: AllDefinitions +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + AfterExternBlock: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakBeforeBinaryOperators: NonAssignment +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Attach +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeColon +BreakBeforeTernaryOperators: true +BreakConstructorInitializersBeforeComma: false +BreakConstructorInitializers: BeforeColon +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: true +ColumnLimit: 120 +CommentPragmas: '^ IWYU pragma:' +QualifierAlignment: Leave +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DeriveLineEnding: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock +ExperimentalAutoDetectBinPacking: false +PackConstructorInitializers: BinPack +ConstructorInitializerAllOnOneLineOrOnePerLine: false +AllowAllConstructorInitializersOnNextLine: true +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Preserve +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^(<|"(gtest|gmock|isl|json)/)' + Priority: 3 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 1 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false +IndentCaseLabels: true +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +# IndentRequires: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: true +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: None +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyReturnTypeOnItsOwnLine: 60 +PenaltyIndentedWhitespace: 0 +PointerAlignment: Left +PPIndentWidth: -1 +ReferenceAlignment: Pointer +ReflowComments: false +RemoveBracesLLVM: false +SeparateDefinitionBlocks: Always +ShortNamespaceLines: 1 +SortIncludes: CaseSensitive +SortJavaStaticImport: Before +SortUsingDeclarations: true +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + BeforeNonEmptyParentheses: false +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +... diff --git a/src/ZeDMD.cpp b/src/ZeDMD.cpp index 4202ced..6a19d61 100644 --- a/src/ZeDMD.cpp +++ b/src/ZeDMD.cpp @@ -2,879 +2,899 @@ #include "ZeDMDComm.h" #include "ZeDMDWiFi.h" -ZeDMD::ZeDMD() -{ - m_romWidth = 0; - m_romHeight = 0; +ZeDMD::ZeDMD() { + m_romWidth = 0; + m_romHeight = 0; - memset(m_palette4, 0, sizeof(m_palette4)); - memset(m_palette16, 0, sizeof(m_palette16)); - memset(m_palette64, 0, sizeof(m_palette64)); + memset(m_palette4, 0, sizeof(m_palette4)); + memset(m_palette16, 0, sizeof(m_palette16)); + memset(m_palette64, 0, sizeof(m_palette64)); - m_pFrameBuffer = NULL; - m_pScaledFrameBuffer = NULL; - m_pCommandBuffer = NULL; - m_pPlanes = NULL; + m_pFrameBuffer = NULL; + m_pScaledFrameBuffer = NULL; + m_pCommandBuffer = NULL; + m_pPlanes = NULL; - m_pZeDMDComm = new ZeDMDComm(); - m_pZeDMDWiFi = new ZeDMDWiFi(); + m_pZeDMDComm = new ZeDMDComm(); + m_pZeDMDWiFi = new ZeDMDWiFi(); } -ZeDMD::~ZeDMD() -{ - m_pZeDMDComm->Disconnect(); - free(m_pZeDMDComm); +ZeDMD::~ZeDMD() { + m_pZeDMDComm->Disconnect(); + free(m_pZeDMDComm); - m_pZeDMDWiFi->Disconnect(); - free(m_pZeDMDWiFi); + m_pZeDMDWiFi->Disconnect(); + free(m_pZeDMDWiFi); - if (m_pFrameBuffer) - delete m_pFrameBuffer; + if (m_pFrameBuffer) + delete m_pFrameBuffer; - if (m_pScaledFrameBuffer) - delete m_pScaledFrameBuffer; + if (m_pScaledFrameBuffer) + delete m_pScaledFrameBuffer; - if (m_pCommandBuffer) - delete m_pCommandBuffer; + if (m_pCommandBuffer) + delete m_pCommandBuffer; - if (m_pPlanes) - delete m_pPlanes; + if (m_pPlanes) + delete m_pPlanes; } -void ZeDMD::SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void *userData) -{ - m_pZeDMDComm->SetLogMessageCallback(callback, userData); - m_pZeDMDWiFi->SetLogMessageCallback(callback, userData); +void +ZeDMD::SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void* userData) { + m_pZeDMDComm->SetLogMessageCallback(callback, userData); + m_pZeDMDWiFi->SetLogMessageCallback(callback, userData); } #ifdef __ANDROID__ -void ZeDMD::SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func) -{ - m_pZeDMDComm->SetAndroidGetJNIEnvFunc(func); +void +ZeDMD::SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func) { + m_pZeDMDComm->SetAndroidGetJNIEnvFunc(func); } #endif -void ZeDMD::Close() -{ - m_pZeDMDComm->Disconnect(); - m_pZeDMDWiFi->Disconnect(); +void +ZeDMD::Close() { + m_pZeDMDComm->Disconnect(); + m_pZeDMDWiFi->Disconnect(); } -void ZeDMD::IgnoreDevice(const char *const ignore_device) -{ - m_pZeDMDComm->IgnoreDevice(ignore_device); +void +ZeDMD::IgnoreDevice(const char* const ignore_device) { + m_pZeDMDComm->IgnoreDevice(ignore_device); } -void ZeDMD::SetDevice(const char *const device) -{ - m_pZeDMDComm->SetDevice(device); +void +ZeDMD::SetDevice(const char* const device) { + m_pZeDMDComm->SetDevice(device); } -void ZeDMD::SetFrameSize(uint16_t width, uint16_t height) -{ - m_romWidth = width; - m_romHeight = height; +void +ZeDMD::SetFrameSize(uint16_t width, uint16_t height) { + m_romWidth = width; + m_romHeight = height; - if (m_usb) - { - uint16_t frameWidth = m_pZeDMDComm->GetWidth(); - uint16_t frameHeight = m_pZeDMDComm->GetHeight(); - uint8_t size[4]; + if (m_usb) { + uint16_t frameWidth = m_pZeDMDComm->GetWidth(); + uint16_t frameHeight = m_pZeDMDComm->GetHeight(); + uint8_t size[4]; - if ((m_downscaling && (width > frameWidth || height > frameHeight)) || (m_upscaling && (width < frameWidth || height < frameHeight))) - { - size[0] = (uint8_t)(frameWidth & 0xFF); - size[1] = (uint8_t)((frameWidth >> 8) & 0xFF); - size[2] = (uint8_t)(frameHeight & 0xFF); - size[3] = (uint8_t)((frameHeight >> 8) & 0xFF); - } - else - { - size[0] = (uint8_t)(width & 0xFF); - size[1] = (uint8_t)((width >> 8) & 0xFF); - size[2] = (uint8_t)(height & 0xFF); - size[3] = (uint8_t)((height >> 8) & 0xFF); - } + if ((m_downscaling && (width > frameWidth || height > frameHeight)) + || (m_upscaling && (width < frameWidth || height < frameHeight))) { + size[0] = (uint8_t)(frameWidth & 0xFF); + size[1] = (uint8_t)((frameWidth >> 8) & 0xFF); + size[2] = (uint8_t)(frameHeight & 0xFF); + size[3] = (uint8_t)((frameHeight >> 8) & 0xFF); + } else { + size[0] = (uint8_t)(width & 0xFF); + size[1] = (uint8_t)((width >> 8) & 0xFF); + size[2] = (uint8_t)(height & 0xFF); + size[3] = (uint8_t)((height >> 8) & 0xFF); + } - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::FrameSize, size, 4); - } + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::FrameSize, size, 4); + } } -void ZeDMD::LedTest() -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::LEDTest); +void +ZeDMD::LedTest() { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::LEDTest); } -void ZeDMD::EnableDebug() -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::EnableDebug); +void +ZeDMD::EnableDebug() { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::EnableDebug); } -void ZeDMD::DisableDebug() -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::DisableDebug); +void +ZeDMD::DisableDebug() { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::DisableDebug); } -void ZeDMD::SetRGBOrder(uint8_t rgbOrder) -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGBOrder, rgbOrder); +void +ZeDMD::SetRGBOrder(uint8_t rgbOrder) { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGBOrder, rgbOrder); } -void ZeDMD::SetBrightness(uint8_t brightness) -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::Brightness, brightness); +void +ZeDMD::SetBrightness(uint8_t brightness) { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::Brightness, brightness); } -void ZeDMD::SaveSettings() -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SaveSettings); - // Avoid that client resets the device before settings are saved. - std::this_thread::sleep_for(std::chrono::milliseconds(5000)); +void +ZeDMD::SaveSettings() { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SaveSettings); + // Avoid that client resets the device before settings are saved. + std::this_thread::sleep_for(std::chrono::milliseconds(5000)); } -void ZeDMD::EnablePreDownscaling() -{ - m_downscaling = true; +void +ZeDMD::EnablePreDownscaling() { + m_downscaling = true; } -void ZeDMD::DisablePreDownscaling() -{ - m_downscaling = false; +void +ZeDMD::DisablePreDownscaling() { + m_downscaling = false; } -void ZeDMD::EnablePreUpscaling() -{ - m_upscaling = true; - m_hd = (m_pZeDMDComm->GetWidth() == 256); +void +ZeDMD::EnablePreUpscaling() { + m_upscaling = true; + m_hd = (m_pZeDMDComm->GetWidth() == 256); } -void ZeDMD::DisablePreUpscaling() -{ - m_upscaling = false; - m_hd = false; +void +ZeDMD::DisablePreUpscaling() { + m_upscaling = false; + m_hd = false; } -void ZeDMD::EnableUpscaling() -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::EnableUpscaling); +void +ZeDMD::EnableUpscaling() { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::EnableUpscaling); } -void ZeDMD::DisableUpscaling() -{ - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::DisableUpscaling); +void +ZeDMD::DisableUpscaling() { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::DisableUpscaling); } -void ZeDMD::SetWiFiSSID(const char *const ssid) -{ - int size = strlen(ssid); - uint8_t data[33] = {0}; - data[0] = (uint8_t)size; - memcpy(&data[1], (uint8_t *)ssid, size); - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetWiFiSSID, data, size + 1); +void +ZeDMD::SetWiFiSSID(const char* const ssid) { + int size = strlen(ssid); + uint8_t data[33] = {0}; + data[0] = (uint8_t)size; + memcpy(&data[1], (uint8_t*)ssid, size); + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetWiFiSSID, data, size + 1); } -void ZeDMD::SetWiFiPassword(const char *const password) -{ - int size = strlen(password); - uint8_t data[33] = {0}; - data[0] = (uint8_t)size; - memcpy(&data[1], (uint8_t *)password, size); - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetWiFiPassword, data, size + 1); +void +ZeDMD::SetWiFiPassword(const char* const password) { + int size = strlen(password); + uint8_t data[33] = {0}; + data[0] = (uint8_t)size; + memcpy(&data[1], (uint8_t*)password, size); + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetWiFiPassword, data, size + 1); } -void ZeDMD::SetWiFiPort(int port) -{ - uint8_t data[2]; - data[0] = (uint8_t)(port >> 8 & 0xFF); - data[1] = (uint8_t)(port & 0xFF); +void +ZeDMD::SetWiFiPort(int port) { + uint8_t data[2]; + data[0] = (uint8_t)(port >> 8 & 0xFF); + data[1] = (uint8_t)(port & 0xFF); - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetWiFiPort, data, 2); + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::SetWiFiPort, data, 2); } -bool ZeDMD::OpenWiFi(const char *ip, int port) -{ - m_wifi = m_pZeDMDWiFi->Connect(ip, port); +bool +ZeDMD::OpenWiFi(const char* ip, int port) { + m_wifi = m_pZeDMDWiFi->Connect(ip, port); - // @todo allow parallel mode for USB commands - if (m_wifi && !m_usb) - { - m_pFrameBuffer = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); - m_pScaledFrameBuffer = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); - m_pPlanes = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); + // @todo allow parallel mode for USB commands + if (m_wifi && !m_usb) { + m_pFrameBuffer = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); + m_pScaledFrameBuffer = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); + m_pPlanes = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); - m_pZeDMDWiFi->Run(); - } + m_pZeDMDWiFi->Run(); + } - return m_wifi; + return m_wifi; } -bool ZeDMD::Open() -{ - m_usb = m_pZeDMDComm->Connect(); +bool +ZeDMD::Open() { + m_usb = m_pZeDMDComm->Connect(); - // @todo allow parallel connection for USB commands - if (m_usb && !m_wifi) - { - m_pFrameBuffer = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); - m_pScaledFrameBuffer = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); - m_pCommandBuffer = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3 + 192); - m_pPlanes = (uint8_t *)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); + // @todo allow parallel connection for USB commands + if (m_usb && !m_wifi) { + m_pFrameBuffer = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); + m_pScaledFrameBuffer = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); + m_pCommandBuffer = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3 + 192); + m_pPlanes = (uint8_t*)malloc(ZEDMD_MAX_WIDTH * ZEDMD_MAX_HEIGHT * 3); - m_hd = (m_pZeDMDComm->GetWidth() == 256); + m_hd = (m_pZeDMDComm->GetWidth() == 256); - m_pZeDMDComm->Run(); - } + m_pZeDMDComm->Run(); + } - return m_usb; + return m_usb; } -bool ZeDMD::Open(uint16_t width, uint16_t height) -{ - if (Open()) - { - SetFrameSize(width, height); - } +bool +ZeDMD::Open(uint16_t width, uint16_t height) { + if (Open()) { + SetFrameSize(width, height); + } - return m_usb; + return m_usb; } -void ZeDMD::SetPalette(uint8_t *pPalette) -{ - SetPalette(pPalette, 64); +void +ZeDMD::SetPalette(uint8_t* pPalette) { + SetPalette(pPalette, 64); } -void ZeDMD::SetPalette(uint8_t *pPalette, uint8_t numColors) -{ - m_paletteChanged = false; +void +ZeDMD::SetPalette(uint8_t* pPalette, uint8_t numColors) { + m_paletteChanged = false; - uint8_t *pPaletteNumber; - switch (numColors) - { - case 4: - pPaletteNumber = m_palette4; - break; - case 16: - pPaletteNumber = m_palette16; - break; - case 64: - pPaletteNumber = m_palette64; - break; - default: - return; - } + uint8_t* pPaletteNumber; + switch (numColors) { + case 4: + pPaletteNumber = m_palette4; + break; + case 16: + pPaletteNumber = m_palette16; + break; + case 64: + pPaletteNumber = m_palette64; + break; + default: + return; + } - if (memcmp(pPaletteNumber, pPalette, numColors * 3)) - { - memcpy(pPaletteNumber, pPalette, numColors * 3); - m_paletteChanged = true; - } + if (memcmp(pPaletteNumber, pPalette, numColors * 3)) { + memcpy(pPaletteNumber, pPalette, numColors * 3); + m_paletteChanged = true; + } } -void ZeDMD::SetDefaultPalette(uint8_t bitDepth) -{ - switch (bitDepth) - { - case 2: - SetPalette(m_DmdDefaultPalette2Bit, 4); - break; - - default: - SetPalette(m_DmdDefaultPalette4Bit, 16); - } +void +ZeDMD::SetDefaultPalette(uint8_t bitDepth) { + switch (bitDepth) { + case 2: + SetPalette(m_DmdDefaultPalette2Bit, 4); + break; + + default: + SetPalette(m_DmdDefaultPalette4Bit, 16); + } } -uint8_t *ZeDMD::GetDefaultPalette(uint8_t bitDepth) -{ - switch (bitDepth) - { - case 2: - return m_DmdDefaultPalette2Bit; - break; +uint8_t* +ZeDMD::GetDefaultPalette(uint8_t bitDepth) { + switch (bitDepth) { + case 2: + return m_DmdDefaultPalette2Bit; + break; + + default: + return m_DmdDefaultPalette4Bit; + } +} - default: - return m_DmdDefaultPalette4Bit; - } +void +ZeDMD::EnforceStreaming() { + m_streaming = true; } - -void ZeDMD::EnforceStreaming() -{ - m_streaming = true; + +void +ZeDMD::ClearScreen() { + if (m_usb) { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::ClearScreen); + } else if (m_wifi) { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::ClearScreen); + } } -void ZeDMD::ClearScreen() -{ - if (m_usb) - { - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::ClearScreen); - } - else if (m_wifi) - { - m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::ClearScreen); - } -} - -void ZeDMD::RenderGray2(uint8_t *pFrame) -{ - if (!(m_usb || m_wifi) || !(UpdateFrameBuffer8(pFrame) || m_paletteChanged)) - { - return; - } +void +ZeDMD::RenderGray2(uint8_t* pFrame) { + if (!(m_usb || m_wifi) || !(UpdateFrameBuffer8(pFrame) || m_paletteChanged)) { + return; + } + + uint16_t width; + uint16_t height; + + int bufferSize = Scale(m_pScaledFrameBuffer, m_pFrameBuffer, 1, &width, &height); - uint16_t width; - uint16_t height; - - int bufferSize = Scale(m_pScaledFrameBuffer, m_pFrameBuffer, 1, &width, &height); - - if (m_hd || m_wifi || m_streaming) - { - ConvertToRgb24(m_pPlanes, m_pScaledFrameBuffer, bufferSize, m_palette4); - - if (m_wifi) - { - m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); - } - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); - } - else if (m_usb) - { - Split(m_pPlanes, width, height, 2, m_pScaledFrameBuffer); - - bufferSize = bufferSize / 8 * 2; - - memcpy(m_pCommandBuffer, m_palette4, 12); - memcpy(m_pCommandBuffer + 12, m_pPlanes, bufferSize); - - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::Gray2, m_pCommandBuffer, 12 + bufferSize); - } -} - -void ZeDMD::RenderGray4(uint8_t *pFrame) -{ - if (!(m_usb || m_wifi) || !(UpdateFrameBuffer8(pFrame) || m_paletteChanged)) - { - return; - } - - uint16_t width; - uint16_t height; - - int bufferSize = Scale(m_pScaledFrameBuffer, m_pFrameBuffer, 1, &width, &height); - - if (m_hd || m_wifi || m_streaming) - { - ConvertToRgb24(m_pPlanes, m_pScaledFrameBuffer, bufferSize, m_palette16); - - if (m_wifi) - { - m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); - } - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); - } - else if (m_usb) - { - // Review: why? - bufferSize /= 2; - Split(m_pPlanes, width, height, 4, m_pScaledFrameBuffer); + if (m_hd || m_wifi || m_streaming) { + ConvertToRgb24(m_pPlanes, m_pScaledFrameBuffer, bufferSize, m_palette4); - memcpy(m_pCommandBuffer, m_palette16, 48); - memcpy(m_pCommandBuffer + 48, m_pPlanes, bufferSize); + if (m_wifi) { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); + } + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); + } else if (m_usb) { + Split(m_pPlanes, width, height, 2, m_pScaledFrameBuffer); - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::ColGray4, m_pCommandBuffer, 48 + bufferSize); - } + bufferSize = bufferSize / 8 * 2; + + memcpy(m_pCommandBuffer, m_palette4, 12); + memcpy(m_pCommandBuffer + 12, m_pPlanes, bufferSize); + + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::Gray2, m_pCommandBuffer, 12 + bufferSize); + } } -void ZeDMD::RenderColoredGray6(uint8_t *pFrame, uint8_t *pPalette, uint8_t *pRotations) -{ - SetPalette(pPalette); - RenderColoredGray6(pFrame, pRotations); +void +ZeDMD::RenderGray4(uint8_t* pFrame) { + if (!(m_usb || m_wifi) || !(UpdateFrameBuffer8(pFrame) || m_paletteChanged)) { + return; + } + + uint16_t width; + uint16_t height; + + int bufferSize = Scale(m_pScaledFrameBuffer, m_pFrameBuffer, 1, &width, &height); + + if (m_hd || m_wifi || m_streaming) { + ConvertToRgb24(m_pPlanes, m_pScaledFrameBuffer, bufferSize, m_palette16); + + if (m_wifi) { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); + } + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); + } else if (m_usb) { + // Review: why? + bufferSize /= 2; + Split(m_pPlanes, width, height, 4, m_pScaledFrameBuffer); + + memcpy(m_pCommandBuffer, m_palette16, 48); + memcpy(m_pCommandBuffer + 48, m_pPlanes, bufferSize); + + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::ColGray4, m_pCommandBuffer, 48 + bufferSize); + } +} + +void +ZeDMD::RenderColoredGray6(uint8_t* pFrame, uint8_t* pPalette, uint8_t* pRotations) { + SetPalette(pPalette); + RenderColoredGray6(pFrame, pRotations); } -void ZeDMD::RenderColoredGray6(uint8_t *pFrame, uint8_t *pRotations) -{ - if (!(m_usb || m_wifi) || !(UpdateFrameBuffer8(pFrame) || m_paletteChanged)) - return; +void +ZeDMD::RenderColoredGray6(uint8_t* pFrame, uint8_t* pRotations) { + if (!(m_usb || m_wifi) || !(UpdateFrameBuffer8(pFrame) || m_paletteChanged)) + return; - uint16_t width; - uint16_t height; + uint16_t width; + uint16_t height; - int bufferSize = Scale(m_pScaledFrameBuffer, m_pFrameBuffer, 1, &width, &height); + int bufferSize = Scale(m_pScaledFrameBuffer, m_pFrameBuffer, 1, &width, &height); - if (m_hd || m_wifi || m_streaming) - { - ConvertToRgb24(m_pPlanes, m_pScaledFrameBuffer, bufferSize, m_palette64); + if (m_hd || m_wifi || m_streaming) { + ConvertToRgb24(m_pPlanes, m_pScaledFrameBuffer, bufferSize, m_palette64); - if (m_wifi) - { - m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); - } - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); - } - else if (m_usb) - { - Split(m_pPlanes, width, height, 6, m_pScaledFrameBuffer); + if (m_wifi) { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); + } + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize * 3, width, height); + } else if (m_usb) { + Split(m_pPlanes, width, height, 6, m_pScaledFrameBuffer); - bufferSize = bufferSize / 8 * 6; + bufferSize = bufferSize / 8 * 6; - memcpy(m_pCommandBuffer, m_palette64, 192); - memcpy(m_pCommandBuffer + 192, m_pPlanes, bufferSize); + memcpy(m_pCommandBuffer, m_palette64, 192); + memcpy(m_pCommandBuffer + 192, m_pPlanes, bufferSize); - if (pRotations) - memcpy(m_pCommandBuffer + 192 + bufferSize, pRotations, 24); - else - memset(m_pCommandBuffer + 192 + bufferSize, 255, 24); + if (pRotations) + memcpy(m_pCommandBuffer + 192 + bufferSize, pRotations, 24); + else + memset(m_pCommandBuffer + 192 + bufferSize, 255, 24); - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::ColGray6, m_pCommandBuffer, 192 + bufferSize + 24); - } + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::ColGray6, m_pCommandBuffer, 192 + bufferSize + 24); + } } -void ZeDMD::RenderRgb24(uint8_t *pFrame) -{ - if (!(m_usb || m_wifi) || !UpdateFrameBuffer24(pFrame)) - { - return; - } +void +ZeDMD::RenderRgb24(uint8_t* pFrame) { + if (!(m_usb || m_wifi) || !UpdateFrameBuffer24(pFrame)) { + return; + } - uint16_t width; - uint16_t height; + uint16_t width; + uint16_t height; - int bufferSize = Scale(m_pPlanes, m_pFrameBuffer, 3, &width, &height); + int bufferSize = Scale(m_pPlanes, m_pFrameBuffer, 3, &width, &height); - if (m_wifi) - { - m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize, width, height); - } - else if (m_hd || m_streaming) - { - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize, width, height); - } - else if (m_usb) - { - m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24, m_pPlanes, bufferSize); - } + if (m_wifi) { + m_pZeDMDWiFi->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize, width, height); + } else if (m_hd || m_streaming) { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24ZonesStream, m_pPlanes, bufferSize, width, height); + } else if (m_usb) { + m_pZeDMDComm->QueueCommand(ZEDMD_COMM_COMMAND::RGB24, m_pPlanes, bufferSize); + } } -bool ZeDMD::UpdateFrameBuffer8(uint8_t *pFrame) -{ - if (!memcmp(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight)) - return false; +bool +ZeDMD::UpdateFrameBuffer8(uint8_t* pFrame) { + if (!memcmp(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight)) + return false; - memcpy(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight); - return true; + memcpy(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight); + return true; } -bool ZeDMD::UpdateFrameBuffer24(uint8_t *pFrame) -{ - if (!memcmp(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight * 3)) - return false; +bool +ZeDMD::UpdateFrameBuffer24(uint8_t* pFrame) { + if (!memcmp(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight * 3)) + return false; - memcpy(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight * 3); - return true; + memcpy(m_pFrameBuffer, pFrame, m_romWidth * m_romHeight * 3); + return true; } /** * Derived from https://github.com/freezy/dmd-extensions/blob/master/LibDmd/Common/FrameUtil.cs */ -void ZeDMD::Split(uint8_t *pPlanes, uint16_t width, uint16_t height, uint8_t bitlen, uint8_t *pFrame) -{ - int planeSize = width * height / 8; - int pos = 0; - uint8_t *bd = (uint8_t *)malloc(bitlen); - - for (int y = 0; y < height; y++) - { - for (int x = 0; x < width; x += 8) - { - memset(bd, 0, bitlen * sizeof(uint8_t)); - - for (int v = 7; v >= 0; v--) - { - uint8_t pixel = pFrame[(y * width) + (x + v)]; - for (int i = 0; i < bitlen; i++) - { - bd[i] <<= 1; - if ((pixel & (1 << i)) != 0) - bd[i] |= 1; - } - } - - for (int i = 0; i < bitlen; i++) - pPlanes[i * planeSize + pos] = bd[i]; - - pos++; - } - } - - free(bd); -} - -void ZeDMD::ConvertToRgb24(uint8_t *pFrameRgb24, uint8_t *pFrame, int size, uint8_t *pPalette) -{ - for (int i = 0; i < size; i++) - { - memcpy(&pFrameRgb24[i * 3], &pPalette[pFrame[i] * 3], 3); - } -} - -bool ZeDMD::CmpColor(uint8_t *px1, uint8_t *px2, uint8_t colors) -{ - if (colors == 3) - { - return (px1[0] == px2[0]) && - (px1[1] == px2[1]) && - (px1[2] == px2[2]); - } - - return px1[0] == px2[0]; -} - -void ZeDMD::SetColor(uint8_t *px1, uint8_t *px2, uint8_t colors) -{ - px1[0] = px2[0]; - - if (colors == 3) - { - px1[1] = px2[1]; - px1[2] = px2[2]; - } -} - -int ZeDMD::Scale(uint8_t *pScaledFrame, uint8_t *pFrame, uint8_t colors, uint16_t *width, uint16_t *height) -{ - int xoffset = 0; - int yoffset = 0; - uint8_t scale = 0; // 0 - no scale, 1 - half scale, 2 - double scale - uint16_t frameWidth = m_pZeDMDComm->GetWidth(); - uint16_t frameHeight = m_pZeDMDComm->GetHeight(); - int bufferSize = m_romWidth * m_romHeight * colors; - - if (m_upscaling && m_romWidth == 192 && frameWidth == 256) - { - (*width) = frameWidth; - (*height) = frameHeight; - - xoffset = 32; - } - else if (m_downscaling && m_romWidth == 192) - { - (*width) = frameWidth; - (*height) = frameHeight; - - xoffset = 16; - scale = 1; - } - else if (m_upscaling && m_romHeight == 16 && frameHeight == 32) - { - (*width) = frameWidth; - (*height) = frameHeight; - - yoffset = 8; - } - else if (m_upscaling && m_romHeight == 16 && frameHeight == 64) - { - (*width) = frameWidth; - (*height) = frameHeight; - - yoffset = 16; - scale = 2; - } - else if (m_downscaling && m_romWidth == 256 && frameWidth == 128) - { - (*width) = frameWidth; - (*height) = frameHeight; - - scale = 1; - } - else if (m_upscaling && m_romWidth == 128 && frameWidth == 256) - { - (*width) = frameWidth; - (*height) = frameHeight; - - scale = 2; - } - else - { - (*width) = m_romWidth; - (*height) = m_romHeight; - - memcpy(pScaledFrame, pFrame, bufferSize); - return bufferSize; - } - - bufferSize = frameWidth * frameHeight * colors; - memset(pScaledFrame, 0, bufferSize); - - if (scale == 1) - { - // for half scaling we take the 4 points and look if there is one colour repeated - for (int y = 0; y < m_romHeight; y += 2) - { - for (int x = 0; x < m_romWidth; x += 2) - { - uint16_t upper_left = y * m_romWidth * colors + x * colors; - uint16_t upper_right = upper_left + colors; - uint16_t lower_left = upper_left + m_romWidth * colors; - uint16_t lower_right = lower_left + colors; - uint16_t target = (xoffset + (x / 2) + (y / 2) * frameWidth) * colors; - - // Prefer most outer upper_lefts. - if (x < m_romWidth / 2) - { - if (y < m_romHeight / 2) - { - if (CmpColor(&pFrame[upper_left], &pFrame[upper_right], colors) || CmpColor(&pFrame[upper_left], &pFrame[lower_left], colors) || CmpColor(&pFrame[upper_left], &pFrame[lower_right], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); - } - else if (CmpColor(&pFrame[upper_right], &pFrame[lower_left], colors) || CmpColor(&pFrame[upper_right], &pFrame[lower_right], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); - } - else if (CmpColor(&pFrame[lower_left], &pFrame[lower_right], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); - } - else - { - SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); - } - } - else - { - if (CmpColor(&pFrame[lower_left], &pFrame[lower_right], colors) || CmpColor(&pFrame[lower_left], &pFrame[upper_left], colors) || CmpColor(&pFrame[lower_left], &pFrame[upper_right], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); - } - else if (CmpColor(&pFrame[lower_right], &pFrame[upper_left], colors) || CmpColor(&pFrame[lower_right], &pFrame[upper_right], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); - } - else if (CmpColor(&pFrame[upper_left], &pFrame[upper_right], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); - } - else - { - SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); - } - } - } - else - { - if (y < m_romHeight / 2) - { - if (CmpColor(&pFrame[upper_right], &pFrame[upper_left], colors) || CmpColor(&pFrame[upper_right], &pFrame[lower_right], colors) || CmpColor(&pFrame[upper_right], &pFrame[lower_left], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); - } - else if (CmpColor(&pFrame[upper_left], &pFrame[lower_right], colors) || CmpColor(&pFrame[upper_left], &pFrame[lower_left], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); - } - else if (CmpColor(&pFrame[lower_right], &pFrame[lower_left], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); - } - else - { - SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); - } - } - else - { - if (CmpColor(&pFrame[lower_right], &pFrame[lower_left], colors) || CmpColor(&pFrame[lower_right], &pFrame[upper_right], colors) || CmpColor(&pFrame[lower_right], &pFrame[upper_left], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); - } - else if (CmpColor(&pFrame[lower_left], &pFrame[upper_right], colors) || CmpColor(&pFrame[lower_left], &pFrame[upper_left], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); - } - else if (CmpColor(&pFrame[upper_right], &pFrame[upper_left], colors)) - { - SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); - } - else - { - SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); - } - } - } - } - } - } - else if (scale == 2) - { - // we implement scale2x http://www.scale2x.it/algorithm - uint16_t row = m_romWidth * colors; - uint8_t *a = (uint8_t *)malloc(colors); - uint8_t *b = (uint8_t *)malloc(colors); - uint8_t *c = (uint8_t *)malloc(colors); - uint8_t *d = (uint8_t *)malloc(colors); - uint8_t *e = (uint8_t *)malloc(colors); - uint8_t *f = (uint8_t *)malloc(colors); - uint8_t *g = (uint8_t *)malloc(colors); - uint8_t *h = (uint8_t *)malloc(colors); - uint8_t *i = (uint8_t *)malloc(colors); - - for (int x = 0; x < m_romHeight; x++) - { - for (int y = 0; y < m_romWidth; y++) - { - for (uint8_t tc = 0; tc < colors; tc++) - { - if (y == 0 && x == 0) - { - a[tc] = b[tc] = d[tc] = e[tc] = pFrame[tc]; - c[tc] = f[tc] = pFrame[colors + tc]; - g[tc] = h[tc] = pFrame[row + tc]; - i[tc] = pFrame[row + colors + tc]; - } - else if ((y == 0) && (x == m_romHeight - 1)) - { - a[tc] = b[tc] = pFrame[(x - 1) * row + tc]; - c[tc] = pFrame[(x - 1) * row + colors + tc]; - d[tc] = g[tc] = h[tc] = e[tc] = pFrame[x * row + tc]; - f[tc] = i[tc] = pFrame[x * row + colors + tc]; - } - else if ((y == m_romWidth - 1) && (x == 0)) - { - a[tc] = d[tc] = pFrame[y * colors - colors + tc]; - b[tc] = c[tc] = f[tc] = e[tc] = pFrame[y * colors + tc]; - g[tc] = pFrame[row + y * colors - colors + tc]; - h[tc] = i[tc] = pFrame[row + y * colors + tc]; - } - else if ((y == m_romWidth - 1) && (x == m_romHeight - 1)) - { - a[tc] = pFrame[x * row - 2 * colors + tc]; - b[tc] = c[tc] = pFrame[x * row - colors + tc]; - d[tc] = g[tc] = pFrame[m_romHeight * row - 2 * colors + tc]; - e[tc] = f[tc] = h[tc] = i[tc] = pFrame[m_romHeight * row - colors + tc]; - } - else if (y == 0) - { - a[tc] = b[tc] = pFrame[(x - 1) * row + tc]; - c[tc] = pFrame[(x - 1) * row + colors + tc]; - d[tc] = e[tc] = pFrame[x * row + tc]; - f[tc] = pFrame[x * row + colors + tc]; - g[tc] = h[tc] = pFrame[(x + 1) * row + tc]; - i[tc] = pFrame[(x + 1) * row + colors + tc]; - } - else if (y == m_romWidth - 1) - { - a[tc] = pFrame[x * row - 2 * colors + tc]; - b[tc] = c[tc] = pFrame[x * row - colors + tc]; - d[tc] = pFrame[(x + 1) * row - 2 * colors + tc]; - e[tc] = f[tc] = pFrame[(x + 1) * row - colors + tc]; - g[tc] = pFrame[(x + 2) * row - 2 * colors + tc]; - h[tc] = i[tc] = pFrame[(x + 2) * row - colors + tc]; - } - else if (x == 0) - { - a[tc] = d[tc] = pFrame[y * colors - colors + tc]; - b[tc] = e[tc] = pFrame[y * colors + tc]; - c[tc] = f[tc] = pFrame[y * colors + colors + tc]; - g[tc] = pFrame[row + y * colors - colors + tc]; - h[tc] = pFrame[row + y * colors + tc]; - i[tc] = pFrame[row + y * colors + colors + tc]; - } - else if (x == m_romHeight - 1) - { - a[tc] = pFrame[(x - 1) * row + y * colors - colors + tc]; - b[tc] = pFrame[(x - 1) * row + y * colors + tc]; - c[tc] = pFrame[(x - 1) * row + y * colors + colors + tc]; - d[tc] = g[tc] = pFrame[x * row + y * colors - colors + tc]; - e[tc] = h[tc] = pFrame[x * row + y * colors + tc]; - f[tc] = i[tc] = pFrame[x * row + y * colors + colors + tc]; - } - else - { - a[tc] = pFrame[(x - 1) * row + y * colors - colors + tc]; - b[tc] = pFrame[(x - 1) * row + y * colors + tc]; - c[tc] = pFrame[(x - 1) * row + y * colors + colors + tc]; - d[tc] = pFrame[x * row + y * colors - colors + tc]; - e[tc] = pFrame[x * row + y * colors + tc]; - f[tc] = pFrame[x * row + y * colors + colors + tc]; - g[tc] = pFrame[(x + 1) * row + y * colors - colors + tc]; - h[tc] = pFrame[(x + 1) * row + y * colors + tc]; - i[tc] = pFrame[(x + 1) * row + y * colors + colors + tc]; - } +void +ZeDMD::Split(uint8_t* pPlanes, uint16_t width, uint16_t height, uint8_t bitlen, uint8_t* pFrame) { + int planeSize = width * height / 8; + int pos = 0; + uint8_t* bd = (uint8_t*)malloc(bitlen); + + for (int y = 0; y < height; y++) { + for (int x = 0; x < width; x += 8) { + memset(bd, 0, bitlen * sizeof(uint8_t)); + + for (int v = 7; v >= 0; v--) { + uint8_t pixel = pFrame[(y * width) + (x + v)]; + for (int i = 0; i < bitlen; i++) { + bd[i] <<= 1; + if ((pixel & (1 << i)) != 0) + bd[i] |= 1; + } } - if (!CmpColor(b, h, colors) && !CmpColor(d, f, colors)) - { - SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + xoffset) * colors], CmpColor(d, b, colors) ? d : e, colors); - SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + 1 + xoffset) * colors], CmpColor(b, f, colors) ? f : e, colors); - SetColor(&pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + xoffset) * colors], CmpColor(d, h, colors) ? d : e, colors); - SetColor(&pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + 1 + xoffset) * colors], CmpColor(h, f, colors) ? f : e, colors); + for (int i = 0; i < bitlen; i++) + pPlanes[i * planeSize + pos] = bd[i]; + + pos++; + } + } + + free(bd); +} + +void +ZeDMD::ConvertToRgb24(uint8_t* pFrameRgb24, uint8_t* pFrame, int size, uint8_t* pPalette) { + for (int i = 0; i < size; i++) { + memcpy(&pFrameRgb24[i * 3], &pPalette[pFrame[i] * 3], 3); + } +} + +bool +ZeDMD::CmpColor(uint8_t* px1, uint8_t* px2, uint8_t colors) { + if (colors == 3) { + return (px1[0] == px2[0]) && (px1[1] == px2[1]) && (px1[2] == px2[2]); + } + + return px1[0] == px2[0]; +} + +void +ZeDMD::SetColor(uint8_t* px1, uint8_t* px2, uint8_t colors) { + px1[0] = px2[0]; + + if (colors == 3) { + px1[1] = px2[1]; + px1[2] = px2[2]; + } +} + +int +ZeDMD::Scale(uint8_t* pScaledFrame, uint8_t* pFrame, uint8_t colors, uint16_t* width, uint16_t* height) { + int xoffset = 0; + int yoffset = 0; + uint8_t scale = 0; // 0 - no scale, 1 - half scale, 2 - double scale + uint16_t frameWidth = m_pZeDMDComm->GetWidth(); + uint16_t frameHeight = m_pZeDMDComm->GetHeight(); + int bufferSize = m_romWidth * m_romHeight * colors; + + if (m_upscaling && m_romWidth == 192 && frameWidth == 256) { + (*width) = frameWidth; + (*height) = frameHeight; + + xoffset = 32; + } else if (m_downscaling && m_romWidth == 192) { + (*width) = frameWidth; + (*height) = frameHeight; + + xoffset = 16; + scale = 1; + } else if (m_upscaling && m_romHeight == 16 && frameHeight == 32) { + (*width) = frameWidth; + (*height) = frameHeight; + + yoffset = 8; + } else if (m_upscaling && m_romHeight == 16 && frameHeight == 64) { + (*width) = frameWidth; + (*height) = frameHeight; + + yoffset = 16; + scale = 2; + } else if (m_downscaling && m_romWidth == 256 && frameWidth == 128) { + (*width) = frameWidth; + (*height) = frameHeight; + + scale = 1; + } else if (m_upscaling && m_romWidth == 128 && frameWidth == 256) { + (*width) = frameWidth; + (*height) = frameHeight; + + scale = 2; + } else { + (*width) = m_romWidth; + (*height) = m_romHeight; + + memcpy(pScaledFrame, pFrame, bufferSize); + return bufferSize; + } + + bufferSize = frameWidth * frameHeight * colors; + memset(pScaledFrame, 0, bufferSize); + + if (scale == 1) { + // for half scaling we take the 4 points and look if there is one colour repeated + for (int y = 0; y < m_romHeight; y += 2) { + for (int x = 0; x < m_romWidth; x += 2) { + uint16_t upper_left = y * m_romWidth * colors + x * colors; + uint16_t upper_right = upper_left + colors; + uint16_t lower_left = upper_left + m_romWidth * colors; + uint16_t lower_right = lower_left + colors; + uint16_t target = (xoffset + (x / 2) + (y / 2) * frameWidth) * colors; + + // Prefer most outer upper_lefts. + if (x < m_romWidth / 2) { + if (y < m_romHeight / 2) { + if (CmpColor(&pFrame[upper_left], &pFrame[upper_right], colors) + || CmpColor(&pFrame[upper_left], &pFrame[lower_left], colors) + || CmpColor(&pFrame[upper_left], &pFrame[lower_right], colors)) { + SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); + } else if (CmpColor(&pFrame[upper_right], &pFrame[lower_left], colors) + || CmpColor(&pFrame[upper_right], &pFrame[lower_right], colors)) { + SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); + } else if (CmpColor(&pFrame[lower_left], &pFrame[lower_right], colors)) { + SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); + } else { + SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); + } + } else { + if (CmpColor(&pFrame[lower_left], &pFrame[lower_right], colors) + || CmpColor(&pFrame[lower_left], &pFrame[upper_left], colors) + || CmpColor(&pFrame[lower_left], &pFrame[upper_right], colors)) { + SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); + } else if (CmpColor(&pFrame[lower_right], &pFrame[upper_left], colors) + || CmpColor(&pFrame[lower_right], &pFrame[upper_right], colors)) { + SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); + } else if (CmpColor(&pFrame[upper_left], &pFrame[upper_right], colors)) { + SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); + } else { + SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); + } + } + } else { + if (y < m_romHeight / 2) { + if (CmpColor(&pFrame[upper_right], &pFrame[upper_left], colors) + || CmpColor(&pFrame[upper_right], &pFrame[lower_right], colors) + || CmpColor(&pFrame[upper_right], &pFrame[lower_left], colors)) { + SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); + } else if (CmpColor(&pFrame[upper_left], &pFrame[lower_right], colors) + || CmpColor(&pFrame[upper_left], &pFrame[lower_left], colors)) { + SetColor(&pScaledFrame[target], &pFrame[upper_left], colors); + } else if (CmpColor(&pFrame[lower_right], &pFrame[lower_left], colors)) { + SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); + } else { + SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); + } + } else { + if (CmpColor(&pFrame[lower_right], &pFrame[lower_left], colors) + || CmpColor(&pFrame[lower_right], &pFrame[upper_right], colors) + || CmpColor(&pFrame[lower_right], &pFrame[upper_left], colors)) { + SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); + } else if (CmpColor(&pFrame[lower_left], &pFrame[upper_right], colors) + || CmpColor(&pFrame[lower_left], &pFrame[upper_left], colors)) { + SetColor(&pScaledFrame[target], &pFrame[lower_left], colors); + } else if (CmpColor(&pFrame[upper_right], &pFrame[upper_left], colors)) { + SetColor(&pScaledFrame[target], &pFrame[upper_right], colors); + } else { + SetColor(&pScaledFrame[target], &pFrame[lower_right], colors); + } + } + } } - else - { - SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + xoffset) * colors], e, colors); - SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + 1 + xoffset) * colors], e, colors); - SetColor(&pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + xoffset) * colors], e, colors); - SetColor(&pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + 1 + xoffset) * colors], e, colors); + } + } else if (scale == 2) { + // we implement scale2x http://www.scale2x.it/algorithm + uint16_t row = m_romWidth * colors; + uint8_t* a = (uint8_t*)malloc(colors); + uint8_t* b = (uint8_t*)malloc(colors); + uint8_t* c = (uint8_t*)malloc(colors); + uint8_t* d = (uint8_t*)malloc(colors); + uint8_t* e = (uint8_t*)malloc(colors); + uint8_t* f = (uint8_t*)malloc(colors); + uint8_t* g = (uint8_t*)malloc(colors); + uint8_t* h = (uint8_t*)malloc(colors); + uint8_t* i = (uint8_t*)malloc(colors); + + for (int x = 0; x < m_romHeight; x++) { + for (int y = 0; y < m_romWidth; y++) { + for (uint8_t tc = 0; tc < colors; tc++) { + if (y == 0 && x == 0) { + a[tc] = b[tc] = d[tc] = e[tc] = pFrame[tc]; + c[tc] = f[tc] = pFrame[colors + tc]; + g[tc] = h[tc] = pFrame[row + tc]; + i[tc] = pFrame[row + colors + tc]; + } else if ((y == 0) && (x == m_romHeight - 1)) { + a[tc] = b[tc] = pFrame[(x - 1) * row + tc]; + c[tc] = pFrame[(x - 1) * row + colors + tc]; + d[tc] = g[tc] = h[tc] = e[tc] = pFrame[x * row + tc]; + f[tc] = i[tc] = pFrame[x * row + colors + tc]; + } else if ((y == m_romWidth - 1) && (x == 0)) { + a[tc] = d[tc] = pFrame[y * colors - colors + tc]; + b[tc] = c[tc] = f[tc] = e[tc] = pFrame[y * colors + tc]; + g[tc] = pFrame[row + y * colors - colors + tc]; + h[tc] = i[tc] = pFrame[row + y * colors + tc]; + } else if ((y == m_romWidth - 1) && (x == m_romHeight - 1)) { + a[tc] = pFrame[x * row - 2 * colors + tc]; + b[tc] = c[tc] = pFrame[x * row - colors + tc]; + d[tc] = g[tc] = pFrame[m_romHeight * row - 2 * colors + tc]; + e[tc] = f[tc] = h[tc] = i[tc] = pFrame[m_romHeight * row - colors + tc]; + } else if (y == 0) { + a[tc] = b[tc] = pFrame[(x - 1) * row + tc]; + c[tc] = pFrame[(x - 1) * row + colors + tc]; + d[tc] = e[tc] = pFrame[x * row + tc]; + f[tc] = pFrame[x * row + colors + tc]; + g[tc] = h[tc] = pFrame[(x + 1) * row + tc]; + i[tc] = pFrame[(x + 1) * row + colors + tc]; + } else if (y == m_romWidth - 1) { + a[tc] = pFrame[x * row - 2 * colors + tc]; + b[tc] = c[tc] = pFrame[x * row - colors + tc]; + d[tc] = pFrame[(x + 1) * row - 2 * colors + tc]; + e[tc] = f[tc] = pFrame[(x + 1) * row - colors + tc]; + g[tc] = pFrame[(x + 2) * row - 2 * colors + tc]; + h[tc] = i[tc] = pFrame[(x + 2) * row - colors + tc]; + } else if (x == 0) { + a[tc] = d[tc] = pFrame[y * colors - colors + tc]; + b[tc] = e[tc] = pFrame[y * colors + tc]; + c[tc] = f[tc] = pFrame[y * colors + colors + tc]; + g[tc] = pFrame[row + y * colors - colors + tc]; + h[tc] = pFrame[row + y * colors + tc]; + i[tc] = pFrame[row + y * colors + colors + tc]; + } else if (x == m_romHeight - 1) { + a[tc] = pFrame[(x - 1) * row + y * colors - colors + tc]; + b[tc] = pFrame[(x - 1) * row + y * colors + tc]; + c[tc] = pFrame[(x - 1) * row + y * colors + colors + tc]; + d[tc] = g[tc] = pFrame[x * row + y * colors - colors + tc]; + e[tc] = h[tc] = pFrame[x * row + y * colors + tc]; + f[tc] = i[tc] = pFrame[x * row + y * colors + colors + tc]; + } else { + a[tc] = pFrame[(x - 1) * row + y * colors - colors + tc]; + b[tc] = pFrame[(x - 1) * row + y * colors + tc]; + c[tc] = pFrame[(x - 1) * row + y * colors + colors + tc]; + d[tc] = pFrame[x * row + y * colors - colors + tc]; + e[tc] = pFrame[x * row + y * colors + tc]; + f[tc] = pFrame[x * row + y * colors + colors + tc]; + g[tc] = pFrame[(x + 1) * row + y * colors - colors + tc]; + h[tc] = pFrame[(x + 1) * row + y * colors + tc]; + i[tc] = pFrame[(x + 1) * row + y * colors + colors + tc]; + } + } + + if (!CmpColor(b, h, colors) && !CmpColor(d, f, colors)) { + SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + xoffset) * colors], + CmpColor(d, b, colors) ? d : e, colors); + SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + 1 + xoffset) * colors], + CmpColor(b, f, colors) ? f : e, colors); + SetColor( + &pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + xoffset) * colors], + CmpColor(d, h, colors) ? d : e, colors); + SetColor( + &pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + 1 + xoffset) * colors], + CmpColor(h, f, colors) ? f : e, colors); + } else { + SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + xoffset) * colors], e, + colors); + SetColor(&pScaledFrame[(yoffset * frameWidth + x * 2 * frameWidth + y * 2 + 1 + xoffset) * colors], + e, colors); + SetColor( + &pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + xoffset) * colors], e, + colors); + SetColor( + &pScaledFrame[(yoffset * frameWidth + (x * 2 + 1) * frameWidth + y * 2 + 1 + xoffset) * colors], + e, colors); + } } - } - } - - free(a); - free(b); - free(c); - free(d); - free(e); - free(f); - free(g); - free(h); - free(i); - } - else // offset!=0 - { - for (int y = 0; y < m_romHeight; y++) - { - for (int x = 0; x < m_romWidth; x++) - { - for (uint8_t c = 0; c < colors; c++) - { - pScaledFrame[((yoffset + y) * frameWidth + xoffset + x) * colors + c] = pFrame[(y * m_romWidth + x) * colors + c]; + } + + free(a); + free(b); + free(c); + free(d); + free(e); + free(f); + free(g); + free(h); + free(i); + } else // offset!=0 + { + for (int y = 0; y < m_romHeight; y++) { + for (int x = 0; x < m_romWidth; x++) { + for (uint8_t c = 0; c < colors; c++) { + pScaledFrame[((yoffset + y) * frameWidth + xoffset + x) * colors + c] = + pFrame[(y * m_romWidth + x) * colors + c]; + } } - } - } - } - - return bufferSize; -} - -ZEDMDAPI ZeDMD *ZeDMD_GetInstance() { return new ZeDMD(); }; -ZEDMDAPI void ZeDMD_IgnoreDevice(ZeDMD *pZeDMD, const char *const ignore_device) { return pZeDMD->IgnoreDevice(ignore_device); }; -ZEDMDAPI void ZeDMD_SetDevice(ZeDMD *pZeDMD, const char *const device) { return pZeDMD->SetDevice(device); }; -ZEDMDAPI bool ZeDMD_Open(ZeDMD *pZeDMD) { return pZeDMD->Open(); }; -ZEDMDAPI bool ZeDMD_OpenWiFi(ZeDMD *pZeDMD, const char *ip, int port) { return pZeDMD->OpenWiFi(ip, port); }; -ZEDMDAPI void ZeDMD_Close(ZeDMD *pZeDMD) { return pZeDMD->Close(); }; - -ZEDMDAPI void ZeDMD_SetFrameSize(ZeDMD *pZeDMD, uint16_t width, uint16_t height) { return pZeDMD->SetFrameSize(width, height); }; -ZEDMDAPI void ZeDMD_SetPalette(ZeDMD *pZeDMD, uint8_t *pPalette, uint8_t numColors) { return pZeDMD->SetPalette(pPalette, numColors); }; -ZEDMDAPI void ZeDMD_SetDefaultPalette(ZeDMD *pZeDMD, uint8_t bitDepth) { return pZeDMD->SetDefaultPalette(bitDepth); }; -ZEDMDAPI uint8_t *ZeDMD_GetDefaultPalette(ZeDMD *pZeDMD, uint8_t bitDepth) { return pZeDMD->GetDefaultPalette(bitDepth); }; -ZEDMDAPI void ZeDMD_LedTest(ZeDMD *pZeDMD) { return pZeDMD->LedTest(); }; -ZEDMDAPI void ZeDMD_EnableDebug(ZeDMD *pZeDMD) { return pZeDMD->EnableDebug(); }; -ZEDMDAPI void ZeDMD_DisableDebug(ZeDMD *pZeDMD) { return pZeDMD->DisableDebug(); }; -ZEDMDAPI void ZeDMD_SetRGBOrder(ZeDMD *pZeDMD, uint8_t rgbOrder) { return pZeDMD->SetRGBOrder(rgbOrder); }; -ZEDMDAPI void ZeDMD_SetBrightness(ZeDMD *pZeDMD, uint8_t brightness) { return pZeDMD->SetBrightness(brightness); }; -ZEDMDAPI void ZeDMD_SaveSettings(ZeDMD *pZeDMD) { return pZeDMD->SaveSettings(); }; -ZEDMDAPI void ZeDMD_EnablePreDownscaling(ZeDMD *pZeDMD) { return pZeDMD->EnablePreDownscaling(); }; -ZEDMDAPI void ZeDMD_DisablePreDownscaling(ZeDMD *pZeDMD) { return pZeDMD->DisablePreDownscaling(); }; -ZEDMDAPI void ZeDMD_EnablePreUpscaling(ZeDMD *pZeDMD) { return pZeDMD->EnablePreUpscaling(); }; -ZEDMDAPI void ZeDMD_DisablePreUpscaling(ZeDMD *pZeDMD) { return pZeDMD->DisablePreUpscaling(); }; -ZEDMDAPI void ZeDMD_EnableUpscaling(ZeDMD *pZeDMD) { return pZeDMD->EnableUpscaling(); }; -ZEDMDAPI void ZeDMD_DisableUpscaling(ZeDMD *pZeDMD) { return pZeDMD->DisableUpscaling(); }; -ZEDMDAPI void ZeDMD_SetWiFiSSID(ZeDMD *pZeDMD, const char *const ssid) { return pZeDMD->SetWiFiSSID(ssid); }; -ZEDMDAPI void ZeDMD_SetWiFiPassword(ZeDMD *pZeDMD, const char *const password) { return pZeDMD->SetWiFiPassword(password); }; -ZEDMDAPI void ZeDMD_SetWiFiPort(ZeDMD *pZeDMD, int port) { return pZeDMD->SetWiFiPort(port); }; -ZEDMDAPI void ZeDMD_EnforceStreaming(ZeDMD *pZeDMD) { return pZeDMD->EnforceStreaming(); }; - -ZEDMDAPI void ZeDMD_ClearScreen(ZeDMD *pZeDMD) { return pZeDMD->ClearScreen(); }; -ZEDMDAPI void ZeDMD_RenderGray2(ZeDMD *pZeDMD, uint8_t *frame) { return pZeDMD->RenderGray2(frame); }; -ZEDMDAPI void ZeDMD_RenderGray4(ZeDMD *pZeDMD, uint8_t *frame) { return pZeDMD->RenderGray4(frame); }; -ZEDMDAPI void ZeDMD_RenderColoredGray6(ZeDMD *pZeDMD, uint8_t *frame, uint8_t *rotations) { return pZeDMD->RenderColoredGray6(frame, rotations); }; -ZEDMDAPI void ZeDMD_RenderRgb24(ZeDMD *pZeDMD, uint8_t *frame) { return pZeDMD->RenderRgb24(frame); }; + } + } + + return bufferSize; +} + +ZEDMDAPI ZeDMD* +ZeDMD_GetInstance() { + return new ZeDMD(); +}; + +ZEDMDAPI void +ZeDMD_IgnoreDevice(ZeDMD* pZeDMD, const char* const ignore_device) { + return pZeDMD->IgnoreDevice(ignore_device); +}; + +ZEDMDAPI void +ZeDMD_SetDevice(ZeDMD* pZeDMD, const char* const device) { + return pZeDMD->SetDevice(device); +}; + +ZEDMDAPI bool +ZeDMD_Open(ZeDMD* pZeDMD) { + return pZeDMD->Open(); +}; + +ZEDMDAPI bool +ZeDMD_OpenWiFi(ZeDMD* pZeDMD, const char* ip, int port) { + return pZeDMD->OpenWiFi(ip, port); +}; + +ZEDMDAPI void +ZeDMD_Close(ZeDMD* pZeDMD) { + return pZeDMD->Close(); +}; + +ZEDMDAPI void +ZeDMD_SetFrameSize(ZeDMD* pZeDMD, uint16_t width, uint16_t height) { + return pZeDMD->SetFrameSize(width, height); +}; + +ZEDMDAPI void +ZeDMD_SetPalette(ZeDMD* pZeDMD, uint8_t* pPalette, uint8_t numColors) { + return pZeDMD->SetPalette(pPalette, numColors); +}; + +ZEDMDAPI void +ZeDMD_SetDefaultPalette(ZeDMD* pZeDMD, uint8_t bitDepth) { + return pZeDMD->SetDefaultPalette(bitDepth); +}; + +ZEDMDAPI uint8_t* +ZeDMD_GetDefaultPalette(ZeDMD* pZeDMD, uint8_t bitDepth) { + return pZeDMD->GetDefaultPalette(bitDepth); +}; + +ZEDMDAPI void +ZeDMD_LedTest(ZeDMD* pZeDMD) { + return pZeDMD->LedTest(); +}; + +ZEDMDAPI void +ZeDMD_EnableDebug(ZeDMD* pZeDMD) { + return pZeDMD->EnableDebug(); +}; + +ZEDMDAPI void +ZeDMD_DisableDebug(ZeDMD* pZeDMD) { + return pZeDMD->DisableDebug(); +}; + +ZEDMDAPI void +ZeDMD_SetRGBOrder(ZeDMD* pZeDMD, uint8_t rgbOrder) { + return pZeDMD->SetRGBOrder(rgbOrder); +}; + +ZEDMDAPI void +ZeDMD_SetBrightness(ZeDMD* pZeDMD, uint8_t brightness) { + return pZeDMD->SetBrightness(brightness); +}; + +ZEDMDAPI void +ZeDMD_SaveSettings(ZeDMD* pZeDMD) { + return pZeDMD->SaveSettings(); +}; + +ZEDMDAPI void +ZeDMD_EnablePreDownscaling(ZeDMD* pZeDMD) { + return pZeDMD->EnablePreDownscaling(); +}; + +ZEDMDAPI void +ZeDMD_DisablePreDownscaling(ZeDMD* pZeDMD) { + return pZeDMD->DisablePreDownscaling(); +}; + +ZEDMDAPI void +ZeDMD_EnablePreUpscaling(ZeDMD* pZeDMD) { + return pZeDMD->EnablePreUpscaling(); +}; + +ZEDMDAPI void +ZeDMD_DisablePreUpscaling(ZeDMD* pZeDMD) { + return pZeDMD->DisablePreUpscaling(); +}; + +ZEDMDAPI void +ZeDMD_EnableUpscaling(ZeDMD* pZeDMD) { + return pZeDMD->EnableUpscaling(); +}; + +ZEDMDAPI void +ZeDMD_DisableUpscaling(ZeDMD* pZeDMD) { + return pZeDMD->DisableUpscaling(); +}; + +ZEDMDAPI void +ZeDMD_SetWiFiSSID(ZeDMD* pZeDMD, const char* const ssid) { + return pZeDMD->SetWiFiSSID(ssid); +}; + +ZEDMDAPI void +ZeDMD_SetWiFiPassword(ZeDMD* pZeDMD, const char* const password) { + return pZeDMD->SetWiFiPassword(password); +}; + +ZEDMDAPI void +ZeDMD_SetWiFiPort(ZeDMD* pZeDMD, int port) { + return pZeDMD->SetWiFiPort(port); +}; + +ZEDMDAPI void +ZeDMD_EnforceStreaming(ZeDMD* pZeDMD) { + return pZeDMD->EnforceStreaming(); +}; + +ZEDMDAPI void +ZeDMD_ClearScreen(ZeDMD* pZeDMD) { + return pZeDMD->ClearScreen(); +}; + +ZEDMDAPI void +ZeDMD_RenderGray2(ZeDMD* pZeDMD, uint8_t* frame) { + return pZeDMD->RenderGray2(frame); +}; + +ZEDMDAPI void +ZeDMD_RenderGray4(ZeDMD* pZeDMD, uint8_t* frame) { + return pZeDMD->RenderGray4(frame); +}; + +ZEDMDAPI void +ZeDMD_RenderColoredGray6(ZeDMD* pZeDMD, uint8_t* frame, uint8_t* rotations) { + return pZeDMD->RenderColoredGray6(frame, rotations); +}; + +ZEDMDAPI void +ZeDMD_RenderRgb24(ZeDMD* pZeDMD, uint8_t* frame) { + return pZeDMD->RenderRgb24(frame); +}; diff --git a/src/ZeDMD.h b/src/ZeDMD.h index c2d2fd6..8a05b49 100644 --- a/src/ZeDMD.h +++ b/src/ZeDMD.h @@ -4,15 +4,16 @@ #define ZEDMD_VERSION_MINOR 3 // Max 2 Digits #define ZEDMD_VERSION_PATCH 1 // Max 2 Digits -#define _ZEDMD_STR(x) #x -#define ZEDMD_STR(x) _ZEDMD_STR(x) +#define _ZEDMD_STR(x) #x +#define ZEDMD_STR(x) _ZEDMD_STR(x) -#define ZEDMD_VERSION ZEDMD_STR(ZEDMD_VERSION_MAJOR) "." ZEDMD_STR(ZEDMD_VERSION_MINOR) "." ZEDMD_STR(ZEDMD_VERSION_PATCH) +#define ZEDMD_VERSION \ + ZEDMD_STR(ZEDMD_VERSION_MAJOR) "." ZEDMD_STR(ZEDMD_VERSION_MINOR) "." ZEDMD_STR(ZEDMD_VERSION_PATCH) #define ZEDMD_MINOR_VERSION ZEDMD_STR(ZEDMD_VERSION_MAJOR) "." ZEDMD_STR(ZEDMD_VERSION_MINOR) -#define ZEDMD_MAX_WIDTH 256 -#define ZEDMD_MAX_HEIGHT 64 -#define ZEDMD_MAX_PALETTE 192 +#define ZEDMD_MAX_WIDTH 256 +#define ZEDMD_MAX_HEIGHT 64 +#define ZEDMD_MAX_PALETTE 192 #if defined(_WIN32) || defined(_WIN64) #define ZEDMDAPI __declspec(dllexport) @@ -23,143 +24,140 @@ #endif #include -#include #include +#include #ifdef __ANDROID__ -typedef void *(*ZeDMD_AndroidGetJNIEnvFunc)(); +typedef void* (*ZeDMD_AndroidGetJNIEnvFunc)(); #endif -typedef void(CALLBACK *ZeDMD_LogMessageCallback)(const char *format, va_list args, const void *userData); +typedef void(CALLBACK* ZeDMD_LogMessageCallback)(const char* format, va_list args, const void* userData); class ZeDMDComm; class ZeDMDWiFi; -class ZEDMDAPI ZeDMD -{ -public: - ZeDMD(); - ~ZeDMD(); +class ZEDMDAPI ZeDMD { + public: + ZeDMD(); + ~ZeDMD(); #ifdef __ANDROID__ - void SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func); + void SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func); #endif - void SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void *userData); - - void IgnoreDevice(const char *const ignore_device); - void SetDevice(const char *const device); - bool Open(uint16_t width, uint16_t height); - bool Open(); - bool OpenWiFi(const char *ip, int port); - void Close(); - - void SetFrameSize(uint16_t width, uint16_t height); - void SetPalette(uint8_t *pPalette); - void SetPalette(uint8_t *pPalette, uint8_t numColors); - void SetDefaultPalette(uint8_t bitDepth); - uint8_t *GetDefaultPalette(uint8_t bitDepth); - void LedTest(); - void EnableDebug(); - void DisableDebug(); - void SetRGBOrder(uint8_t rgbOrder); - void SetBrightness(uint8_t brightness); - void SaveSettings(); - void EnablePreDownscaling(); - void DisablePreDownscaling(); - void EnablePreUpscaling(); - void DisablePreUpscaling(); - void EnableUpscaling(); - void DisableUpscaling(); - void SetWiFiSSID(const char *const ssid); - void SetWiFiPassword(const char *const password); - void SetWiFiPort(int port); - void EnforceStreaming(); - - void ClearScreen(); - void RenderGray2(uint8_t *frame); - void RenderGray4(uint8_t *frame); - void RenderColoredGray6(uint8_t *frame, uint8_t *palette, uint8_t *rotations); - void RenderColoredGray6(uint8_t *frame, uint8_t *rotations); - void RenderRgb24(uint8_t *frame); - -private: - bool UpdateFrameBuffer8(uint8_t *pFrame); - bool UpdateFrameBuffer24(uint8_t *pFrame); - - void Split(uint8_t *planes, uint16_t width, uint16_t height, uint8_t bitlen, uint8_t *frame); - void ConvertToRgb24(uint8_t *pFrameRgb24, uint8_t *pFrame, int size, uint8_t *pPalette); - bool CmpColor(uint8_t *px1, uint8_t *px2, uint8_t colors); - void SetColor(uint8_t *px1, uint8_t *px2, uint8_t colors); - int Scale(uint8_t *pScaledFrame, uint8_t *pFrame, uint8_t colors, uint16_t *width, uint16_t *height); - - ZeDMDComm *m_pZeDMDComm; - ZeDMDWiFi *m_pZeDMDWiFi; - - uint16_t m_romWidth; - uint16_t m_romHeight; - - bool m_usb = false; - bool m_wifi = false; - bool m_hd = false; - bool m_downscaling = false; - bool m_upscaling = false; - bool m_streaming = false; - bool m_paletteChanged = false; - - uint8_t *m_pFrameBuffer; - uint8_t *m_pScaledFrameBuffer; - uint8_t *m_pCommandBuffer; - uint8_t *m_pPlanes; - - uint8_t m_palette4[4 * 3] = {0}; - uint8_t m_palette16[16 * 3] = {0}; - uint8_t m_palette64[64 * 3] = {0}; - uint8_t m_DmdDefaultPalette2Bit[12] = {0, 0, 0, 144, 34, 0, 192, 76, 0, 255, 127, 0}; - uint8_t m_DmdDefaultPalette4Bit[48] = {0, 0, 0, 51, 25, 0, 64, 32, 0, 77, 38, 0, - 89, 44, 0, 102, 51, 0, 115, 57, 0, 128, 64, 0, - 140, 70, 0, 153, 76, 0, 166, 83, 0, 179, 89, 0, - 191, 95, 0, 204, 102, 0, 230, 114, 0, 255, 127, 0}; + void SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void* userData); + + void IgnoreDevice(const char* const ignore_device); + void SetDevice(const char* const device); + bool Open(uint16_t width, uint16_t height); + bool Open(); + bool OpenWiFi(const char* ip, int port); + void Close(); + + void SetFrameSize(uint16_t width, uint16_t height); + void SetPalette(uint8_t* pPalette); + void SetPalette(uint8_t* pPalette, uint8_t numColors); + void SetDefaultPalette(uint8_t bitDepth); + uint8_t* GetDefaultPalette(uint8_t bitDepth); + void LedTest(); + void EnableDebug(); + void DisableDebug(); + void SetRGBOrder(uint8_t rgbOrder); + void SetBrightness(uint8_t brightness); + void SaveSettings(); + void EnablePreDownscaling(); + void DisablePreDownscaling(); + void EnablePreUpscaling(); + void DisablePreUpscaling(); + void EnableUpscaling(); + void DisableUpscaling(); + void SetWiFiSSID(const char* const ssid); + void SetWiFiPassword(const char* const password); + void SetWiFiPort(int port); + void EnforceStreaming(); + + void ClearScreen(); + void RenderGray2(uint8_t* frame); + void RenderGray4(uint8_t* frame); + void RenderColoredGray6(uint8_t* frame, uint8_t* palette, uint8_t* rotations); + void RenderColoredGray6(uint8_t* frame, uint8_t* rotations); + void RenderRgb24(uint8_t* frame); + + private: + bool UpdateFrameBuffer8(uint8_t* pFrame); + bool UpdateFrameBuffer24(uint8_t* pFrame); + + void Split(uint8_t* planes, uint16_t width, uint16_t height, uint8_t bitlen, uint8_t* frame); + void ConvertToRgb24(uint8_t* pFrameRgb24, uint8_t* pFrame, int size, uint8_t* pPalette); + bool CmpColor(uint8_t* px1, uint8_t* px2, uint8_t colors); + void SetColor(uint8_t* px1, uint8_t* px2, uint8_t colors); + int Scale(uint8_t* pScaledFrame, uint8_t* pFrame, uint8_t colors, uint16_t* width, uint16_t* height); + + ZeDMDComm* m_pZeDMDComm; + ZeDMDWiFi* m_pZeDMDWiFi; + + uint16_t m_romWidth; + uint16_t m_romHeight; + + bool m_usb = false; + bool m_wifi = false; + bool m_hd = false; + bool m_downscaling = false; + bool m_upscaling = false; + bool m_streaming = false; + bool m_paletteChanged = false; + + uint8_t* m_pFrameBuffer; + uint8_t* m_pScaledFrameBuffer; + uint8_t* m_pCommandBuffer; + uint8_t* m_pPlanes; + + uint8_t m_palette4[4 * 3] = {0}; + uint8_t m_palette16[16 * 3] = {0}; + uint8_t m_palette64[64 * 3] = {0}; + uint8_t m_DmdDefaultPalette2Bit[12] = {0, 0, 0, 144, 34, 0, 192, 76, 0, 255, 127, 0}; + uint8_t m_DmdDefaultPalette4Bit[48] = {0, 0, 0, 51, 25, 0, 64, 32, 0, 77, 38, 0, 89, 44, 0, 102, + 51, 0, 115, 57, 0, 128, 64, 0, 140, 70, 0, 153, 76, 0, 166, 83, + 0, 179, 89, 0, 191, 95, 0, 204, 102, 0, 230, 114, 0, 255, 127, 0}; }; #ifdef __cplusplus -extern "C" -{ +extern "C" { #endif - extern ZEDMDAPI ZeDMD *ZeDMD_GetInstance(); - extern ZEDMDAPI void ZeDMD_IgnoreDevice(ZeDMD *pZeDMD, const char *const ignore_device); - extern ZEDMDAPI void ZeDMD_SetDevice(ZeDMD *pZeDMD, const char *const device); - extern ZEDMDAPI bool ZeDMD_Open(ZeDMD *pZeDMD); - extern ZEDMDAPI bool ZeDMD_OpenWiFi(ZeDMD *pZeDMD, const char *ip, int port); - extern ZEDMDAPI void ZeDMD_Close(ZeDMD *pZeDMD); - - extern ZEDMDAPI void ZeDMD_SetFrameSize(ZeDMD *pZeDMD, uint16_t width, uint16_t height); - extern ZEDMDAPI void ZeDMD_SetPalette(ZeDMD *pZeDMD, uint8_t *pPalette, uint8_t numColors); - extern ZEDMDAPI void ZeDMD_SetDefaultPalette(ZeDMD *pZeDMD, uint8_t bitDepth); - extern ZEDMDAPI uint8_t *ZeDMD_GetDefaultPalette(ZeDMD *pZeDMD, uint8_t bitDepth); - extern ZEDMDAPI void ZeDMD_LedTest(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_EnableDebug(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_DisableDebug(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_SetRGBOrder(ZeDMD *pZeDMD, uint8_t rgbOrder); - extern ZEDMDAPI void ZeDMD_SetBrightness(ZeDMD *pZeDMD, uint8_t brightness); - extern ZEDMDAPI void ZeDMD_SaveSettings(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_EnablePreDownscaling(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_DisablePreDownscaling(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_EnablePreUpscaling(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_DisablePreUpscaling(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_EnableUpscaling(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_DisableUpscaling(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_SetWiFiSSID(ZeDMD *pZeDMD, const char *const ssid); - extern ZEDMDAPI void ZeDMD_SetWiFiPassword(ZeDMD *pZeDMD, const char *const password); - extern ZEDMDAPI void ZeDMD_SetWiFiPort(ZeDMD *pZeDMD, int port); - extern ZEDMDAPI void ZeDMD_EnforceStreaming(ZeDMD *pZeDMD); - - extern ZEDMDAPI void ZeDMD_ClearScreen(ZeDMD *pZeDMD); - extern ZEDMDAPI void ZeDMD_RenderGray2(ZeDMD *pZeDMD, uint8_t *frame); - extern ZEDMDAPI void ZeDMD_RenderGray4(ZeDMD *pZeDMD, uint8_t *frame); - extern ZEDMDAPI void ZeDMD_RenderColoredGray6(ZeDMD *pZeDMD, uint8_t *frame, uint8_t *rotations); - extern ZEDMDAPI void ZeDMD_RenderRgb24(ZeDMD *pZeDMD, uint8_t *frame); +extern ZEDMDAPI ZeDMD* ZeDMD_GetInstance(); +extern ZEDMDAPI void ZeDMD_IgnoreDevice(ZeDMD* pZeDMD, const char* const ignore_device); +extern ZEDMDAPI void ZeDMD_SetDevice(ZeDMD* pZeDMD, const char* const device); +extern ZEDMDAPI bool ZeDMD_Open(ZeDMD* pZeDMD); +extern ZEDMDAPI bool ZeDMD_OpenWiFi(ZeDMD* pZeDMD, const char* ip, int port); +extern ZEDMDAPI void ZeDMD_Close(ZeDMD* pZeDMD); + +extern ZEDMDAPI void ZeDMD_SetFrameSize(ZeDMD* pZeDMD, uint16_t width, uint16_t height); +extern ZEDMDAPI void ZeDMD_SetPalette(ZeDMD* pZeDMD, uint8_t* pPalette, uint8_t numColors); +extern ZEDMDAPI void ZeDMD_SetDefaultPalette(ZeDMD* pZeDMD, uint8_t bitDepth); +extern ZEDMDAPI uint8_t* ZeDMD_GetDefaultPalette(ZeDMD* pZeDMD, uint8_t bitDepth); +extern ZEDMDAPI void ZeDMD_LedTest(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_EnableDebug(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_DisableDebug(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_SetRGBOrder(ZeDMD* pZeDMD, uint8_t rgbOrder); +extern ZEDMDAPI void ZeDMD_SetBrightness(ZeDMD* pZeDMD, uint8_t brightness); +extern ZEDMDAPI void ZeDMD_SaveSettings(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_EnablePreDownscaling(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_DisablePreDownscaling(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_EnablePreUpscaling(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_DisablePreUpscaling(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_EnableUpscaling(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_DisableUpscaling(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_SetWiFiSSID(ZeDMD* pZeDMD, const char* const ssid); +extern ZEDMDAPI void ZeDMD_SetWiFiPassword(ZeDMD* pZeDMD, const char* const password); +extern ZEDMDAPI void ZeDMD_SetWiFiPort(ZeDMD* pZeDMD, int port); +extern ZEDMDAPI void ZeDMD_EnforceStreaming(ZeDMD* pZeDMD); + +extern ZEDMDAPI void ZeDMD_ClearScreen(ZeDMD* pZeDMD); +extern ZEDMDAPI void ZeDMD_RenderGray2(ZeDMD* pZeDMD, uint8_t* frame); +extern ZEDMDAPI void ZeDMD_RenderGray4(ZeDMD* pZeDMD, uint8_t* frame); +extern ZEDMDAPI void ZeDMD_RenderColoredGray6(ZeDMD* pZeDMD, uint8_t* frame, uint8_t* rotations); +extern ZEDMDAPI void ZeDMD_RenderRgb24(ZeDMD* pZeDMD, uint8_t* frame); #ifdef __cplusplus } diff --git a/src/ZeDMDComm.cpp b/src/ZeDMDComm.cpp index 09fd5be..ab836f8 100644 --- a/src/ZeDMDComm.cpp +++ b/src/ZeDMDComm.cpp @@ -1,540 +1,474 @@ #include "ZeDMDComm.h" -#include "miniz/miniz.h" #include "komihash/komihash.h" +#include "miniz/miniz.h" -ZeDMDComm::ZeDMDComm() -{ - m_pThread = NULL; -} +ZeDMDComm::ZeDMDComm() { m_pThread = NULL; } -ZeDMDComm::~ZeDMDComm() -{ - if (m_pThread) - { - m_pThread->join(); +ZeDMDComm::~ZeDMDComm() { + if (m_pThread) { + m_pThread->join(); - delete m_pThread; - } + delete m_pThread; + } } #ifdef __ANDROID__ -void ZeDMDComm::SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func) -{ - m_serialPort.SetAndroidGetJNIEnvFunc(func); +void +ZeDMDComm::SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func) { + m_serialPort.SetAndroidGetJNIEnvFunc(func); } #endif -void ZeDMDComm::SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void *userData) -{ - m_logMessageCallback = callback; - m_logMessageUserData = userData; +void +ZeDMDComm::SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void* userData) { + m_logMessageCallback = callback; + m_logMessageUserData = userData; } -void ZeDMDComm::LogMessage(const char *format, ...) -{ - if (!m_logMessageCallback) - return; +void +ZeDMDComm::LogMessage(const char* format, ...) { + if (!m_logMessageCallback) + return; - va_list args; - va_start(args, format); - (*(m_logMessageCallback))(format, args, m_logMessageUserData); - va_end(args); + va_list args; + va_start(args, format); + (*(m_logMessageCallback))(format, args, m_logMessageUserData); + va_end(args); } -void ZeDMDComm::Run() -{ - m_pThread = new std::thread([this]() - { - LogMessage("ZeDMDComm run thread starting"); - int8_t lastStreamId = -1; - - while (IsConnected()) - { - m_frameQueueMutex.lock(); - - if (m_frames.empty()) - { - m_delayedFrameMutex.lock(); - if (m_delayedFrameReady) { - while (m_delayedFrames.size() > 0) - { - ZeDMDFrame frame = m_delayedFrames.front(); - lastStreamId = frame.streamId; - m_frames.push(frame); - m_delayedFrames.pop(); - } - m_delayedFrameReady = false; - m_frameCounter = 1; - m_delayedFrameMutex.unlock(); - m_frameQueueMutex.unlock(); - continue; - } - m_delayedFrameMutex.unlock(); - m_frameQueueMutex.unlock(); - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - continue; - } - else - { - bool delay = false; - m_delayedFrameMutex.lock(); - delay = m_delayedFrameReady; - m_delayedFrameMutex.unlock(); - - if (delay && m_frameCounter > ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX_DELAYED) { - while (m_frames.size() > 0) - { - m_frames.pop(); - } - m_frameCounter = 0; - m_frameQueueMutex.unlock(); - continue; - } - } - - ZeDMDFrame frame = m_frames.front(); - m_frames.pop(); - if (frame.streamId != -1) - { - if (frame.streamId != lastStreamId) - { - if (lastStreamId != -1) - { - m_frameCounter--; - } - - lastStreamId = frame.streamId; - } - } - else { - m_frameCounter--; - } - m_frameQueueMutex.unlock(); - - bool success = StreamBytes(&frame); - if (!success && frame.size < ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT) - { - std::this_thread::sleep_for(std::chrono::milliseconds(8)); - // Try to send the command again, in case the wait for the (R)eady signal ran into a timeout. - success = StreamBytes(&frame); - } - - if (frame.data) - { - free(frame.data); - } - - if (!success) - { - std::this_thread::sleep_for(std::chrono::milliseconds(2)); - } - } - - LogMessage("ZeDMDComm run thread finished"); }); +void +ZeDMDComm::Run() { + m_pThread = new std::thread([this]() { + LogMessage("ZeDMDComm run thread starting"); + int8_t lastStreamId = -1; + + while (IsConnected()) { + m_frameQueueMutex.lock(); + + if (m_frames.empty()) { + m_delayedFrameMutex.lock(); + if (m_delayedFrameReady) { + while (m_delayedFrames.size() > 0) { + ZeDMDFrame frame = m_delayedFrames.front(); + lastStreamId = frame.streamId; + m_frames.push(frame); + m_delayedFrames.pop(); + } + m_delayedFrameReady = false; + m_frameCounter = 1; + m_delayedFrameMutex.unlock(); + m_frameQueueMutex.unlock(); + continue; + } + m_delayedFrameMutex.unlock(); + m_frameQueueMutex.unlock(); + std::this_thread::sleep_for(std::chrono::milliseconds(1)); + continue; + } else { + bool delay = false; + m_delayedFrameMutex.lock(); + delay = m_delayedFrameReady; + m_delayedFrameMutex.unlock(); + + if (delay && m_frameCounter > ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX_DELAYED) { + while (m_frames.size() > 0) { + m_frames.pop(); + } + m_frameCounter = 0; + m_frameQueueMutex.unlock(); + continue; + } + } + + ZeDMDFrame frame = m_frames.front(); + m_frames.pop(); + if (frame.streamId != -1) { + if (frame.streamId != lastStreamId) { + if (lastStreamId != -1) { + m_frameCounter--; + } + + lastStreamId = frame.streamId; + } + } else { + m_frameCounter--; + } + m_frameQueueMutex.unlock(); + + bool success = StreamBytes(&frame); + if (!success && frame.size < ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT) { + std::this_thread::sleep_for(std::chrono::milliseconds(8)); + // Try to send the command again, in case the wait for the (R)eady signal ran into a timeout. + success = StreamBytes(&frame); + } + + if (frame.data) { + free(frame.data); + } + + if (!success) { + std::this_thread::sleep_for(std::chrono::milliseconds(2)); + } + } + + LogMessage("ZeDMDComm run thread finished"); + }); } -void ZeDMDComm::QueueCommand(char command, uint8_t *data, int size, int8_t streamId, bool delayed) -{ - if (!IsConnected()) - { - return; - } - - ZeDMDFrame frame = {0}; - frame.command = command; - frame.size = size; - frame.streamId = streamId; - - if (data && size > 0) - { - frame.data = (uint8_t *)malloc(size); - memcpy(frame.data, data, size); - } - - // delayed standard frame - if (streamId == -1 && FillDelayed()) - { - m_delayedFrameMutex.lock(); - while (m_delayedFrames.size() > 0) - { - m_delayedFrames.pop(); - } - m_delayedFrames.push(frame); - m_delayedFrameReady = true; - m_delayedFrameMutex.unlock(); - m_lastStreamId = -1; - } - // delayed streamed zones - else if (streamId != -1 && delayed) - { - m_delayedFrameMutex.lock(); - m_delayedFrames.push(frame); - m_delayedFrameMutex.unlock(); - m_lastStreamId = streamId; - } - else - { - m_frameQueueMutex.lock(); - if (streamId == -1 || m_lastStreamId != streamId) - { - m_frameCounter++; - m_lastStreamId = streamId; - } - m_frames.push(frame); - m_frameQueueMutex.unlock(); - } +void +ZeDMDComm::QueueCommand(char command, uint8_t* data, int size, int8_t streamId, bool delayed) { + if (!IsConnected()) { + return; + } + + ZeDMDFrame frame = {0}; + frame.command = command; + frame.size = size; + frame.streamId = streamId; + + if (data && size > 0) { + frame.data = (uint8_t*)malloc(size); + memcpy(frame.data, data, size); + } + + // delayed standard frame + if (streamId == -1 && FillDelayed()) { + m_delayedFrameMutex.lock(); + while (m_delayedFrames.size() > 0) { + m_delayedFrames.pop(); + } + m_delayedFrames.push(frame); + m_delayedFrameReady = true; + m_delayedFrameMutex.unlock(); + m_lastStreamId = -1; + } + // delayed streamed zones + else if (streamId != -1 && delayed) { + m_delayedFrameMutex.lock(); + m_delayedFrames.push(frame); + m_delayedFrameMutex.unlock(); + m_lastStreamId = streamId; + } else { + m_frameQueueMutex.lock(); + if (streamId == -1 || m_lastStreamId != streamId) { + m_frameCounter++; + m_lastStreamId = streamId; + } + m_frames.push(frame); + m_frameQueueMutex.unlock(); + } } -void ZeDMDComm::QueueCommand(char command, uint8_t value) -{ - QueueCommand(command, &value, 1); +void +ZeDMDComm::QueueCommand(char command, uint8_t value) { + QueueCommand(command, &value, 1); } -void ZeDMDComm::QueueCommand(char command) -{ - QueueCommand(command, NULL, 0); +void +ZeDMDComm::QueueCommand(char command) { + QueueCommand(command, NULL, 0); } -void ZeDMDComm::QueueCommand(char command, uint8_t *data, int size, uint16_t width, uint16_t height) -{ - uint8_t buffer[256 * 16 * 3 + 16]; - uint16_t bufferSize = 0; - uint8_t idx = 0; - uint8_t zone[16 * 8 * 3] = {0}; - uint16_t zonesBytesLimit = 0; - if (m_zonesBytesLimit) - { - while (zonesBytesLimit < m_zonesBytesLimit) - { - zonesBytesLimit += m_zoneWidth * m_zoneHeight * 3 + 1; - } - } - else - { - zonesBytesLimit = width * m_zoneHeight * 3 + 16; - } - - if (++m_streamId > 64) - { - m_streamId = 0; - } - - bool delayed = false; - if (FillDelayed()) - { - delayed = true; - m_delayedFrameMutex.lock(); - m_delayedFrameReady = false; - while (m_delayedFrames.size() > 0) - { - m_delayedFrames.pop(); - } - m_delayedFrameMutex.unlock(); - // A delayed frame needs to be complete. - memset(m_zoneHashes, 0, 128); - } - - for (uint16_t y = 0; y < height; y += m_zoneHeight) - { - for (uint16_t x = 0; x < width; x += m_zoneWidth) - { - for (uint8_t z = 0; z < m_zoneHeight; z++) - { - memcpy(&zone[z * m_zoneWidth * 3], &data[((y + z) * width + x) * 3], m_zoneWidth * 3); - } - - uint64_t hash = komihash(zone, m_zoneWidth * m_zoneHeight * 3, 0); - if (hash != m_zoneHashes[idx]) - { - m_zoneHashes[idx] = hash; - - buffer[bufferSize++] = idx; - memcpy(&buffer[bufferSize], zone, m_zoneWidth * m_zoneHeight * 3); - bufferSize += m_zoneWidth * m_zoneHeight * 3; - - if (bufferSize >= zonesBytesLimit) - { - QueueCommand(command, buffer, bufferSize, m_streamId, delayed); - bufferSize = 0; +void +ZeDMDComm::QueueCommand(char command, uint8_t* data, int size, uint16_t width, uint16_t height) { + uint8_t buffer[256 * 16 * 3 + 16]; + uint16_t bufferSize = 0; + uint8_t idx = 0; + uint8_t zone[16 * 8 * 3] = {0}; + uint16_t zonesBytesLimit = 0; + if (m_zonesBytesLimit) { + while (zonesBytesLimit < m_zonesBytesLimit) { + zonesBytesLimit += m_zoneWidth * m_zoneHeight * 3 + 1; + } + } else { + zonesBytesLimit = width * m_zoneHeight * 3 + 16; + } + + if (++m_streamId > 64) { + m_streamId = 0; + } + + bool delayed = false; + if (FillDelayed()) { + delayed = true; + m_delayedFrameMutex.lock(); + m_delayedFrameReady = false; + while (m_delayedFrames.size() > 0) { + m_delayedFrames.pop(); + } + m_delayedFrameMutex.unlock(); + // A delayed frame needs to be complete. + memset(m_zoneHashes, 0, 128); + } + + for (uint16_t y = 0; y < height; y += m_zoneHeight) { + for (uint16_t x = 0; x < width; x += m_zoneWidth) { + for (uint8_t z = 0; z < m_zoneHeight; z++) { + memcpy(&zone[z * m_zoneWidth * 3], &data[((y + z) * width + x) * 3], m_zoneWidth * 3); + } + + uint64_t hash = komihash(zone, m_zoneWidth * m_zoneHeight * 3, 0); + if (hash != m_zoneHashes[idx]) { + m_zoneHashes[idx] = hash; + + buffer[bufferSize++] = idx; + memcpy(&buffer[bufferSize], zone, m_zoneWidth * m_zoneHeight * 3); + bufferSize += m_zoneWidth * m_zoneHeight * 3; + + if (bufferSize >= zonesBytesLimit) { + QueueCommand(command, buffer, bufferSize, m_streamId, delayed); + bufferSize = 0; + } } - } - idx++; - } - } - - if (bufferSize > 0) - { - QueueCommand(command, buffer, bufferSize, m_streamId, delayed); - } - - if (delayed) - { - m_delayedFrameMutex.lock(); - m_delayedFrameReady = true; - m_delayedFrameMutex.unlock(); - } + idx++; + } + } + + if (bufferSize > 0) { + QueueCommand(command, buffer, bufferSize, m_streamId, delayed); + } + + if (delayed) { + m_delayedFrameMutex.lock(); + m_delayedFrameReady = true; + m_delayedFrameMutex.unlock(); + } } -bool ZeDMDComm::FillDelayed() -{ - uint8_t count = 0; - bool delayed = false; - m_frameQueueMutex.lock(); - count = m_frameCounter; - delayed = m_delayedFrameReady; - m_frameQueueMutex.unlock(); - return (count > ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX) || delayed; +bool +ZeDMDComm::FillDelayed() { + uint8_t count = 0; + bool delayed = false; + m_frameQueueMutex.lock(); + count = m_frameCounter; + delayed = m_delayedFrameReady; + m_frameQueueMutex.unlock(); + return (count > ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX) || delayed; } -void ZeDMDComm::IgnoreDevice(const char *ignore_device) -{ - if (sizeof(ignore_device) < 32 && m_ignoredDevicesCounter < 10) - { - strcpy(&m_ignoredDevices[m_ignoredDevicesCounter++][0], ignore_device); - } +void +ZeDMDComm::IgnoreDevice(const char* ignore_device) { + if (sizeof(ignore_device) < 32 && m_ignoredDevicesCounter < 10) { + strcpy(&m_ignoredDevices[m_ignoredDevicesCounter++][0], ignore_device); + } } -void ZeDMDComm::SetDevice(const char *device) -{ - if (sizeof(device) < 32) - { - strcpy(&m_device[0], device); - } +void +ZeDMDComm::SetDevice(const char* device) { + if (sizeof(device) < 32) { + strcpy(&m_device[0], device); + } } -bool ZeDMDComm::Connect() -{ +bool +ZeDMDComm::Connect() { #ifndef __ANDROID__ - if (m_device[0] != 0) - { - return Connect(m_device); - } + if (m_device[0] != 0) { + return Connect(m_device); + } - char szDevice[32]; + char szDevice[32]; - for (int i = 0; i < 7; i++) - { + for (int i = 0; i < 7; i++) { #ifdef __APPLE__ - sprintf(szDevice, "/dev/cu.usbserial-%04d", i); + sprintf(szDevice, "/dev/cu.usbserial-%04d", i); #elif defined(_WIN32) || defined(_WIN64) - sprintf(szDevice, "\\\\.\\COM%d", i + 1); + sprintf(szDevice, "\\\\.\\COM%d", i + 1); #else - sprintf(szDevice, "/dev/ttyUSB%d", i); + sprintf(szDevice, "/dev/ttyUSB%d", i); #endif - for (int j = 0; j < m_ignoredDevicesCounter; j++) - { - if (strcmp(szDevice, m_ignoredDevices[j]) == 0) - { - continue; - } - } + for (int j = 0; j < m_ignoredDevicesCounter; j++) { + if (strcmp(szDevice, m_ignoredDevices[j]) == 0) { + continue; + } + } - if (Connect(szDevice)) - return true; - } + if (Connect(szDevice)) + return true; + } - return false; + return false; #else - return Connect(NULL); + return Connect(NULL); #endif } -void ZeDMDComm::Disconnect() -{ - if (!IsConnected()) - return; +void +ZeDMDComm::Disconnect() { + if (!IsConnected()) + return; - Reset(); + Reset(); - m_serialPort.Close(); + m_serialPort.Close(); } -bool ZeDMDComm::Connect(char *pDevice) -{ - m_serialPort.SetReadTimeout(ZEDMD_COMM_SERIAL_READ_TIMEOUT); - m_serialPort.SetWriteTimeout(ZEDMD_COMM_SERIAL_WRITE_TIMEOUT); +bool +ZeDMDComm::Connect(char* pDevice) { + m_serialPort.SetReadTimeout(ZEDMD_COMM_SERIAL_READ_TIMEOUT); + m_serialPort.SetWriteTimeout(ZEDMD_COMM_SERIAL_WRITE_TIMEOUT); - if (m_serialPort.Open(pDevice, ZEDMD_COMM_BAUD_RATE, 8, 1, 0) != 1) - return false; + if (m_serialPort.Open(pDevice, ZEDMD_COMM_BAUD_RATE, 8, 1, 0) != 1) + return false; - Reset(); + Reset(); - uint8_t data[8] = {0}; + uint8_t data[8] = {0}; - // Android in general but also ZeDMD HD require some time after opening the device. - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + // Android in general but also ZeDMD HD require some time after opening the device. + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - // ESP32 sends some information about itself before we could use the line. - while (m_serialPort.Available() > 0) - m_serialPort.ReadBytes(data, 8); + // ESP32 sends some information about itself before we could use the line. + while (m_serialPort.Available() > 0) + m_serialPort.ReadBytes(data, 8); #ifdef __ANDROID__ - // Android returns a large buffer of 80 and 00, so wait and read again to clear - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + // Android returns a large buffer of 80 and 00, so wait and read again to clear + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); - while (m_serialPort.Available() > 0) - m_serialPort.ReadBytes(data, 8); + while (m_serialPort.Available() > 0) + m_serialPort.ReadBytes(data, 8); #endif - m_serialPort.WriteBytes((uint8_t *)CTRL_CHARS_HEADER, CTRL_CHARS_HEADER_SIZE); - m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::Handshake); - std::this_thread::sleep_for(std::chrono::milliseconds(200)); - - if (m_serialPort.ReadBytes(data, 8)) - { - if (!memcmp(data, CTRL_CHARS_HEADER, 4)) - { - m_width = data[4] + data[5] * 256; - m_height = data[6] + data[7] * 256; - m_zoneWidth = m_width / 16; - m_zoneHeight = m_height / 8; - - uint8_t response; - - if (m_serialPort.ReadByte() == 'R') - { - m_serialPort.WriteBytes((uint8_t *)CTRL_CHARS_HEADER, 6); - m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::Compression); - std::this_thread::sleep_for(std::chrono::milliseconds(4)); - - if (m_serialPort.ReadByte() == 'A' && m_serialPort.ReadByte() == 'R') - { - m_serialPort.WriteBytes((uint8_t *)CTRL_CHARS_HEADER, 6); - m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::Chunk); - m_serialPort.WriteChar(ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE / 256); - std::this_thread::sleep_for(std::chrono::milliseconds(4)); - - if (m_serialPort.ReadByte() == 'A' && m_serialPort.ReadByte() == 'R') - { - m_serialPort.WriteBytes((uint8_t *)CTRL_CHARS_HEADER, 6); - m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::EnableFlowControlV2); - std::this_thread::sleep_for(std::chrono::milliseconds(4)); - - if (m_serialPort.ReadByte() == 'A') - { - m_flowControlCounter = 1; - - if (pDevice) - { - LogMessage("ZeDMD found: device=%s, width=%d, height=%d", pDevice, m_width, m_height); - } - else - { - LogMessage("ZeDMD found: width=%d, height=%d", m_width, m_height); - } - - return true; - } - } + m_serialPort.WriteBytes((uint8_t*)CTRL_CHARS_HEADER, CTRL_CHARS_HEADER_SIZE); + m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::Handshake); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); + + if (m_serialPort.ReadBytes(data, 8)) { + if (!memcmp(data, CTRL_CHARS_HEADER, 4)) { + m_width = data[4] + data[5] * 256; + m_height = data[6] + data[7] * 256; + m_zoneWidth = m_width / 16; + m_zoneHeight = m_height / 8; + + uint8_t response; + + if (m_serialPort.ReadByte() == 'R') { + m_serialPort.WriteBytes((uint8_t*)CTRL_CHARS_HEADER, 6); + m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::Compression); + std::this_thread::sleep_for(std::chrono::milliseconds(4)); + + if (m_serialPort.ReadByte() == 'A' && m_serialPort.ReadByte() == 'R') { + m_serialPort.WriteBytes((uint8_t*)CTRL_CHARS_HEADER, 6); + m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::Chunk); + m_serialPort.WriteChar(ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE / 256); + std::this_thread::sleep_for(std::chrono::milliseconds(4)); + + if (m_serialPort.ReadByte() == 'A' && m_serialPort.ReadByte() == 'R') { + m_serialPort.WriteBytes((uint8_t*)CTRL_CHARS_HEADER, 6); + m_serialPort.WriteChar(ZEDMD_COMM_COMMAND::EnableFlowControlV2); + std::this_thread::sleep_for(std::chrono::milliseconds(4)); + + if (m_serialPort.ReadByte() == 'A') { + m_flowControlCounter = 1; + + if (pDevice) { + LogMessage("ZeDMD found: device=%s, width=%d, height=%d", pDevice, m_width, m_height); + } else { + LogMessage("ZeDMD found: width=%d, height=%d", m_width, m_height); + } + + return true; + } + } + } } - } - } - } + } + } - Disconnect(); + Disconnect(); - return false; + return false; } -bool ZeDMDComm::IsConnected() -{ - return m_serialPort.IsOpen(); +bool +ZeDMDComm::IsConnected() { + return m_serialPort.IsOpen(); } -void ZeDMDComm::Reset() -{ - m_serialPort.ClearDTR(); - m_serialPort.SetRTS(); - std::this_thread::sleep_for(std::chrono::milliseconds(200)); +void +ZeDMDComm::Reset() { + m_serialPort.ClearDTR(); + m_serialPort.SetRTS(); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); - m_serialPort.ClearRTS(); - m_serialPort.ClearDTR(); - std::this_thread::sleep_for(std::chrono::milliseconds(200)); + m_serialPort.ClearRTS(); + m_serialPort.ClearDTR(); + std::this_thread::sleep_for(std::chrono::milliseconds(200)); } -bool ZeDMDComm::StreamBytes(ZeDMDFrame *pFrame) -{ - uint8_t *data; - int size; - - if (pFrame->size == 0) - { - size = CTRL_CHARS_HEADER_SIZE + 1; - data = (uint8_t *)malloc(size); - memcpy(data, CTRL_CHARS_HEADER, CTRL_CHARS_HEADER_SIZE); - data[CTRL_CHARS_HEADER_SIZE] = pFrame->command; - } - else - { - mz_ulong compressedSize = mz_compressBound(pFrame->size); - data = (uint8_t *)malloc(CTRL_CHARS_HEADER_SIZE + 3 + compressedSize); - memcpy(data, CTRL_CHARS_HEADER, CTRL_CHARS_HEADER_SIZE); - data[CTRL_CHARS_HEADER_SIZE] = pFrame->command; - mz_compress(data + CTRL_CHARS_HEADER_SIZE + 3, &compressedSize, pFrame->data, pFrame->size); - size = CTRL_CHARS_HEADER_SIZE + 3 + compressedSize; - data[CTRL_CHARS_HEADER_SIZE + 1] = (uint8_t)(compressedSize >> 8 & 0xFF); - data[CTRL_CHARS_HEADER_SIZE + 2] = (uint8_t)(compressedSize & 0xFF); - } - - bool success = false; - - uint8_t flowControlCounter; - do - { - // In case of a timeout, ReadByte() returns 0. - flowControlCounter = m_serialPort.ReadByte(); - } while (flowControlCounter != 0 && flowControlCounter != m_flowControlCounter); - - if (flowControlCounter == m_flowControlCounter) - { - int position = 0; - success = true; - - while (position < size && success) - { - m_serialPort.WriteBytes(data + position, ((size - position) < ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE) ? (size - position) : ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE); - - uint8_t response; - do - { - response = m_serialPort.ReadByte(); - } while (response == flowControlCounter); - - if (response == 'A') - position += ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE; - else - { - success = false; - LogMessage("Write bytes failure: response=%c", response); - } - } - - if (m_flowControlCounter < 32) - { - m_flowControlCounter++; - } - else - { - m_flowControlCounter = 1; - } - } - else - { - LogMessage("No Ready Signal"); - } - - free(data); - - return success; +bool +ZeDMDComm::StreamBytes(ZeDMDFrame* pFrame) { + uint8_t* data; + int size; + + if (pFrame->size == 0) { + size = CTRL_CHARS_HEADER_SIZE + 1; + data = (uint8_t*)malloc(size); + memcpy(data, CTRL_CHARS_HEADER, CTRL_CHARS_HEADER_SIZE); + data[CTRL_CHARS_HEADER_SIZE] = pFrame->command; + } else { + mz_ulong compressedSize = mz_compressBound(pFrame->size); + data = (uint8_t*)malloc(CTRL_CHARS_HEADER_SIZE + 3 + compressedSize); + memcpy(data, CTRL_CHARS_HEADER, CTRL_CHARS_HEADER_SIZE); + data[CTRL_CHARS_HEADER_SIZE] = pFrame->command; + mz_compress(data + CTRL_CHARS_HEADER_SIZE + 3, &compressedSize, pFrame->data, pFrame->size); + size = CTRL_CHARS_HEADER_SIZE + 3 + compressedSize; + data[CTRL_CHARS_HEADER_SIZE + 1] = (uint8_t)(compressedSize >> 8 & 0xFF); + data[CTRL_CHARS_HEADER_SIZE + 2] = (uint8_t)(compressedSize & 0xFF); + } + + bool success = false; + + uint8_t flowControlCounter; + do { + // In case of a timeout, ReadByte() returns 0. + flowControlCounter = m_serialPort.ReadByte(); + } while (flowControlCounter != 0 && flowControlCounter != m_flowControlCounter); + + if (flowControlCounter == m_flowControlCounter) { + int position = 0; + success = true; + + while (position < size && success) { + m_serialPort.WriteBytes(data + position, ((size - position) < ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE) + ? (size - position) + : ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE); + + uint8_t response; + do { + response = m_serialPort.ReadByte(); + } while (response == flowControlCounter); + + if (response == 'A') + position += ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE; + else { + success = false; + LogMessage("Write bytes failure: response=%c", response); + } + } + + if (m_flowControlCounter < 32) { + m_flowControlCounter++; + } else { + m_flowControlCounter = 1; + } + } else { + LogMessage("No Ready Signal"); + } + + free(data); + + return success; } -uint16_t ZeDMDComm::GetWidth() -{ - return m_width; +uint16_t +ZeDMDComm::GetWidth() { + return m_width; } -uint16_t ZeDMDComm::GetHeight() -{ - return m_height; +uint16_t +ZeDMDComm::GetHeight() { + return m_height; } \ No newline at end of file diff --git a/src/ZeDMDComm.h b/src/ZeDMDComm.h index 56a0c52..b9b0c5c 100644 --- a/src/ZeDMDComm.h +++ b/src/ZeDMDComm.h @@ -1,12 +1,12 @@ #pragma once -#include -#include -#include #include #include -#include +#include #include +#include +#include +#include // @todo better handling of external lib #include "../../libserialport/src/SerialPort.h" @@ -16,143 +16,140 @@ #define CALLBACK #endif -typedef enum -{ - FrameSize = 0x02, - Handshake = 0x0c, - Chunk = 0x0d, - Compression = 0x0e, - EnableCompression = 0x0e, - DisableCompression = 0x0f, - LEDTest = 0x10, - EnableUpscaling = 0x15, - DisableUpscaling = 0x14, - Brightness = 0x16, - RGBOrder = 0x17, - GetBrightness = 0x18, - GetRGBOrder = 0x19, - EnableFlowControlV2 = 0x1a, - SetWiFiSSID = 0x1b, - SetWiFiPassword = 0x1c, - SetWiFiPort = 0x1d, - SaveSettings = 0x1e, - Reset = 0x1f, - GetVersionBytes = 0x20, - GetResolution = 0x21, - - RGB24 = 0x03, - RGB24ZonesStream = 0x04, - Gray2 = 0x08, - ColGray4 = 0x09, - ColGray6 = 0x0b, - ClearScreen = 0x0a, - - DisableDebug = 0x62, - EnableDebug = 0x63, +typedef enum { + FrameSize = 0x02, + Handshake = 0x0c, + Chunk = 0x0d, + Compression = 0x0e, + EnableCompression = 0x0e, + DisableCompression = 0x0f, + LEDTest = 0x10, + EnableUpscaling = 0x15, + DisableUpscaling = 0x14, + Brightness = 0x16, + RGBOrder = 0x17, + GetBrightness = 0x18, + GetRGBOrder = 0x19, + EnableFlowControlV2 = 0x1a, + SetWiFiSSID = 0x1b, + SetWiFiPassword = 0x1c, + SetWiFiPort = 0x1d, + SaveSettings = 0x1e, + Reset = 0x1f, + GetVersionBytes = 0x20, + GetResolution = 0x21, + + RGB24 = 0x03, + RGB24ZonesStream = 0x04, + Gray2 = 0x08, + ColGray4 = 0x09, + ColGray6 = 0x0b, + ClearScreen = 0x0a, + + DisableDebug = 0x62, + EnableDebug = 0x63, } ZEDMD_COMM_COMMAND; -struct ZeDMDFrame -{ - uint8_t command; - uint8_t *data; - int size; - int8_t streamId; +struct ZeDMDFrame { + uint8_t command; + uint8_t* data; + int size; + int8_t streamId; }; #define ZEDMD_COMM_BAUD_RATE 921600 #if defined(_WIN32) || defined(_WIN64) #define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 8192 -#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 16 -#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 +#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 16 +#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 #elif defined(__APPLE__) #define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 256 -#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 64 -#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 +#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 64 +#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 #elif defined(__ANDROID__) #define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 2048 -#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 16 -#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 +#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 16 +#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 #else // defined (__linux__) #define ZEDMD_COMM_MAX_SERIAL_WRITE_AT_ONCE 256 -#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 64 -#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 +#define ZEDMD_COMM_SERIAL_READ_TIMEOUT 64 +#define ZEDMD_COMM_SERIAL_WRITE_TIMEOUT 16 #endif -#define ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT 10 -#define ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX 8 +#define ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT 10 +#define ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX 8 #define ZEDMD_COMM_FRAME_QUEUE_SIZE_MAX_DELAYED 2 #ifdef __ANDROID__ -typedef void *(*ZeDMD_AndroidGetJNIEnvFunc)(); +typedef void* (*ZeDMD_AndroidGetJNIEnvFunc)(); #endif -typedef void(CALLBACK *ZeDMD_LogMessageCallback)(const char *format, va_list args, const void *userData); +typedef void(CALLBACK* ZeDMD_LogMessageCallback)(const char* format, va_list args, const void* userData); -class ZeDMDComm -{ -public: - static const int CTRL_CHARS_HEADER_SIZE = 6; - static constexpr uint8_t CTRL_CHARS_HEADER[] = {0x5a, 0x65, 0x64, 0x72, 0x75, 0x6d}; +class ZeDMDComm { + public: + static const int CTRL_CHARS_HEADER_SIZE = 6; + static constexpr uint8_t CTRL_CHARS_HEADER[] = {0x5a, 0x65, 0x64, 0x72, 0x75, 0x6d}; -public: - ZeDMDComm(); - ~ZeDMDComm(); + public: + ZeDMDComm(); + ~ZeDMDComm(); #ifdef __ANDROID__ - void SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func); + void SetAndroidGetJNIEnvFunc(ZeDMD_AndroidGetJNIEnvFunc func); #endif - void SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void *userData); - - void IgnoreDevice(const char *ignore_device); - void SetDevice(const char *device); - - virtual bool Connect(); - virtual void Disconnect(); - virtual bool IsConnected(); - - void Run(); - void QueueCommand(char command, uint8_t *buffer, int size, uint16_t width, uint16_t height); - void QueueCommand(char command, uint8_t *buffer, int size, int8_t streamId = -1, bool delayed = false); - void QueueCommand(char command); - void QueueCommand(char command, uint8_t value); - bool FillDelayed(); - - uint16_t GetWidth(); - uint16_t GetHeight(); - -protected: - virtual bool StreamBytes(ZeDMDFrame *pFrame); - virtual void Reset(); - - uint16_t m_zonesBytesLimit = 0; - uint8_t m_zoneWidth = 8; - uint8_t m_zoneHeight = 4; - -private: - void LogMessage(const char *format, ...); - - bool Connect(char *pName); - - ZeDMD_LogMessageCallback m_logMessageCallback = nullptr; - const void *m_logMessageUserData = nullptr; - uint64_t m_zoneHashes[128] = {0}; - uint16_t m_width = 128; - uint16_t m_height = 32; - int8_t m_streamId = -1; - int8_t m_lastStreamId = -1; - uint8_t m_flowControlCounter = 0; - char m_ignoredDevices[10][32] = {0}; - uint8_t m_ignoredDevicesCounter = 0; - char m_device[32] = {0}; - SerialPort m_serialPort; - std::queue m_frames; - std::thread *m_pThread; - std::mutex m_frameQueueMutex; - uint8_t m_frameCounter = 0; - std::queue m_delayedFrames; - std::mutex m_delayedFrameMutex; - bool m_delayedFrameReady = false; + void SetLogMessageCallback(ZeDMD_LogMessageCallback callback, const void* userData); + + void IgnoreDevice(const char* ignore_device); + void SetDevice(const char* device); + + virtual bool Connect(); + virtual void Disconnect(); + virtual bool IsConnected(); + + void Run(); + void QueueCommand(char command, uint8_t* buffer, int size, uint16_t width, uint16_t height); + void QueueCommand(char command, uint8_t* buffer, int size, int8_t streamId = -1, bool delayed = false); + void QueueCommand(char command); + void QueueCommand(char command, uint8_t value); + bool FillDelayed(); + + uint16_t GetWidth(); + uint16_t GetHeight(); + + protected: + virtual bool StreamBytes(ZeDMDFrame* pFrame); + virtual void Reset(); + + uint16_t m_zonesBytesLimit = 0; + uint8_t m_zoneWidth = 8; + uint8_t m_zoneHeight = 4; + + private: + void LogMessage(const char* format, ...); + + bool Connect(char* pName); + + ZeDMD_LogMessageCallback m_logMessageCallback = nullptr; + const void* m_logMessageUserData = nullptr; + uint64_t m_zoneHashes[128] = {0}; + uint16_t m_width = 128; + uint16_t m_height = 32; + int8_t m_streamId = -1; + int8_t m_lastStreamId = -1; + uint8_t m_flowControlCounter = 0; + char m_ignoredDevices[10][32] = {0}; + uint8_t m_ignoredDevicesCounter = 0; + char m_device[32] = {0}; + SerialPort m_serialPort; + std::queue m_frames; + std::thread* m_pThread; + std::mutex m_frameQueueMutex; + uint8_t m_frameCounter = 0; + std::queue m_delayedFrames; + std::mutex m_delayedFrameMutex; + bool m_delayedFrameReady = false; }; \ No newline at end of file diff --git a/src/ZeDMDWiFi.cpp b/src/ZeDMDWiFi.cpp index 59b9b7c..c0f5e2b 100644 --- a/src/ZeDMDWiFi.cpp +++ b/src/ZeDMDWiFi.cpp @@ -1,100 +1,93 @@ #include "ZeDMDWiFi.h" -#include "miniz/miniz.h" #include "komihash/komihash.h" +#include "miniz/miniz.h" -bool ZeDMDWiFi::Connect(const char *ip, int port) -{ +bool +ZeDMDWiFi::Connect(const char* ip, int port) { #if defined(_WIN32) || defined(_WIN64) - WSADATA wsaData; - if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) - { - return false; - } + WSADATA wsaData; + if (WSAStartup(MAKEWORD(2, 2), &wsaData) != NO_ERROR) { + return false; + } #endif - if ((m_wifiSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) - { - return false; - } + if ((m_wifiSocket = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { + return false; + } - m_wifiServer.sin_family = AF_INET; - m_wifiServer.sin_port = htons(port); - m_wifiServer.sin_addr.s_addr = inet_addr(ip); - m_connected = true; + m_wifiServer.sin_family = AF_INET; + m_wifiServer.sin_port = htons(port); + m_wifiServer.sin_addr.s_addr = inet_addr(ip); + m_connected = true; - return true; + return true; } -void ZeDMDWiFi::Disconnect() -{ - Reset(); +void +ZeDMDWiFi::Disconnect() { + Reset(); #if defined(_WIN32) || defined(_WIN64) - WSACleanup(); + WSACleanup(); #endif } -bool ZeDMDWiFi::IsConnected() -{ - return m_connected; +bool +ZeDMDWiFi::IsConnected() { + return m_connected; } -void ZeDMDWiFi::Reset() -{ -} +void +ZeDMDWiFi::Reset() {} -bool ZeDMDWiFi::StreamBytes(ZeDMDFrame *pFrame) -{ - // An UDP package should not exceed the MTU (WiFi rx_buffer in ESP32 is 1460 bytes). - // We send 4 zones of 16 * 8 pixels: - // 512 pixels, 3 bytes RGB per pixel, 4 bytes for zones index, 4 bytes command header: 1544 bytes - // As we additionally use compression, that should be safe. +bool +ZeDMDWiFi::StreamBytes(ZeDMDFrame* pFrame) { + // An UDP package should not exceed the MTU (WiFi rx_buffer in ESP32 is 1460 bytes). + // We send 4 zones of 16 * 8 pixels: + // 512 pixels, 3 bytes RGB per pixel, 4 bytes for zones index, 4 bytes command header: 1544 bytes + // As we additionally use compression, that should be safe. - if (pFrame->size < ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT) - { - uint8_t data[ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT + 4] = {0}; - data[0] = pFrame->command; // command - data[1] = 0; // not compressed - data[2] = (uint8_t)(pFrame->size >> 8 & 0xFF); - data[3] = (uint8_t)(pFrame->size & 0xFF); - if (pFrame->size > 0) - { - memcpy(&data[4], pFrame->data, pFrame->size); - } + if (pFrame->size < ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT) { + uint8_t data[ZEDMD_COMM_FRAME_SIZE_COMMAND_LIMIT + 4] = {0}; + data[0] = pFrame->command; // command + data[1] = 0; // not compressed + data[2] = (uint8_t)(pFrame->size >> 8 & 0xFF); + data[3] = (uint8_t)(pFrame->size & 0xFF); + if (pFrame->size > 0) { + memcpy(&data[4], pFrame->data, pFrame->size); + } - // Send command three times in case an UDP packet gets lost. - for (int i = 0; i < 3; i++) - { + // Send command three times in case an UDP packet gets lost. + for (int i = 0; i < 3; i++) { #if defined(_WIN32) || defined(_WIN64) - sendto(m_wifiSocket, (const char *)data, pFrame->size + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); + sendto(m_wifiSocket, (const char*)data, pFrame->size + 4, 0, (struct sockaddr*)&m_wifiServer, + sizeof(m_wifiServer)); #else - sendto(m_wifiSocket, data, pFrame->size + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); + sendto(m_wifiSocket, data, pFrame->size + 4, 0, (struct sockaddr*)&m_wifiServer, sizeof(m_wifiServer)); #endif - std::this_thread::sleep_for(std::chrono::milliseconds(10)); - } - return true; - } - else - { - uint8_t data[ZEDMD_WIFI_ZONES_BYTES_LIMIT] = {0}; - data[0] = pFrame->command; // command - data[1] = (uint8_t)(128 | (pFrame->size / (m_zoneWidth * m_zoneHeight * 3 + 1))); // compressed + zone index + std::this_thread::sleep_for(std::chrono::milliseconds(10)); + } + return true; + } else { + uint8_t data[ZEDMD_WIFI_ZONES_BYTES_LIMIT] = {0}; + data[0] = pFrame->command; // command + data[1] = (uint8_t)(128 | (pFrame->size / (m_zoneWidth * m_zoneHeight * 3 + 1))); // compressed + zone index - mz_ulong compressedSize = mz_compressBound(pFrame->size); - int status = mz_compress(&data[4], &compressedSize, pFrame->data, pFrame->size); - data[2] = (uint8_t)(compressedSize >> 8 & 0xFF); - data[3] = (uint8_t)(compressedSize & 0xFF); + mz_ulong compressedSize = mz_compressBound(pFrame->size); + int status = mz_compress(&data[4], &compressedSize, pFrame->data, pFrame->size); + data[2] = (uint8_t)(compressedSize >> 8 & 0xFF); + data[3] = (uint8_t)(compressedSize & 0xFF); - if (status == MZ_OK) - { + if (status == MZ_OK) { #if defined(_WIN32) || defined(_WIN64) - sendto(m_wifiSocket, (const char *)data, compressedSize + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); + sendto(m_wifiSocket, (const char*)data, compressedSize + 4, 0, (struct sockaddr*)&m_wifiServer, + sizeof(m_wifiServer)); #else - sendto(m_wifiSocket, data, compressedSize + 4, 0, (struct sockaddr *)&m_wifiServer, sizeof(m_wifiServer)); + sendto(m_wifiSocket, data, compressedSize + 4, 0, (struct sockaddr*)&m_wifiServer, sizeof(m_wifiServer)); #endif - return true; - } - } + return true; + } + } - return false; + return false; } diff --git a/src/ZeDMDWiFi.h b/src/ZeDMDWiFi.h index c8068fd..e7557f8 100644 --- a/src/ZeDMDWiFi.h +++ b/src/ZeDMDWiFi.h @@ -4,33 +4,29 @@ #include #define CALLBACK __stdcall #else -#include #include #include +#include #define CALLBACK #endif #include "ZeDMDComm.h" #define ZEDMD_WIFI_ZONES_BYTES_LIMIT 1800 -class ZeDMDWiFi : public ZeDMDComm -{ -public: - ZeDMDWiFi() : ZeDMDComm() - { - m_zonesBytesLimit = ZEDMD_WIFI_ZONES_BYTES_LIMIT; - } +class ZeDMDWiFi : public ZeDMDComm { + public: + ZeDMDWiFi() : ZeDMDComm() { m_zonesBytesLimit = ZEDMD_WIFI_ZONES_BYTES_LIMIT; } - virtual bool Connect(const char *ip, int port); - virtual void Disconnect(); - virtual bool IsConnected(); + virtual bool Connect(const char* ip, int port); + virtual void Disconnect(); + virtual bool IsConnected(); -protected: - virtual bool StreamBytes(ZeDMDFrame *pFrame); - virtual void Reset(); + protected: + virtual bool StreamBytes(ZeDMDFrame* pFrame); + virtual void Reset(); -private: - int m_wifiSocket; - struct sockaddr_in m_wifiServer; - bool m_connected = false; + private: + int m_wifiSocket; + struct sockaddr_in m_wifiServer; + bool m_connected = false; }; \ No newline at end of file