4
4
5
5
#include "IPCQueue.h"
6
6
7
+ typedef struct
8
+ {
9
+ uint32_t mDWord0 ;
10
+ uint32_t mDWord1 ;
11
+ uint32_t mStatus ;
12
+ void * mBuffer ;
13
+ } IPCMessageReply ;
14
+
7
15
/*
8
16
* IPCMessage
9
17
*/
10
18
11
19
int
12
20
IPCMessageInit (IPCMessage * aMsg )
13
21
{
22
+ aMsg -> mMonitor = xQueueCreate (1 , sizeof (IPCMessageReply ));
23
+ if (!aMsg -> mMonitor ) {
24
+ return -1 ;
25
+ }
26
+
14
27
aMsg -> mDWord0 = 0 ;
15
28
aMsg -> mDWord1 = 0 ;
16
- aMsg -> mStatus = 0 ;
29
+ aMsg -> mStatus = IPC_MESSAGE_STATE_CLEAR ;
17
30
aMsg -> mBuffer = NULL ;
18
31
19
32
return 0 ;
20
33
}
21
34
35
+ void
36
+ IPCMessageUninit (IPCMessage * aMsg )
37
+ {
38
+ vQueueDelete (aMsg -> mMonitor );
39
+ }
40
+
22
41
uint32_t
23
42
IPCMessageGetBufferLength (const IPCMessage * aMsg )
24
43
{
25
44
return aMsg -> mStatus & 0x00ffffff ;
26
45
}
27
46
28
47
int
29
- IPCMessageProduce (IPCMessage * aMsg )
48
+ IPCMessageProduce (IPCMessage * aMsg , uint32_t aLength , void * aBuffer )
49
+ {
50
+ switch (aMsg -> mStatus & 0xf0000000 ) {
51
+ case IPC_MESSAGE_STATE_CLEAR : /* fall through */
52
+ case IPC_MESSAGE_STATE_PRODUCED : /* fall through */
53
+ case IPC_MESSAGE_STATE_ERROR :
54
+ /* We're good if the message is currently not in transit. */
55
+ break ;
56
+ case IPC_MESSAGE_STATE_PENDING : /* fall through */
57
+ default :
58
+ /* If the message is currently in transit or the status is
59
+ * unknown, we don't produce a new one. Better abort here. */
60
+ return -1 ;
61
+ }
62
+
63
+ aMsg -> mDWord0 = 0 ;
64
+ aMsg -> mDWord1 = 0 ;
65
+ aMsg -> mStatus = 0 ;
66
+ aMsg -> mStatus |= IPC_MESSAGE_STATE_PRODUCED ;
67
+ aMsg -> mStatus |= aLength ;
68
+ aMsg -> mBuffer = aBuffer ;
69
+
70
+ return 0 ;
71
+ }
72
+
73
+ static int
74
+ WaitForConsumption (IPCMessage * aMsg , IPCMessageReply * aReply )
75
+ {
76
+ uint32_t state = aMsg -> mStatus & 0xf0000000 ;
77
+ if (state != IPC_MESSAGE_STATE_PENDING ) {
78
+ return -1 ;
79
+ }
80
+ BaseType_t ret = xQueueReceive (aMsg -> mMonitor , aReply , portMAX_DELAY );
81
+ if (ret != pdPASS ) {
82
+ return -1 ;
83
+ };
84
+ return 0 ;
85
+ }
86
+
87
+ int
88
+ IPCMessageWaitForReply (IPCMessage * aMsg )
30
89
{
31
- /* TODO: At some point we have to implement efficient IPC with
32
- * large buffers. IPCMessageProduce() will signal the end of the
33
- * message constrcution **on the producer tast.** A produced
34
- * message can be send over over an IPC queue to a consumer task.
35
- * The consumer calls IPCMessageConsume() after it processed the
36
- * buffer. The producer can then release the buffer. */
90
+ IPCMessageReply reply ;
91
+ int res = WaitForConsumption (aMsg , & reply );
92
+ if (res < 0 ) {
93
+ return -1 ;
94
+ };
95
+ aMsg -> mDWord0 = reply .mDWord0 ;
96
+ aMsg -> mDWord1 = reply .mDWord1 ;
97
+ aMsg -> mStatus = reply .mStatus ;
98
+ aMsg -> mBuffer = reply .mBuffer ;
37
99
return 0 ;
38
100
}
39
101
40
102
int
41
- IPCMessageConsume (IPCMessage * aMsg )
103
+ IPCMessageWaitForConsumption (IPCMessage * aMsg )
42
104
{
43
- /* TODO: See IPCMessageProduce() */
105
+ IPCMessageReply reply ;
106
+ int res = WaitForConsumption (aMsg , & reply );
107
+ if (res < 0 ) {
108
+ return -1 ;
109
+ };
110
+ aMsg -> mStatus &= 0x0fffffff ; /* clear pending status */
111
+ return 0 ;
112
+ }
113
+
114
+ static int
115
+ ConsumeAndReply (IPCMessage * aMsg , const IPCMessageReply * aReply )
116
+ {
117
+ BaseType_t res = xQueueSend (aMsg -> mMonitor , & aReply , 0 );
118
+ if (res != pdPASS ) {
119
+ return -1 ;
120
+ }
44
121
return 0 ;
45
122
}
46
123
124
+ int
125
+ IPCMessageConsumeAndReply (IPCMessage * aMsg ,
126
+ uint32_t aDWord0 , uint32_t aDWord1 ,
127
+ uint32_t aFlags , uint32_t aLength ,
128
+ void * aBuffer )
129
+ {
130
+ IPCMessageReply reply = {
131
+ .mDWord0 = aDWord0 ,
132
+ .mDWord1 = aDWord1 ,
133
+ .mStatus = aFlags | aLength ,
134
+ .mBuffer = aBuffer
135
+ };
136
+ return ConsumeAndReply (aMsg , & reply );
137
+ }
138
+
139
+ int
140
+ IPCMessageConsume (IPCMessage * aMsg )
141
+ {
142
+ static const IPCMessageReply sReply = {
143
+ .mDWord0 = 0 ,
144
+ .mDWord1 = 0 ,
145
+ .mStatus = IPC_MESSAGE_STATE_CLEAR ,
146
+ .mBuffer = NULL ,
147
+ };
148
+ return ConsumeAndReply (aMsg , & sReply );
149
+ }
150
+
47
151
/*
48
152
* IPCMessageQueue
49
153
*/
@@ -58,14 +162,42 @@ IPCMessageQueueInit(IPCMessageQueue* aMsgQueue)
58
162
return 0 ;
59
163
}
60
164
165
+ void
166
+ IPCMessageQueueUninit (IPCMessageQueue * aMsgQueue )
167
+ {
168
+ vQueueDelete (aMsgQueue -> mWaitQueue );
169
+ }
170
+
61
171
int
62
172
IPCMessageQueueConsume (IPCMessageQueue * aMsgQueue , IPCMessage * aMsg )
63
173
{
64
- BaseType_t res = xQueueSend (aMsgQueue -> mWaitQueue , aMsg , 0 );
65
- if (res != pdPASS ){
66
- return -1 ;
67
- }
68
- return 0 ;
174
+ uint32_t status = aMsg -> mStatus ;
175
+
176
+ switch (status & 0xf0000000 ) {
177
+ case IPC_MESSAGE_STATE_PRODUCED : /* fall through */
178
+ /* We're good if the message has been produced correctly. */
179
+ break ;
180
+ case IPC_MESSAGE_STATE_CLEAR : /* fall through */
181
+ case IPC_MESSAGE_STATE_PENDING : /* fall through */
182
+ case IPC_MESSAGE_STATE_ERROR : /* fall through */
183
+ default :
184
+ /* In any other case, the message is probably not ready for
185
+ * consumption. Better abort here. */
186
+ return -1 ;
187
+ }
188
+
189
+ aMsg -> mStatus &= 0x0fffffff ;
190
+ aMsg -> mStatus |= IPC_MESSAGE_STATE_PENDING ;
191
+
192
+ BaseType_t res = xQueueSend (aMsgQueue -> mWaitQueue , aMsg , 0 );
193
+ if (res != pdPASS ){
194
+ goto err_xQueueSend ;
195
+ }
196
+ return 0 ;
197
+
198
+ err_xQueueSend :
199
+ aMsg -> mStatus = status ;
200
+ return -1 ;
69
201
}
70
202
71
203
int
0 commit comments