Projektarbeit Line Following Robot bei Prof. Chowanetz im WS22/23
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

mmalomx_commands.c 16KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462
  1. /*
  2. Copyright (c) 2012, Broadcom Europe Ltd
  3. All rights reserved.
  4. Redistribution and use in source and binary forms, with or without
  5. modification, are permitted provided that the following conditions are met:
  6. * Redistributions of source code must retain the above copyright
  7. notice, this list of conditions and the following disclaimer.
  8. * Redistributions in binary form must reproduce the above copyright
  9. notice, this list of conditions and the following disclaimer in the
  10. documentation and/or other materials provided with the distribution.
  11. * Neither the name of the copyright holder nor the
  12. names of its contributors may be used to endorse or promote products
  13. derived from this software without specific prior written permission.
  14. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
  15. ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  16. WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  17. DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
  18. DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  19. (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  20. LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  21. ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  22. (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  23. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  24. */
  25. #include "mmalomx.h"
  26. #include "mmalomx_commands.h"
  27. #include "mmalomx_buffer.h"
  28. #include "mmalomx_logging.h"
  29. typedef struct {
  30. OMX_STATETYPE state;
  31. OMX_STATETYPE request;
  32. uint32_t actions;
  33. } MMALOMX_STATE_TRANSITION_T;
  34. MMALOMX_STATE_TRANSITION_T state_transition_table[] =
  35. {
  36. {OMX_StateInvalid, OMX_StateInvalid, 0},
  37. {OMX_StateLoaded, OMX_StateIdle, MMALOMX_ACTION_CHECK_ALLOCATED|MMALOMX_ACTION_ENABLE},
  38. {OMX_StateLoaded, OMX_StateWaitForResources, 0},
  39. {OMX_StateWaitForResources, OMX_StateLoaded, 0},
  40. {OMX_StateWaitForResources, OMX_StateIdle, MMALOMX_ACTION_CHECK_ALLOCATED|MMALOMX_ACTION_ENABLE},
  41. {OMX_StateIdle, OMX_StateLoaded, MMALOMX_ACTION_CHECK_DEALLOCATED|MMALOMX_ACTION_DISABLE},
  42. {OMX_StateIdle, OMX_StateExecuting, 0},
  43. {OMX_StateIdle, OMX_StatePause, 0},
  44. {OMX_StateExecuting, OMX_StateIdle, MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED},
  45. {OMX_StateExecuting, OMX_StatePause, 0},
  46. {OMX_StatePause, OMX_StateIdle, 0},
  47. {OMX_StatePause, OMX_StateExecuting, 0},
  48. {OMX_StateMax, OMX_StateMax, 0}
  49. };
  50. /*****************************************************************************/
  51. static unsigned int mmalomx_state_transition_get(OMX_STATETYPE state, OMX_STATETYPE request)
  52. {
  53. unsigned int i;
  54. for (i = 0; state_transition_table[i].state != OMX_StateMax; i++)
  55. if (state_transition_table[i].state == state &&
  56. state_transition_table[i].request == request)
  57. break;
  58. return state_transition_table[i].state != OMX_StateMax ? i : 0;
  59. }
  60. /*****************************************************************************/
  61. static void mmalomx_buffer_cb_io(MMAL_PORT_T *port, MMAL_BUFFER_HEADER_T *buffer)
  62. {
  63. mmalomx_buffer_return((MMALOMX_PORT_T *)port->userdata, buffer);
  64. }
  65. /*****************************************************************************/
  66. static void mmalomx_commands_check_port_actions(MMALOMX_COMPONENT_T *component,
  67. MMALOMX_PORT_T *port)
  68. {
  69. uint32_t exec_actions = 0;
  70. MMAL_STATUS_T status;
  71. MMALOMX_LOCK_PORT(component, port);
  72. if (!port->actions)
  73. {
  74. MMALOMX_UNLOCK_PORT(component, port);
  75. return;
  76. }
  77. if (port->actions & MMALOMX_ACTION_FLUSH)
  78. {
  79. port->actions &= ~MMALOMX_ACTION_FLUSH;
  80. port->actions |= MMALOMX_ACTION_PENDING_FLUSH;
  81. exec_actions |= MMALOMX_ACTION_PENDING_FLUSH;
  82. }
  83. if ((port->actions & MMALOMX_ACTION_DISABLE) &&
  84. (!port->buffers_in_transit ||
  85. !(port->actions & MMALOMX_ACTION_CHECK_FLUSHED)))
  86. {
  87. port->actions &= ~MMALOMX_ACTION_DISABLE;
  88. port->actions |= MMALOMX_ACTION_PENDING_DISABLE;
  89. exec_actions |= MMALOMX_ACTION_PENDING_DISABLE;
  90. }
  91. if ((port->actions & MMALOMX_ACTION_ENABLE) &&
  92. port->buffers)
  93. {
  94. /* We defer enabling the mmal port until the first buffer allocation
  95. * has been done. Only at that point do we know for sure whether we
  96. * are going to use shared memory or not.
  97. * We might want to delay it to just before sending the event to the client ???
  98. */
  99. port->actions &= ~MMALOMX_ACTION_ENABLE;
  100. port->actions |= MMALOMX_ACTION_PENDING_ENABLE;
  101. exec_actions |= MMALOMX_ACTION_PENDING_ENABLE;
  102. }
  103. MMALOMX_UNLOCK_PORT(component, port);
  104. if (exec_actions & MMALOMX_ACTION_PENDING_FLUSH)
  105. mmal_port_flush(port->mmal);
  106. if (exec_actions & MMALOMX_ACTION_PENDING_DISABLE)
  107. {
  108. mmal_port_disable(port->mmal);
  109. /* If there was a port format changed event, we need to make sure
  110. * the new format has been committed */
  111. if (port->format_changed)
  112. {
  113. status = mmal_port_format_commit(port->mmal);
  114. if (status != MMAL_SUCCESS)
  115. LOG_WARN("could not commit new format (%i)", status);
  116. port->format_changed = MMAL_FALSE;
  117. }
  118. }
  119. if (exec_actions & MMALOMX_ACTION_PENDING_ENABLE)
  120. {
  121. status = mmal_port_enable(port->mmal, mmalomx_buffer_cb_io);
  122. if (status == MMAL_SUCCESS)
  123. status = mmal_pool_resize(port->pool, port->mmal->buffer_num, 0);
  124. if (status != MMAL_SUCCESS)
  125. mmalomx_callback_event_handler(component, OMX_EventError, mmalil_error_to_omx(status), 0, NULL);
  126. /* FIXME: we're still going to generate a cmd complete. Not sure if that's an issue. */
  127. }
  128. MMALOMX_LOCK_PORT(component, port);
  129. port->actions &= ~exec_actions;
  130. if ((port->actions & MMALOMX_ACTION_CHECK_ALLOCATED) && port->populated)
  131. port->actions &= ~MMALOMX_ACTION_CHECK_ALLOCATED;
  132. if ((port->actions & MMALOMX_ACTION_CHECK_DEALLOCATED) && !port->buffers)
  133. port->actions &= ~MMALOMX_ACTION_CHECK_DEALLOCATED;
  134. if ((port->actions & MMALOMX_ACTION_CHECK_FLUSHED) && !port->buffers_in_transit)
  135. port->actions &= ~MMALOMX_ACTION_CHECK_FLUSHED;
  136. exec_actions = port->actions;
  137. if (port->actions == MMALOMX_ACTION_NOTIFY_FLUSH ||
  138. port->actions == MMALOMX_ACTION_NOTIFY_ENABLE ||
  139. port->actions == MMALOMX_ACTION_NOTIFY_DISABLE)
  140. port->actions = 0; /* We're done */
  141. MMALOMX_UNLOCK_PORT(component, port);
  142. if (exec_actions == MMALOMX_ACTION_NOTIFY_FLUSH)
  143. mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
  144. OMX_CommandFlush, port->index, NULL);
  145. else if (exec_actions == MMALOMX_ACTION_NOTIFY_ENABLE)
  146. mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
  147. OMX_CommandPortEnable, port->index, NULL);
  148. else if (exec_actions == MMALOMX_ACTION_NOTIFY_DISABLE)
  149. mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
  150. OMX_CommandPortDisable, port->index, NULL);
  151. }
  152. /*****************************************************************************/
  153. void mmalomx_commands_actions_check(MMALOMX_COMPONENT_T *component)
  154. {
  155. uint32_t actions_left = 0;
  156. unsigned int i;
  157. for (i = 0; i < component->ports_num; i++)
  158. mmalomx_commands_check_port_actions(component, &component->ports[i]);
  159. MMALOMX_LOCK(component);
  160. for (i = 0; i < component->ports_num; i++)
  161. actions_left |= component->ports[i].actions;
  162. if (!actions_left && component->state_transition)
  163. {
  164. component->state = state_transition_table[component->state_transition].request;
  165. component->state_transition = 0;
  166. actions_left = MMALOMX_ACTION_NOTIFY_STATE;
  167. }
  168. MMALOMX_UNLOCK(component);
  169. if (actions_left == MMALOMX_ACTION_NOTIFY_STATE)
  170. {
  171. mmalomx_callback_event_handler(component, OMX_EventCmdComplete,
  172. OMX_CommandStateSet, component->state, NULL);
  173. actions_left = 0;
  174. }
  175. /* If we're not currently processing a command, we can start processing
  176. * the next one. */
  177. if (!actions_left)
  178. mmalomx_commands_actions_next(component);
  179. }
  180. /*****************************************************************************/
  181. void mmalomx_commands_actions_signal(MMALOMX_COMPONENT_T *component)
  182. {
  183. if (component->cmd_thread_used)
  184. vcos_semaphore_post(&component->cmd_sema);
  185. else
  186. mmalomx_commands_actions_check(component);
  187. }
  188. /*****************************************************************************/
  189. OMX_ERRORTYPE mmalomx_command_state_set(
  190. OMX_HANDLETYPE hComponent,
  191. OMX_STATETYPE state)
  192. {
  193. MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
  194. unsigned int i, transition;
  195. if (component->state == state)
  196. {
  197. mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorSameState, 0, NULL);
  198. return OMX_ErrorNone;
  199. }
  200. /* We're asked to transition to StateInvalid */
  201. if (state == OMX_StateInvalid)
  202. {
  203. component->state = state;
  204. mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorInvalidState, 0, NULL);
  205. return OMX_ErrorNone;
  206. }
  207. /* Commands are being queued so we should never get into that state */
  208. vcos_assert(!component->state_transition);
  209. /* Check the transition is valid */
  210. transition = mmalomx_state_transition_get(component->state, state);
  211. if (!transition)
  212. {
  213. mmalomx_callback_event_handler(component, OMX_EventError, OMX_ErrorIncorrectStateTransition, 0, NULL);
  214. return OMX_ErrorNone;
  215. }
  216. /* Special case for transition in and out of Executing */
  217. if (state == OMX_StateExecuting || component->state == OMX_StateExecuting)
  218. {
  219. MMAL_STATUS_T status;
  220. if (state == OMX_StateExecuting)
  221. status = mmal_component_enable(component->mmal);
  222. else
  223. status = mmal_component_disable(component->mmal);
  224. if (status != MMAL_SUCCESS)
  225. {
  226. LOG_ERROR("could not %s %s", state == OMX_StateExecuting ? "enable" : "disable", component->name);
  227. mmalomx_callback_event_handler(component, OMX_EventError, mmalil_error_to_omx(status), 0, NULL);
  228. return OMX_ErrorNone;
  229. }
  230. }
  231. MMALOMX_LOCK(component);
  232. component->state_transition = transition;
  233. for (i = 0; i < component->ports_num; i++)
  234. {
  235. if (!component->ports[i].enabled)
  236. continue;
  237. MMALOMX_LOCK_PORT(component, component->ports + i);
  238. component->ports[i].actions = state_transition_table[transition].actions;
  239. /* If we're transitionning from Idle to Loaded we'd rather do a flush first
  240. * to avoid the cmd thread to block for too long (mmal_disable is a
  241. * blocking call). */
  242. if (state_transition_table[transition].state == OMX_StateIdle &&
  243. state_transition_table[transition].request == OMX_StateLoaded &&
  244. component->cmd_thread_used)
  245. component->ports[i].actions |= MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED;
  246. MMALOMX_UNLOCK_PORT(component, component->ports + i);
  247. }
  248. MMALOMX_UNLOCK(component);
  249. mmalomx_commands_actions_check(component);
  250. return OMX_ErrorNone;
  251. }
  252. /*****************************************************************************/
  253. OMX_ERRORTYPE mmalomx_command_port_mark(
  254. OMX_HANDLETYPE hComponent,
  255. OMX_U32 nPortIndex,
  256. OMX_PTR *pCmdData)
  257. {
  258. MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
  259. OMX_MARKTYPE *mark = (OMX_MARKTYPE *)pCmdData;
  260. MMALOMX_PORT_T *port;
  261. if (nPortIndex >= component->ports_num)
  262. return OMX_ErrorBadPortIndex;
  263. port = &component->ports[nPortIndex];
  264. if (port->marks_num == MAX_MARKS_NUM)
  265. return OMX_ErrorInsufficientResources;
  266. port->marks[(port->marks_first + port->marks_num) % MAX_MARKS_NUM] = *mark;
  267. port->marks_num++;
  268. return OMX_ErrorNone;
  269. }
  270. /*****************************************************************************/
  271. OMX_ERRORTYPE mmalomx_command_port_flush(
  272. OMX_HANDLETYPE hComponent,
  273. OMX_U32 nPortIndex)
  274. {
  275. MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
  276. MMALOMX_LOCK_PORT(component, &component->ports[nPortIndex]);
  277. component->ports[nPortIndex].actions =
  278. MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED|MMALOMX_ACTION_NOTIFY_FLUSH;
  279. MMALOMX_UNLOCK_PORT(component, &component->ports[nPortIndex]);
  280. mmalomx_commands_actions_check(component);
  281. return OMX_ErrorNone;
  282. }
  283. /*****************************************************************************/
  284. OMX_ERRORTYPE mmalomx_command_port_enable(
  285. OMX_HANDLETYPE hComponent,
  286. OMX_U32 nPortIndex)
  287. {
  288. MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
  289. component->ports[nPortIndex].enabled = MMAL_TRUE;
  290. if (component->state == OMX_StateLoaded ||
  291. component->state == OMX_StateWaitForResources)
  292. {
  293. mmalomx_callback_event_handler(component, OMX_EventCmdComplete, OMX_CommandPortEnable, nPortIndex, NULL);
  294. return OMX_ErrorNone;
  295. }
  296. MMALOMX_LOCK_PORT(component, &component->ports[nPortIndex]);
  297. component->ports[nPortIndex].actions =
  298. MMALOMX_ACTION_CHECK_ALLOCATED|MMALOMX_ACTION_ENABLE|MMALOMX_ACTION_NOTIFY_ENABLE;
  299. MMALOMX_UNLOCK_PORT(component, &component->ports[nPortIndex]);
  300. mmalomx_commands_actions_check(component);
  301. return OMX_ErrorNone;
  302. }
  303. /*****************************************************************************/
  304. OMX_ERRORTYPE mmalomx_command_port_disable(
  305. OMX_HANDLETYPE hComponent,
  306. OMX_U32 nPortIndex)
  307. {
  308. MMALOMX_COMPONENT_T *component = (MMALOMX_COMPONENT_T *)hComponent;
  309. component->ports[nPortIndex].enabled = MMAL_FALSE;
  310. if (component->state == OMX_StateLoaded ||
  311. component->state == OMX_StateWaitForResources)
  312. {
  313. mmalomx_callback_event_handler(component, OMX_EventCmdComplete, OMX_CommandPortDisable, nPortIndex, NULL);
  314. return OMX_ErrorNone;
  315. }
  316. MMALOMX_LOCK_PORT(component, &component->ports[nPortIndex]);
  317. component->ports[nPortIndex].actions =
  318. MMALOMX_ACTION_DISABLE|MMALOMX_ACTION_CHECK_DEALLOCATED|MMALOMX_ACTION_NOTIFY_DISABLE;
  319. if (component->cmd_thread_used)
  320. component->ports[nPortIndex].actions |=
  321. MMALOMX_ACTION_FLUSH|MMALOMX_ACTION_CHECK_FLUSHED;
  322. MMALOMX_UNLOCK_PORT(component, &component->ports[nPortIndex]);
  323. mmalomx_commands_actions_check(component);
  324. return OMX_ErrorNone;
  325. }
  326. /*****************************************************************************/
  327. OMX_ERRORTYPE mmalomx_command_queue(
  328. MMALOMX_COMPONENT_T *component,
  329. OMX_U32 arg1, OMX_U32 arg2)
  330. {
  331. MMAL_BUFFER_HEADER_T *cmd = mmal_queue_get(component->cmd_pool->queue);
  332. if (!vcos_verify(cmd))
  333. {
  334. LOG_ERROR("command queue too small");
  335. return OMX_ErrorInsufficientResources;
  336. }
  337. cmd->cmd = arg1;
  338. cmd->offset = arg2;
  339. mmal_queue_put(component->cmd_queue, cmd);
  340. mmalomx_commands_actions_signal(component);
  341. return OMX_ErrorNone;
  342. }
  343. /*****************************************************************************/
  344. OMX_ERRORTYPE mmalomx_command_dequeue(
  345. MMALOMX_COMPONENT_T *component,
  346. OMX_U32 *arg1, OMX_U32 *arg2)
  347. {
  348. MMAL_BUFFER_HEADER_T *cmd = mmal_queue_get(component->cmd_queue);
  349. if (!cmd)
  350. return OMX_ErrorNoMore;
  351. *arg1 = cmd->cmd;
  352. *arg2 = cmd->offset;
  353. mmal_buffer_header_release(cmd);
  354. return OMX_ErrorNone;
  355. }
  356. /*****************************************************************************/
  357. void mmalomx_commands_actions_next(MMALOMX_COMPONENT_T *component)
  358. {
  359. OMX_ERRORTYPE status = OMX_ErrorNone;
  360. OMX_COMMANDTYPE cmd;
  361. OMX_U32 arg1, arg2, nParam1;
  362. unsigned int i;
  363. status = mmalomx_command_dequeue(component, &arg1, &arg2);
  364. if (status != OMX_ErrorNone)
  365. return;
  366. cmd = (OMX_COMMANDTYPE)arg1;
  367. nParam1 = arg2;
  368. if (cmd == OMX_CommandStateSet)
  369. {
  370. mmalomx_command_state_set((OMX_HANDLETYPE)&component->omx, nParam1);
  371. }
  372. else if (cmd == OMX_CommandFlush)
  373. {
  374. for (i = 0; i < component->ports_num; i++)
  375. if (i == nParam1 || nParam1 == OMX_ALL)
  376. mmalomx_command_port_flush((OMX_HANDLETYPE)&component->omx, i);
  377. }
  378. else if (cmd == OMX_CommandPortEnable)
  379. {
  380. for (i = 0; i < component->ports_num; i++)
  381. if (i == nParam1 || nParam1 == OMX_ALL)
  382. mmalomx_command_port_enable((OMX_HANDLETYPE)&component->omx, i);
  383. }
  384. else if (cmd == OMX_CommandPortDisable)
  385. {
  386. for (i = 0; i < component->ports_num; i++)
  387. if (i == nParam1 || nParam1 == OMX_ALL)
  388. mmalomx_command_port_disable((OMX_HANDLETYPE)&component->omx, i);
  389. }
  390. }