Thank you both for replying - I'm glad of any help on this...
The lists adding and removing are all (producer and consumer) behind mutex and so should be ok...I can't actually check that yet as the semaphore refuses to signal the thread to use the messages on the queue. I can add more messages from the producer onto the queue and that seems fine.
All producers use this pattern (here's the status producer)
Code: Select all
Procedure AddStatusUpdate(StatusText.s, StatusType.l)
LockMutex(StatusQueueMutex)
AddElement(StatusQueue())
StatusQueue()\StatusText = StatusText
StatusQueue()\Timestamp = Date()
StatusQueue()\StatusType = StatusType
UnlockMutex(StatusQueueMutex)
SignalSemaphore(StatusAvailableSemaphore)
EndProcedure
2nd example (using the semaphore in question) - ALL Semaphores and Mutexs are GlOBAL variables
Code: Select all
Procedure SendJSONCommand(Command.s)
; Basic JSON validation
If CountString(Command, "{") <> CountString(Command, "}")
MessageRequester("Error", "Invalid JSON: Mismatched braces")
ProcedureReturn
EndIf
LockMutex(CommandQueueMutex)
; Add to command queue using PureBasic list commands
AddElement(CommandQueue())
CommandQueue()\CommandText = Command
CommandQueue()\Timestamp = Date()
CommandQueue()\CommandID = Random(999999)
; here we should be loading the exact type of command on the queue and signal the sender to send!
UnlockMutex(CommandQueueMutex)
; Signal serial handler thread
SignalSemaphore(CommandAvailableSemaphore) ; This SHOULD start a transmist in the SerialHanlerThread (ln 365) ????
; Update UI command list
LockMutex(UIUpdateMutex)
; Extract command name for abbreviated display
Protected CommandName.s = "unknown"
Protected Pos = FindString(Command, Chr(34) + "command" + Chr(34) + ":")
If Pos > 0
Pos = FindString(Command, Chr(34), Pos + 10)
If Pos > 0
Protected EndPos = FindString(Command, Chr(34), Pos + 1)
If EndPos > 0
CommandName = Mid(Command, Pos + 1, EndPos - Pos - 1)
EndIf
EndIf
EndIf
AddGadgetItem(#CommandListGadget, -1, FormatDate("%hh:%ii:%ss", Date()) + " - " + CommandName)
; Keep list size manageable
If CountGadgetItems(#CommandListGadget) > #MAX_COMMAND_HISTORY
RemoveGadgetItem(#CommandListGadget, 0)
EndIf
; Auto-scroll to bottom
SetGadgetState(#CommandListGadget, CountGadgetItems(#CommandListGadget) - 1)
UnlockMutex(UIUpdateMutex)
EndProcedure
And the consumers are the same and look like this pattern (some minor differences but the semaphore use is the same)
Code: Select all
; Message processor thread
Procedure ProcessorThread(*Dummy)
Protected Reply.ReplyItem
Protected DisplayText.s
Protected HasReply.l = #False
While Not ExitFlag
; Check for replies to process - non-blocking approach
HasReply = #False
; Check if there are replies available without blocking
If TrySemaphore(ReplyAvailableSemaphore) > 0
; Consume the semaphore signal
; SignalSemaphore(ReplyAvailableSemaphore)
HasReply = #True
; Get reply from queue
LockMutex(ReplyQueueMutex)
If ListSize(ReplyQueue()) > 0
FirstElement(ReplyQueue())
Reply\ReplyText = ReplyQueue()\ReplyText
Reply\Timestamp = ReplyQueue()\Timestamp
Reply\MessageType = ReplyQueue()\MessageType
Reply\RawData = ReplyQueue()\RawData
DeleteElement(ReplyQueue())
Else
; No replies in queue despite semaphore signal
HasReply = #False
EndIf
UnlockMutex(ReplyQueueMutex)
; Process the reply
If HasReply And Reply\ReplyText <> ""
LockMutex(UIUpdateMutex)
; Format display text based on message type
Select Reply\MessageType
Case #MSG_IMAGE
DisplayText = FormatDate("%hh:%ii:%ss", Reply\Timestamp) + " - [IMAGE] " + Left(Reply\ReplyText, 50) + "..."
; Decode and display image
Protected ImagePos = FindString(Reply\ReplyText, "image_data")
If ImagePos > 0
; Extract base64 data (simplified)
Protected Base64Start = FindString(Reply\ReplyText, Chr(34), ImagePos + 10)
If Base64Start > 0
Protected Base64End = FindString(Reply\ReplyText, Chr(34), Base64Start + 1)
If Base64End > 0
Protected Base64Data.s = Mid(Reply\ReplyText, Base64Start + 1, Base64End - Base64Start - 1)
DecodeBase64Image(Base64Data)
EndIf
EndIf
EndIf
Case #MSG_SENSOR_DATA
DisplayText = FormatDate("%hh:%ii:%ss", Reply\Timestamp) + " - [SENSOR] " + Reply\ReplyText
Default
DisplayText = FormatDate("%hh:%ii:%ss", Reply\Timestamp) + " - " + Reply\ReplyText
EndSelect
; Add to reply list
AddGadgetItem(#ReplyListGadget, -1, DisplayText)
; Keep list size manageable
If CountGadgetItems(#ReplyListGadget) > #MAX_REPLY_HISTORY
RemoveGadgetItem(#ReplyListGadget, 0)
EndIf
; Auto-scroll to bottom
SetGadgetState(#ReplyListGadget, CountGadgetItems(#ReplyListGadget) - 1)
UnlockMutex(UIUpdateMutex)
; Clear reply for next iteration
Reply\ReplyText = ""
EndIf
EndIf
; Small delay to prevent CPU hogging
Delay(1)
Wend
ProcedureReturn 0
EndProcedure
Apologies for the code being untidy - still working on logic a little...but first I need basic functionality to work. So why does
the try semaphore never see anything but zero.
Perhaps I can find this with a little help...
1) how can I look at the semaphores actual value
2) if in debug I see it IS non-zero then why on earth would the code "TrySemaphore()" step refuse to trigger the IF clause
OR
3) It never sets
Or
4) they are testing different addresses for the Semaphore (???) - that's why I tried SHARE
thanks Guys - any ideas??