@@ -38,11 +38,12 @@ static const char *const filtered_out_sources[] = {
3838 "NRF_RPC" ,
3939};
4040
41+ static const uint32_t common_output_flags =
42+ LOG_OUTPUT_FLAG_TIMESTAMP | LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP ;
43+
4144static bool panic_mode ;
4245static uint32_t log_format = LOG_OUTPUT_TEXT ;
43- static enum log_rpc_level current_level ;
4446static enum log_rpc_level stream_level = LOG_RPC_LEVEL_NONE ;
45- static uint8_t log_output_buffer [CONFIG_LOG_BACKEND_RPC_BUFFER_SIZE ];
4647
4748/*
4849 * Verify that Zephyr logging level can be used as the nRF RPC logging level without translation.
@@ -89,29 +90,33 @@ static void crash_log_clear(void)
8990 crash_log_max_size = (size_t )rc - sizeof (crash_log_header_t );
9091}
9192
92- static void retain ( const uint8_t * data , size_t length )
93+ static int output_to_retention ( uint8_t * data , size_t length , void * output_ctx )
9394{
9495 const struct device * const crash_log = CRASH_LOG_DEV ;
96+
9597 crash_log_header_t header ;
96- int rc ;
98+ size_t saved_length ;
99+
100+ ARG_UNUSED (output_ctx );
97101
98102 if (crash_log_cur_size >= crash_log_max_size ) {
99103 /* Crash log partition overflow. */
100- return ;
104+ goto out ;
101105 }
102106
103- length = MIN (length , crash_log_max_size - crash_log_cur_size );
107+ saved_length = MIN (length , crash_log_max_size - crash_log_cur_size );
104108
105- rc = retention_write (crash_log , sizeof (header ) + crash_log_cur_size , data , length );
106-
107- if (rc ) {
108- return ;
109+ if (retention_write (crash_log , sizeof (header ) + crash_log_cur_size , data , saved_length )) {
110+ goto out ;
109111 }
110112
111- crash_log_cur_size += length ;
113+ crash_log_cur_size += saved_length ;
112114 header .size = crash_log_cur_size ;
113115
114116 (void )retention_write (crash_log , 0 , (const uint8_t * )& header , sizeof (header ));
117+
118+ out :
119+ return (int )length ;
115120}
116121
117122static void log_rpc_get_crash_log_handler (const struct nrf_rpc_group * group ,
@@ -180,42 +185,105 @@ static void crash_log_clear(void)
180185{
181186}
182187
183- static void retain ( const uint8_t * data , size_t length )
188+ static int output_to_retention ( uint8_t * data , size_t length , void * output_ctx )
184189{
185190 ARG_UNUSED (data );
186191 ARG_UNUSED (length );
192+ ARG_UNUSED (output_ctx );
193+
194+ return (int )length ;
187195}
188196#endif /* CONFIG_LOG_BACKEND_RPC_CRASH_LOG */
189197
190- static void send (const uint8_t * data , size_t length )
198+ static void format_message (struct log_msg * msg , uint32_t flags , log_output_func_t output_func ,
199+ void * output_ctx )
191200{
192- struct nrf_rpc_cbor_ctx ctx ;
193-
194- NRF_RPC_CBOR_ALLOC (& log_rpc_group , ctx , 4 + length );
195- nrf_rpc_encode_uint (& ctx , current_level );
196- nrf_rpc_encode_buffer (& ctx , data , length );
197- nrf_rpc_cbor_evt_no_err (& log_rpc_group , LOG_RPC_EVT_MSG , & ctx );
201+ uint8_t output_buffer [CONFIG_LOG_BACKEND_RPC_OUTPUT_BUFFER_SIZE ];
202+ struct log_output_control_block control_block = {.ctx = output_ctx };
203+ struct log_output output = {
204+ .func = output_func ,
205+ .control_block = & control_block ,
206+ .buf = output_buffer ,
207+ .size = sizeof (output_buffer ),
208+ };
209+ log_format_func_t log_formatter ;
210+
211+ log_formatter = log_format_func_t_get (log_format );
212+ log_formatter (& output , msg , flags );
198213}
199214
200- static int flush (uint8_t * data , size_t length , void * context )
201- {
202- ARG_UNUSED (context );
215+ struct output_to_buf_ctx {
216+ uint8_t * out ;
217+ size_t out_len ;
218+ size_t total_len ;
219+ };
203220
204- if (panic_mode ) {
205- retain (data , length );
206- } else {
207- send (data , length );
221+ static int output_to_buf (uint8_t * data , size_t length , void * ctx )
222+ {
223+ struct output_to_buf_ctx * output_ctx = ctx ;
224+ size_t saved_length ;
225+
226+ if (output_ctx -> out != NULL ) {
227+ saved_length = MIN (length , output_ctx -> out_len );
228+ memcpy (output_ctx -> out , data , saved_length );
229+ output_ctx -> out += saved_length ;
230+ output_ctx -> out_len -= saved_length ;
208231 }
209232
210- /*
211- * Log output does not handle error codes gracefully, so pretend the buffer has been
212- * flushed to move on and not enter an infinite loop.
213- */
233+ output_ctx -> total_len += length ;
214234
215235 return (int )length ;
216236}
217237
218- LOG_OUTPUT_DEFINE (log_output_rpc , flush , log_output_buffer , sizeof (log_output_buffer ));
238+ static size_t format_message_to_buf (struct log_msg * msg , uint32_t flags , uint8_t * out ,
239+ size_t out_len )
240+ {
241+ struct output_to_buf_ctx output_ctx = {
242+ .out = out ,
243+ .out_len = out_len ,
244+ .total_len = 0 ,
245+ };
246+
247+ format_message (msg , flags , output_to_buf , & output_ctx );
248+
249+ return output_ctx .total_len ;
250+ }
251+
252+ static void retain_message (struct log_msg * msg )
253+ {
254+ const uint32_t flags = common_output_flags | LOG_OUTPUT_FLAG_CRLF_LFONLY ;
255+
256+ if (!IS_ENABLED (CONFIG_LOG_BACKEND_RPC_CRASH_LOG )) {
257+ return ;
258+ }
259+
260+ format_message (msg , flags , output_to_retention , NULL );
261+ }
262+
263+ static void stream_message (struct log_msg * msg )
264+ {
265+ const uint32_t flags = common_output_flags | LOG_OUTPUT_FLAG_CRLF_NONE ;
266+
267+ struct nrf_rpc_cbor_ctx ctx ;
268+ size_t length ;
269+ size_t max_length ;
270+
271+ /* 1. Calculate the formatted message length to allocate a sufficient CBOR encode buffer */
272+ length = format_message_to_buf (msg , flags , NULL , 0 );
273+
274+ NRF_RPC_CBOR_ALLOC (& log_rpc_group , ctx , 6 + length );
275+ nrf_rpc_encode_uint (& ctx , log_msg_get_level (msg ));
276+
277+ /* 2. Format the message directly into the CBOR encode buffer. */
278+ if (zcbor_bstr_start_encode (ctx .zs )) {
279+ max_length = ctx .zs [0 ].payload_end - ctx .zs [0 ].payload_mut ;
280+ length = format_message_to_buf (msg , flags , ctx .zs [0 ].payload_mut , max_length );
281+ ctx .zs [0 ].payload_mut += MIN (length , max_length );
282+ zcbor_bstr_end_encode (ctx .zs , NULL );
283+ }
284+
285+ nrf_rpc_cbor_evt_no_err (& log_rpc_group , LOG_RPC_EVT_MSG , & ctx );
286+ }
219287
220288static const char * log_msg_source_name_get (struct log_msg * msg )
221289{
@@ -243,26 +311,12 @@ static bool starts_with(const char *str, const char *prefix)
243311 return strncmp (str , prefix , strlen (prefix )) == 0 ;
244312}
245313
246- static void process (const struct log_backend * const backend , union log_msg_generic * msg )
314+ static void process (const struct log_backend * const backend , union log_msg_generic * msg_generic )
247315{
248- const log_format_func_t log_formatter = log_format_func_t_get (log_format );
249- const char * source_name = log_msg_source_name_get (& msg -> log );
250- uint32_t flags = LOG_OUTPUT_FLAG_TIMESTAMP | LOG_OUTPUT_FLAG_FORMAT_TIMESTAMP ;
251- enum log_rpc_level level = (enum log_rpc_level )log_msg_get_level (& msg -> log );
252- enum log_rpc_level max_level = stream_level ;
253-
254- /*
255- * Panic mode: logs are appended to the buffer in retained RAM, so include LF characters.
256- * Otherwise: if nRF RPC group is ready, logs are sent in separate messages, so skip LFs.
257- */
258- if (panic_mode ) {
259- flags |= LOG_OUTPUT_FLAG_CRLF_LFONLY ;
260- max_level = LOG_RPC_LEVEL_DBG ;
261- } else if (NRF_RPC_GROUP_STATUS (log_rpc_group )) {
262- flags |= LOG_OUTPUT_FLAG_CRLF_NONE ;
263- } else {
264- return ;
265- }
316+ struct log_msg * msg = & msg_generic -> log ;
317+ const char * source_name = log_msg_source_name_get (msg );
318+ enum log_rpc_level level = (enum log_rpc_level )log_msg_get_level (msg );
319+ enum log_rpc_level max_level ;
266320
267321 if (source_name != NULL ) {
268322 for (size_t i = 0 ; i < ARRAY_SIZE (filtered_out_sources ); i ++ ) {
@@ -272,14 +326,20 @@ static void process(const struct log_backend *const backend, union log_msg_gener
272326 }
273327 }
274328
275- /*
276- * The "max_level != LOG_RPC_LEVEL_NONE" condition seems redundant but is neeed because log
277- * messages can be generated without specifying the level. Such messages should still be
278- * rejected if the maximum level is LOG_RPC_LEVEL_NONE.
279- */
329+ if (panic_mode ) {
330+ retain_message (msg );
331+ return ;
332+ }
333+
334+ max_level = stream_level ;
335+
280336 if (max_level != LOG_RPC_LEVEL_NONE && level <= max_level ) {
281- current_level = level ;
282- log_formatter (& log_output_rpc , & msg -> log , flags );
337+ /*
338+ * The "max_level != LOG_RPC_LEVEL_NONE" condition seems redundant but is in fact
339+ * needed, because a log message can be generated with the level NONE, and such
340+ * a message should also be discarded if the configured maximum level is NONE.
341+ */
342+ stream_message (msg );
283343 }
284344}
285345
@@ -303,9 +363,9 @@ static void dropped(const struct log_backend *const backend, uint32_t cnt)
303363
304364 /*
305365 * Due to an issue in Zephyr logging subsystem (see upstream PR 78145), this function
306- * may be called more often than the configured periodicity (1000ms by default), which
307- * might cause sending RPC events to the RPC client indefinitely, wasting the bandwidth
308- * of the RPC communication .
366+ * may be called more often than the configured periodicity (1000ms by default).
367+ * This might cause sending excessively many RPC events to the RPC client, which would
368+ * waste the RCP transport's bandwidth .
309369 *
310370 * For this reason, do not report the dropped log messages until this issue is fixed.
311371 */
0 commit comments