holado 0.2.1__py3-none-any.whl → 0.2.3__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of holado might be problematic. Click here for more details.

Files changed (524) hide show
  1. holado/__init__.py +8 -4
  2. {holado-0.2.1.dist-info → holado-0.2.3.dist-info}/METADATA +13 -9
  3. holado-0.2.3.dist-info/RECORD +535 -0
  4. holado_ais/__init__.py +33 -0
  5. holado_ais/ais/MaritimeIdentificationDigits.csv +295 -0
  6. holado_ais/ais/ais_manager.py +151 -0
  7. holado_ais/ais/ais_messages.py +203 -0
  8. holado_ais/ais/ais_payload.py +35 -0
  9. holado_ais/ais/enums.py +37 -0
  10. holado_ais/ais/patch_pyais.py +1303 -0
  11. holado_ais/tests/behave/steps/__init__.py +17 -0
  12. holado_ais/tests/behave/steps/ais/__init__.py +0 -0
  13. holado_ais/tests/behave/steps/ais/ais_manager_steps.py +50 -0
  14. holado_ais/tests/behave/steps/ais/ais_messages_steps.py +182 -0
  15. holado_binary/__init__.py +17 -0
  16. holado_binary/ipc/binary.py +125 -0
  17. holado_binary/ipc/bit_series.py +307 -0
  18. holado_binary/tests/behave/steps/__init__.py +17 -0
  19. holado_binary/tests/behave/steps/ipc/binary_steps.py +57 -0
  20. holado_binary/tests/behave/steps/ipc/bit_series_steps.py +131 -0
  21. holado_context/__init__.py +16 -0
  22. holado_context/tests/behave/steps/__init__.py +16 -0
  23. holado_context/tests/behave/steps/private/__init__.py +16 -0
  24. holado_context/tests/behave/steps/private/common/context_steps.py +36 -0
  25. holado_core/__init__.py +32 -0
  26. holado_core/common/__init__.py +0 -0
  27. holado_core/common/actors/actions.py +97 -0
  28. holado_core/common/actors/actor.py +226 -0
  29. holado_core/common/actors/element_actor.py +32 -0
  30. holado_core/common/actors/find_actor.py +106 -0
  31. holado_core/common/actors/tree_actor.py +32 -0
  32. holado_core/common/actors/verify_actions.py +69 -0
  33. holado_core/common/block/base.py +122 -0
  34. holado_core/common/block/block_manager.py +173 -0
  35. holado_core/common/block/block_method.py +46 -0
  36. holado_core/common/block/block_steps.py +37 -0
  37. holado_core/common/block/function.py +42 -0
  38. holado_core/common/block/scope_function.py +28 -0
  39. holado_core/common/block/scope_manager.py +238 -0
  40. holado_core/common/block/scope_steps.py +141 -0
  41. holado_core/common/criterias/and_criteria.py +61 -0
  42. holado_core/common/criterias/criteria.py +78 -0
  43. holado_core/common/criterias/or_criteria.py +64 -0
  44. holado_core/common/criterias/tools/criteria_context.py +20 -0
  45. holado_core/common/criterias/tools/criteria_parameters.py +18 -0
  46. holado_core/common/drivers/driver.py +153 -0
  47. holado_core/common/drivers/element_driver.py +30 -0
  48. holado_core/common/drivers/element_internal_api.py +239 -0
  49. holado_core/common/drivers/internal_api.py +40 -0
  50. holado_core/common/drivers/tree_driver.py +30 -0
  51. holado_core/common/drivers/tree_internal_api.py +176 -0
  52. holado_core/common/exceptions/__init__.py +0 -0
  53. holado_core/common/exceptions/element_exception.py +28 -0
  54. holado_core/common/exceptions/exceptions.py +24 -0
  55. holado_core/common/exceptions/functional_exception.py +21 -0
  56. holado_core/common/exceptions/holado_exception.py +25 -0
  57. holado_core/common/exceptions/technical_exception.py +27 -0
  58. holado_core/common/exceptions/timeout_exception.py +20 -0
  59. holado_core/common/exceptions/verify_exception.py +20 -0
  60. holado_core/common/finders/after_in_tree_finder.py +87 -0
  61. holado_core/common/finders/element_finder.py +60 -0
  62. holado_core/common/finders/else_finder.py +105 -0
  63. holado_core/common/finders/finder.py +478 -0
  64. holado_core/common/finders/or_finder.py +98 -0
  65. holado_core/common/finders/then_finder.py +157 -0
  66. holado_core/common/finders/tools/enums.py +30 -0
  67. holado_core/common/finders/tools/find_builder.py +118 -0
  68. holado_core/common/finders/tools/find_context.py +405 -0
  69. holado_core/common/finders/tools/find_info.py +27 -0
  70. holado_core/common/finders/tools/find_parameters.py +240 -0
  71. holado_core/common/finders/tools/find_updater.py +95 -0
  72. holado_core/common/finders/tools/finder_info.py +26 -0
  73. holado_core/common/finders/tree_finder.py +146 -0
  74. holado_core/common/handlers/__init__.py +0 -0
  75. holado_core/common/handlers/abstracts/base_redo.py +695 -0
  76. holado_core/common/handlers/abstracts/get_or_create.py +120 -0
  77. holado_core/common/handlers/element_holder.py +122 -0
  78. holado_core/common/handlers/enums.py +23 -0
  79. holado_core/common/handlers/exceptions/redo_exceptions.py +28 -0
  80. holado_core/common/handlers/features/resource_by_name.py +187 -0
  81. holado_core/common/handlers/features/resource_by_type.py +174 -0
  82. holado_core/common/handlers/redo.py +119 -0
  83. holado_core/common/handlers/wait.py +127 -0
  84. holado_core/common/inspectors/element_inspector.py +57 -0
  85. holado_core/common/inspectors/inspector.py +221 -0
  86. holado_core/common/inspectors/tools/inspect_builder.py +169 -0
  87. holado_core/common/inspectors/tools/inspect_context.py +69 -0
  88. holado_core/common/inspectors/tools/inspect_parameters.py +181 -0
  89. holado_core/common/inspectors/tree_inspector.py +73 -0
  90. holado_core/common/resource/persisted_data_manager.py +113 -0
  91. holado_core/common/resource/persisted_method_to_call_manager.py +133 -0
  92. holado_core/common/resource/resource_manager.py +143 -0
  93. holado_core/common/tables/__init__.py +1 -0
  94. holado_core/common/tables/comparators/__init__.py +0 -0
  95. holado_core/common/tables/comparators/boolean_table_cell_comparator.py +25 -0
  96. holado_core/common/tables/comparators/bytes_table_cell_comparator.py +25 -0
  97. holado_core/common/tables/comparators/datetime_table_cell_comparator.py +24 -0
  98. holado_core/common/tables/comparators/float_table_cell_comparator.py +31 -0
  99. holado_core/common/tables/comparators/integer_table_cell_comparator.py +25 -0
  100. holado_core/common/tables/comparators/internal_table_cell_comparator.py +30 -0
  101. holado_core/common/tables/comparators/string_table_cell_comparator.py +24 -0
  102. holado_core/common/tables/comparators/string_table_comparator.py +29 -0
  103. holado_core/common/tables/comparators/string_table_row_comparator.py +29 -0
  104. holado_core/common/tables/comparators/table_cell_comparator.py +40 -0
  105. holado_core/common/tables/comparators/table_comparator.py +209 -0
  106. holado_core/common/tables/comparators/table_comparator_manager.py +60 -0
  107. holado_core/common/tables/comparators/table_row_comparator.py +116 -0
  108. holado_core/common/tables/comparators/table_with_header_comparator.py +68 -0
  109. holado_core/common/tables/converters/__init__.py +0 -0
  110. holado_core/common/tables/converters/table_converter.py +194 -0
  111. holado_core/common/tables/enums.py +23 -0
  112. holado_core/common/tables/table.py +261 -0
  113. holado_core/common/tables/table_cell.py +126 -0
  114. holado_core/common/tables/table_manager.py +366 -0
  115. holado_core/common/tables/table_row.py +169 -0
  116. holado_core/common/tables/table_with_header.py +236 -0
  117. holado_core/common/tools/__init__.py +0 -0
  118. holado_core/common/tools/comparators/comparator.py +151 -0
  119. holado_core/common/tools/comparators/object_comparator.py +21 -0
  120. holado_core/common/tools/converters/converter.py +107 -0
  121. holado_core/common/tools/path_manager.py +185 -0
  122. holado_core/common/tools/string_tools.py +135 -0
  123. holado_core/common/tools/tools.py +172 -0
  124. holado_core/common/transport/__init__.py +0 -0
  125. holado_core/common/transport/crc.py +40 -0
  126. holado_core/tests/behave/steps/__init__.py +20 -0
  127. holado_core/tests/behave/steps/common/__init__.py +0 -0
  128. holado_core/tests/behave/steps/common/common_steps.py +136 -0
  129. holado_core/tests/behave/steps/common/config_steps.py +42 -0
  130. holado_core/tests/behave/steps/common/resource_steps.py +62 -0
  131. holado_core/tests/behave/steps/common/tables_steps.py +537 -0
  132. holado_core/tools/__init__.py +0 -0
  133. holado_core/tools/abstracts/__init__.py +0 -0
  134. holado_core/tools/abstracts/blocking_command_service.py +56 -0
  135. holado_core/tools/abstracts/service.py +48 -0
  136. holado_data/__init__.py +31 -0
  137. holado_data/data/generator/base.py +93 -0
  138. holado_data/data/generator/python_generator.py +30 -0
  139. holado_data/tests/behave/steps/__init__.py +17 -0
  140. holado_data/tests/behave/steps/data/generator_steps.py +91 -0
  141. holado_data/tests/behave/steps/tools/utils_steps.py +60 -0
  142. holado_db/__init__.py +32 -0
  143. holado_db/tests/behave/steps/__init__.py +18 -0
  144. holado_db/tests/behave/steps/tools/db/db_client_steps.py +134 -0
  145. holado_db/tests/behave/steps/tools/db/postgresql_client_steps.py +59 -0
  146. holado_db/tests/behave/steps/tools/db/sqlite_client_steps.py +57 -0
  147. holado_db/tools/db/clients/base/db_client.py +206 -0
  148. holado_db/tools/db/clients/postgresql/postgresql_client.py +65 -0
  149. holado_db/tools/db/clients/sqlite/sqlite_client.py +56 -0
  150. holado_db/tools/db/db_manager.py +109 -0
  151. holado_db/tools/db/query/base/query_builder.py +87 -0
  152. holado_db/tools/db/query/pypika/pypika_query_builder.py +193 -0
  153. holado_db/tools/db/query/query_manager.py +77 -0
  154. holado_docker/__init__.py +25 -0
  155. holado_docker/sdk/docker/docker_client.py +268 -0
  156. holado_docker/sdk/docker/docker_service.py +71 -0
  157. holado_docker/tests/behave/steps/__init__.py +16 -0
  158. holado_docker/tests/behave/steps/tools/docker_steps.py +33 -0
  159. holado_docker/tools/docker_controler/__init__.py +26 -0
  160. holado_docker/tools/docker_controler/docker_controler_client.py +36 -0
  161. holado_docker/tools/docker_controler/docker_controler_server.py +31 -0
  162. holado_docker/tools/docker_controler/proto/compile_proto.py +60 -0
  163. holado_docker/tools/docker_controler/proto/definitions/docker_controler.proto +63 -0
  164. holado_docker/tools/docker_controler/proto/generated/docker_controler_pb2.py +52 -0
  165. holado_docker/tools/docker_controler/proto/generated/docker_controler_pb2_grpc.py +233 -0
  166. holado_grpc/__init__.py +32 -0
  167. holado_grpc/api/rpc/TODO.txt +4 -0
  168. holado_grpc/api/rpc/grpc_client.py +181 -0
  169. holado_grpc/api/rpc/grpc_manager.py +81 -0
  170. holado_grpc/ipc/rpc/__init__.py +0 -0
  171. holado_grpc/ipc/rpc/grpc_compiler.py +45 -0
  172. holado_grpc/ipc/rpc/grpc_services.py +165 -0
  173. holado_grpc/tests/behave/steps/__init__.py +16 -0
  174. holado_grpc/tests/behave/steps/api/grpc_client_steps.py +173 -0
  175. holado_grpc/tests/behave/steps/private/__init__.py +16 -0
  176. holado_grpc/tests/behave/steps/private/api/grpc_steps.py +77 -0
  177. holado_helper/__init__.py +35 -0
  178. holado_helper/debug/README.txt +32 -0
  179. holado_helper/debug/memory/memory_profiler.py +106 -0
  180. holado_helper/docker/init_user.sh +24 -0
  181. holado_helper/docker/logging.conf +42 -0
  182. holado_helper/docker/run_holado_test_nonreg_in_docker.sh +120 -0
  183. holado_helper/docker/run_terminal_in_docker-with_docker_control.sh +103 -0
  184. holado_helper/docker/run_terminal_in_docker.sh +101 -0
  185. holado_helper/holado_module_template/__init__.py +31 -0
  186. holado_helper/holado_module_template/test/behave/steps/__init__.py +16 -0
  187. holado_helper/holado_module_template/test/behave/steps/private/__init__.py +16 -0
  188. holado_helper/script/action.py +109 -0
  189. holado_helper/script/action_script.py +477 -0
  190. holado_helper/script/any_action_script.py +126 -0
  191. holado_helper/script/behave_action_script.py +99 -0
  192. holado_helper/script/csv_action_script.py +142 -0
  193. holado_helper/script/initialize_script.py +115 -0
  194. holado_helper/script/input_output_script.py +136 -0
  195. holado_helper/script/job.py +75 -0
  196. holado_helper/script/json_action_script.py +104 -0
  197. holado_helper/script/script.py +110 -0
  198. holado_json/__init__.py +16 -0
  199. holado_json/ipc/json.py +125 -0
  200. holado_json/ipc/json_converter.py +69 -0
  201. holado_json/ipc/json_types.py +183 -0
  202. holado_json/tests/behave/steps/__init__.py +16 -0
  203. holado_json/tests/behave/steps/ipc/__init__.py +0 -0
  204. holado_json/tests/behave/steps/ipc/json_steps.py +120 -0
  205. holado_keycloak/__init__.py +16 -0
  206. holado_keycloak/tests/behave/steps/__init__.py +16 -0
  207. holado_keycloak/tests/behave/steps/tools/keycloak_client_steps.py +59 -0
  208. holado_keycloak/tools/keycloak/__init__.py +0 -0
  209. holado_keycloak/tools/keycloak/keycloak_client.py +61 -0
  210. holado_logging/__init__.py +36 -0
  211. holado_logging/common/logging/holado_logger.py +75 -0
  212. holado_logging/common/logging/log_config.py +128 -0
  213. holado_logging/common/logging/log_manager.py +292 -0
  214. holado_multitask/__init__.py +33 -0
  215. holado_multitask/multiprocessing/context/process_context.py +35 -0
  216. holado_multitask/multiprocessing/function_process.py +102 -0
  217. holado_multitask/multiprocessing/periodic_function_process.py +135 -0
  218. holado_multitask/multiprocessing/process.py +196 -0
  219. holado_multitask/multiprocessing/processesmanager.py +133 -0
  220. holado_multitask/multitasking/multitask_manager.py +439 -0
  221. holado_multitask/multithreading/__init__.py +0 -0
  222. holado_multitask/multithreading/context/thread_context.py +84 -0
  223. holado_multitask/multithreading/functionthreaded.py +129 -0
  224. holado_multitask/multithreading/loopfunctionthreaded.py +45 -0
  225. holado_multitask/multithreading/loopthread.py +100 -0
  226. holado_multitask/multithreading/periodicfunctionthreaded.py +136 -0
  227. holado_multitask/multithreading/reflection/inspect.py +47 -0
  228. holado_multitask/multithreading/reflection/sys.py +29 -0
  229. holado_multitask/multithreading/reflection/traceback.py +35 -0
  230. holado_multitask/multithreading/thread.py +177 -0
  231. holado_multitask/multithreading/threadsmanager.py +162 -0
  232. holado_multitask/multithreading/timer.py +48 -0
  233. holado_multitask/tests/behave/steps/__init__.py +17 -0
  234. holado_multitask/tests/behave/steps/multiprocessing_steps.py +138 -0
  235. holado_multitask/tests/behave/steps/multithreading_steps.py +129 -0
  236. holado_protobuf/__init__.py +61 -0
  237. holado_protobuf/ipc/protobuf/__init__.py +0 -0
  238. holado_protobuf/ipc/protobuf/abstracts/type.py +45 -0
  239. holado_protobuf/ipc/protobuf/protobuf_compiler.py +118 -0
  240. holado_protobuf/ipc/protobuf/protobuf_converter.py +153 -0
  241. holado_protobuf/ipc/protobuf/protobuf_messages.py +965 -0
  242. holado_protobuf/ipc/protobuf/protobuf_modifier.py +65 -0
  243. holado_protobuf/ipc/protobuf/types/__init__.py +0 -0
  244. holado_protobuf/ipc/protobuf/types/google/__init__.py +0 -0
  245. holado_protobuf/ipc/protobuf/types/google/protobuf.py +124 -0
  246. holado_protobuf/tests/behave/steps/__init__.py +16 -0
  247. holado_protobuf/tests/behave/steps/ipc/protobuf_steps.py +297 -0
  248. holado_python/__init__.py +35 -0
  249. holado_python/common/enums.py +34 -0
  250. holado_python/common/iterables.py +30 -0
  251. holado_python/common/tools/comparators/boolean_comparator.py +37 -0
  252. holado_python/common/tools/comparators/bytes_comparator.py +48 -0
  253. holado_python/common/tools/comparators/datetime_comparator.py +74 -0
  254. holado_python/common/tools/comparators/float_comparator.py +97 -0
  255. holado_python/common/tools/comparators/integer_comparator.py +37 -0
  256. holado_python/common/tools/comparators/string_comparator.py +99 -0
  257. holado_python/common/tools/comparators/type_comparator.py +31 -0
  258. holado_python/common/tools/datetime.py +279 -0
  259. holado_python/standard_library/csv.py +207 -0
  260. holado_python/standard_library/hashlib.py +82 -0
  261. holado_python/standard_library/multiprocessing.py +62 -0
  262. holado_python/standard_library/queue.py +79 -0
  263. holado_python/standard_library/socket/blocking_socket.py +136 -0
  264. holado_python/standard_library/socket/echo_server.py +28 -0
  265. holado_python/standard_library/socket/message_socket.py +91 -0
  266. holado_python/standard_library/socket/non_blocking_socket.py +151 -0
  267. holado_python/standard_library/socket/socket.py +148 -0
  268. holado_python/standard_library/ssl/resources/certificates/NOTES.txt +5 -0
  269. holado_python/standard_library/ssl/resources/certificates/localhost.crt +19 -0
  270. holado_python/standard_library/ssl/resources/certificates/localhost.key +28 -0
  271. holado_python/standard_library/ssl/ssl.py +81 -0
  272. holado_python/standard_library/typing.py +192 -0
  273. holado_python/tests/behave/steps/__init__.py +27 -0
  274. holado_python/tests/behave/steps/builtins/str_steps.py +45 -0
  275. holado_python/tests/behave/steps/convert_steps.py +59 -0
  276. holado_python/tests/behave/steps/iterable_steps.py +87 -0
  277. holado_python/tests/behave/steps/standard_library/csv_steps.py +134 -0
  278. holado_python/tests/behave/steps/standard_library/datetime_steps.py +163 -0
  279. holado_python/tests/behave/steps/standard_library/hashlib_steps.py +57 -0
  280. holado_python/tests/behave/steps/standard_library/multiprocessing_steps.py +56 -0
  281. holado_python/tests/behave/steps/standard_library/queue_steps.py +358 -0
  282. holado_python/tests/behave/steps/standard_library/socket_steps.py +258 -0
  283. holado_python/tests/behave/steps/standard_library/ssl_steps.py +67 -0
  284. holado_rabbitmq/__init__.py +28 -0
  285. holado_rabbitmq/tests/behave/steps/__init__.py +17 -0
  286. holado_rabbitmq/tests/behave/steps/tools/rabbitmq_client_steps.py +537 -0
  287. holado_rabbitmq/tests/behave/steps/tools/rabbitmq_server_steps.py +64 -0
  288. holado_rabbitmq/tools/rabbitmq/rabbitmq_blocking_client.py +311 -0
  289. holado_rabbitmq/tools/rabbitmq/rabbitmq_client.py +675 -0
  290. holado_rabbitmq/tools/rabbitmq/rabbitmq_manager.py +173 -0
  291. holado_rabbitmq/tools/rabbitmq/rabbitmq_select_client.py +428 -0
  292. holado_rabbitmq/tools/rabbitmq/rabbitmq_server.py +24 -0
  293. holado_redis/__init__.py +17 -0
  294. holado_redis/tests/behave/steps/__init__.py +16 -0
  295. holado_redis/tests/behave/steps/tools/redis_client_steps.py +101 -0
  296. holado_redis/tools/redis/TODO.txt +7 -0
  297. holado_redis/tools/redis/redis_client.py +190 -0
  298. holado_redis/tools/redis/redis_manager.py +38 -0
  299. holado_report/__init__.py +27 -0
  300. holado_report/report/analyze/execution_historic_manager.py +96 -0
  301. holado_report/report/analyze/scenario_duration_manager.py +245 -0
  302. holado_report/report/builders/detailed_scenario_failed_report_builder.py +146 -0
  303. holado_report/report/builders/json_execution_historic_report_builder.py +123 -0
  304. holado_report/report/builders/report_builder.py +64 -0
  305. holado_report/report/builders/short_scenario_failed_report_builder.py +76 -0
  306. holado_report/report/builders/summary_report_builder.py +89 -0
  307. holado_report/report/builders/summary_scenario_failed_report_builder.py +56 -0
  308. holado_report/report/builders/summary_scenario_report_builder.py +74 -0
  309. holado_report/report/execution_historic.py +141 -0
  310. holado_report/report/report_manager.py +256 -0
  311. holado_report/report/reports/base_report.py +163 -0
  312. holado_report/report/reports/feature_report.py +106 -0
  313. holado_report/report/reports/scenario_report.py +64 -0
  314. holado_rest/__init__.py +24 -0
  315. holado_rest/api/rest/TODO.txt +2 -0
  316. holado_rest/api/rest/rest_client.py +113 -0
  317. holado_rest/api/rest/rest_manager.py +62 -0
  318. holado_rest/tests/behave/steps/__init__.py +16 -0
  319. holado_rest/tests/behave/steps/api/__init__.py +0 -0
  320. holado_rest/tests/behave/steps/api/rest_client_steps.py +141 -0
  321. holado_rest/tests/behave/steps/private/__init__.py +16 -0
  322. holado_rest/tests/behave/steps/private/api/__init__.py +0 -0
  323. holado_rest/tests/behave/steps/private/api/rest_steps.py +70 -0
  324. holado_s3/__init__.py +17 -0
  325. holado_s3/tests/behave/steps/__init__.py +17 -0
  326. holado_s3/tests/behave/steps/private/__init__.py +16 -0
  327. holado_s3/tests/behave/steps/private/tools/s3_steps.py +89 -0
  328. holado_s3/tests/behave/steps/tools/s3_client_steps.py +403 -0
  329. holado_s3/tests/behave/steps/tools/s3_server_steps.py +57 -0
  330. holado_s3/tools/s3/__init__.py +0 -0
  331. holado_s3/tools/s3/boto3_s3_client.py +59 -0
  332. holado_s3/tools/s3/minio_client.py +75 -0
  333. holado_s3/tools/s3/moto_server.py +52 -0
  334. holado_scripting/__init__.py +53 -0
  335. holado_scripting/common/tools/dynamic_text_manager.py +73 -0
  336. holado_scripting/common/tools/evaluate_parameters.py +210 -0
  337. holado_scripting/common/tools/expression_evaluator.py +387 -0
  338. holado_scripting/common/tools/variable_manager.py +321 -0
  339. holado_scripting/tests/behave/steps/__init__.py +22 -0
  340. holado_scripting/tests/behave/steps/common/tools/variable_convert_steps.py +158 -0
  341. holado_scripting/tests/behave/steps/common/tools/variable_new_steps.py +130 -0
  342. holado_scripting/tests/behave/steps/common/tools/variable_steps.py +108 -0
  343. holado_scripting/tests/behave/steps/common/tools/variable_verify_steps.py +160 -0
  344. holado_scripting/tests/behave/steps/scenario/function_steps.py +77 -0
  345. holado_scripting/tests/behave/steps/scenario/if_steps.py +87 -0
  346. holado_scripting/tests/behave/steps/scenario/loop_steps.py +119 -0
  347. holado_scripting/text/base/base_function.py +25 -0
  348. holado_scripting/text/base/base_verify_function.py +25 -0
  349. holado_scripting/text/base/text_inspecter.py +204 -0
  350. holado_scripting/text/interpreter/exceptions/interpreter_exception.py +25 -0
  351. holado_scripting/text/interpreter/functions/function_cast.py +60 -0
  352. holado_scripting/text/interpreter/functions/function_convert.py +57 -0
  353. holado_scripting/text/interpreter/functions/function_dynamic_value.py +40 -0
  354. holado_scripting/text/interpreter/functions/function_escape_all_bytes.py +35 -0
  355. holado_scripting/text/interpreter/functions/function_exists_variable.py +39 -0
  356. holado_scripting/text/interpreter/functions/function_hex_to_bytes.py +49 -0
  357. holado_scripting/text/interpreter/functions/function_hex_to_int.py +53 -0
  358. holado_scripting/text/interpreter/functions/function_to_base_64.py +41 -0
  359. holado_scripting/text/interpreter/functions/function_to_bytes.py +50 -0
  360. holado_scripting/text/interpreter/functions/function_to_hex.py +42 -0
  361. holado_scripting/text/interpreter/text_interpreter.py +216 -0
  362. holado_scripting/text/verifier/exceptions/verifier_exception.py +21 -0
  363. holado_scripting/text/verifier/functions/verify_function_extract_in.py +35 -0
  364. holado_scripting/text/verifier/functions/verify_function_match_pattern.py +63 -0
  365. holado_scripting/text/verifier/text_verifier.py +103 -0
  366. holado_sftp/__init__.py +16 -0
  367. holado_sftp/tests/behave/steps/__init__.py +17 -0
  368. holado_sftp/tests/behave/steps/private/__init__.py +16 -0
  369. holado_sftp/tests/behave/steps/private/tools/sftp_steps.py +78 -0
  370. holado_sftp/tests/behave/steps/tools/sftp_client_steps.py +94 -0
  371. holado_sftp/tests/behave/steps/tools/sftp_server_steps.py +82 -0
  372. holado_sftp/tools/sftp/__init__.py +0 -0
  373. holado_sftp/tools/sftp/sftp_client.py +103 -0
  374. holado_sftp/tools/sftp/sftp_server.py +39 -0
  375. holado_swagger/__init__.py +31 -0
  376. holado_swagger/swagger_hub/mockserver/mockserver_client.py +82 -0
  377. holado_swagger/swagger_hub/mockserver/mockserver_manager.py +32 -0
  378. holado_swagger/tests/behave/steps/__init__.py +16 -0
  379. holado_swagger/tests/behave/steps/swagger_hub/mockserver_steps.py +74 -0
  380. holado_system/system/command/command.py +216 -0
  381. holado_system/system/command/command_result.py +128 -0
  382. holado_system/system/command/curl_command.py +101 -0
  383. holado_system/system/command/exceptions.py +59 -0
  384. holado_system/system/filesystem/file.py +76 -0
  385. holado_system/system/global_system.py +187 -0
  386. holado_system/tests/behave/steps/__init__.py +18 -0
  387. holado_system/tests/behave/steps/system/commands_steps.py +92 -0
  388. holado_system/tests/behave/steps/system/file_steps.py +215 -0
  389. holado_system/tests/behave/steps/system/system_steps.py +84 -0
  390. holado_test/__init__.py +27 -0
  391. holado_test/behave/__init__.py +0 -0
  392. holado_test/behave/behave.py +397 -0
  393. holado_test/behave/behave_environment.py +143 -0
  394. holado_test/behave/behave_function.py +33 -0
  395. holado_test/behave/behave_manager.py +555 -0
  396. holado_test/behave/independant_runner.py +68 -0
  397. holado_test/behave/scenario/__init__.py +0 -0
  398. holado_test/behave/scenario/behave_step_tools.py +157 -0
  399. holado_test/common/context/feature_context.py +79 -0
  400. holado_test/common/context/scenario_context.py +217 -0
  401. holado_test/common/context/step_context.py +66 -0
  402. holado_test/common/exceptions/undefined_step_exception.py +21 -0
  403. holado_test/scenario/step_tools.py +523 -0
  404. holado_test/scenario/tester_tools.py +52 -0
  405. holado_test/test_config.py +26 -0
  406. holado_test/tests/behave/steps/__init__.py +18 -0
  407. holado_test/tests/behave/steps/scenario/exception_steps.py +87 -0
  408. holado_test/tests/behave/steps/scenario/scenario_steps.py +87 -0
  409. holado_test/tests/behave/steps/scenario/tester_steps.py +65 -0
  410. holado_value/__init__.py +24 -0
  411. holado_value/common/tables/comparators/table_2_value_table_cell_comparator.py +195 -0
  412. holado_value/common/tables/comparators/table_2_value_table_comparator.py +27 -0
  413. holado_value/common/tables/comparators/table_2_value_table_row_comparator.py +27 -0
  414. holado_value/common/tables/comparators/table_2_value_table_with_header_comparator.py +27 -0
  415. holado_value/common/tables/converters/value_table_converter.py +217 -0
  416. holado_value/common/tables/value_table.py +29 -0
  417. holado_value/common/tables/value_table_cell.py +67 -0
  418. holado_value/common/tables/value_table_manager.py +58 -0
  419. holado_value/common/tables/value_table_row.py +44 -0
  420. holado_value/common/tables/value_table_with_header.py +28 -0
  421. holado_value/common/tools/unique_value_manager.py +108 -0
  422. holado_value/common/tools/value.py +164 -0
  423. holado_value/common/tools/value_types.py +35 -0
  424. holado_value/tests/behave/steps/__init__.py +16 -0
  425. holado_value/tests/behave/steps/private/__init__.py +16 -0
  426. holado_ws/__init__.py +16 -0
  427. holado_ws/api/ws/TODO.txt +2 -0
  428. holado_ws/tests/behave/steps/__init__.py +16 -0
  429. holado_ws/tests/behave/steps/api/web_service_steps.py +189 -0
  430. holado_yaml/__init__.py +31 -0
  431. holado_yaml/tests/behave/steps/__init__.py +16 -0
  432. holado_yaml/tests/behave/steps/yaml_steps.py +64 -0
  433. holado_yaml/yaml/yaml_manager.py +86 -0
  434. test_holado/Dockerfile_test_holado +82 -0
  435. test_holado/__init__.py +4 -0
  436. test_holado/__main__.py +25 -0
  437. test_holado/build_docker_image_to_test_holado_in_docker.sh +7 -0
  438. test_holado/environment.py +42 -0
  439. test_holado/features/NonReg/api/REST.feature +21 -0
  440. test_holado/features/NonReg/api/gRPC.feature +122 -0
  441. test_holado/features/NonReg/common/multiprocessing/simple.feature +60 -0
  442. test_holado/features/NonReg/common/system/commands.feature +43 -0
  443. test_holado/features/NonReg/common/system/system.feature +20 -0
  444. test_holado/features/NonReg/common/tables/table.feature +239 -0
  445. test_holado/features/NonReg/common/tables/value_table_conversion.feature +29 -0
  446. test_holado/features/NonReg/common/tools/DateTime.feature +88 -0
  447. test_holado/features/NonReg/common/tools/UniqueValueManager.feature +43 -0
  448. test_holado/features/NonReg/holado_ais/ais_message-bitarray_to_nmea.feature +135 -0
  449. test_holado/features/NonReg/holado_protobuf/protobuf.feature +291 -0
  450. test_holado/features/NonReg/holado_python/convert.feature +20 -0
  451. test_holado/features/NonReg/holado_python/iterable.feature +61 -0
  452. test_holado/features/NonReg/holado_python/standard_library/socket.feature +101 -0
  453. test_holado/features/NonReg/holado_python/standard_library/socket_with_ssl.feature +180 -0
  454. test_holado/features/NonReg/holado_scripting/common/tools/dynamic_text_manager.feature +18 -0
  455. test_holado/features/NonReg/holado_scripting/common/tools/expression_evaluator.feature +185 -0
  456. test_holado/features/NonReg/holado_scripting/common/tools/variable_manager.feature +71 -0
  457. test_holado/features/NonReg/holado_scripting/text/interpreter/interpreter.error.feature +21 -0
  458. test_holado/features/NonReg/holado_scripting/text/interpreter/interpreter.feature +120 -0
  459. test_holado/features/NonReg/holado_yaml/yaml.feature +218 -0
  460. test_holado/features/NonReg/ipc/bit_series.error.feature +33 -0
  461. test_holado/features/NonReg/ipc/bit_series.feature +131 -0
  462. test_holado/features/NonReg/ipc/json.feature +20 -0
  463. test_holado/features/NonReg/scenario/scenario.feature +139 -0
  464. test_holado/features/NonReg/test_steps/behave.feature +275 -0
  465. test_holado/features/NonReg/test_steps/common.feature +100 -0
  466. test_holado/features/NonReg/tools/RabbitMQ.feature +445 -0
  467. test_holado/features/NonReg/tools/RabbitMQ_steps.feature +276 -0
  468. test_holado/features/NonReg/tools/S3/boto3_client.feature +73 -0
  469. test_holado/features/NonReg/tools/S3/minio_client.feature +75 -0
  470. test_holado/features/NonReg/tools/db_sqlite3.feature +41 -0
  471. test_holado/features/NonReg/tools/sFTP.feature +25 -0
  472. test_holado/features/Test/logger.feature +28 -0
  473. test_holado/features/__init__.py +0 -0
  474. test_holado/logging.conf +41 -0
  475. test_holado/resources/proto/definitions/protobuf/custom_types/field_types.proto +24 -0
  476. test_holado/resources/proto/definitions/protobuf/protobuf.dev/tutorial/addressbook.proto +56 -0
  477. test_holado/resources/proto/generated/protobuf/custom_types/field_types_pb2.py +34 -0
  478. test_holado/resources/proto/generated/protobuf/protobuf/dev/tutorial/addressbook_pb2.py +34 -0
  479. test_holado/resources/scripts/list_tags.sh +2 -0
  480. test_holado/resources/scripts/update_resources_proto_generated.py +70 -0
  481. test_holado/steps/__init__.py +0 -0
  482. test_holado/steps/private_steps.py +20 -0
  483. test_holado/steps/public_steps.py +23 -0
  484. test_holado/test_holado_session_context.py +43 -0
  485. test_holado/tools/django/README.txt +3 -0
  486. test_holado/tools/django/api_grpc/api_grpc/__init__.py +0 -0
  487. test_holado/tools/django/api_grpc/api_grpc/api1/__init__.py +0 -0
  488. test_holado/tools/django/api_grpc/api_grpc/api1/admin.py +3 -0
  489. test_holado/tools/django/api_grpc/api_grpc/api1/apps.py +6 -0
  490. test_holado/tools/django/api_grpc/api_grpc/api1/migrations/__init__.py +0 -0
  491. test_holado/tools/django/api_grpc/api_grpc/api1/models.py +3 -0
  492. test_holado/tools/django/api_grpc/api_grpc/api1/proto/__init__.py +0 -0
  493. test_holado/tools/django/api_grpc/api_grpc/api1/proto/account.proto +27 -0
  494. test_holado/tools/django/api_grpc/api_grpc/api1/proto/account_pb2.py +33 -0
  495. test_holado/tools/django/api_grpc/api_grpc/api1/proto/account_pb2_grpc.py +199 -0
  496. test_holado/tools/django/api_grpc/api_grpc/api1/serializers.py +12 -0
  497. test_holado/tools/django/api_grpc/api_grpc/api1/services.py +11 -0
  498. test_holado/tools/django/api_grpc/api_grpc/api1/tests.py +3 -0
  499. test_holado/tools/django/api_grpc/api_grpc/api1/views.py +3 -0
  500. test_holado/tools/django/api_grpc/api_grpc/asgi.py +16 -0
  501. test_holado/tools/django/api_grpc/api_grpc/settings.py +126 -0
  502. test_holado/tools/django/api_grpc/api_grpc/urls.py +27 -0
  503. test_holado/tools/django/api_grpc/api_grpc/wsgi.py +16 -0
  504. test_holado/tools/django/api_grpc/db.sqlite3 +0 -0
  505. test_holado/tools/django/api_grpc/manage.py +27 -0
  506. test_holado/tools/django/api_grpc/manual_test_commands.txt +25 -0
  507. test_holado/tools/django/api_rest/api_rest/__init__.py +0 -0
  508. test_holado/tools/django/api_rest/api_rest/api1/__init__.py +0 -0
  509. test_holado/tools/django/api_rest/api_rest/api1/admin.py +3 -0
  510. test_holado/tools/django/api_rest/api_rest/api1/apps.py +6 -0
  511. test_holado/tools/django/api_rest/api_rest/api1/migrations/__init__.py +0 -0
  512. test_holado/tools/django/api_rest/api_rest/api1/models.py +3 -0
  513. test_holado/tools/django/api_rest/api_rest/api1/serializers.py +15 -0
  514. test_holado/tools/django/api_rest/api_rest/api1/tests.py +3 -0
  515. test_holado/tools/django/api_rest/api_rest/api1/views.py +24 -0
  516. test_holado/tools/django/api_rest/api_rest/asgi.py +16 -0
  517. test_holado/tools/django/api_rest/api_rest/settings.py +133 -0
  518. test_holado/tools/django/api_rest/api_rest/urls.py +32 -0
  519. test_holado/tools/django/api_rest/api_rest/wsgi.py +16 -0
  520. test_holado/tools/django/api_rest/db.sqlite3 +0 -0
  521. test_holado/tools/django/api_rest/manage.py +22 -0
  522. holado-0.2.1.dist-info/RECORD +0 -17
  523. {holado-0.2.1.dist-info → holado-0.2.3.dist-info}/WHEEL +0 -0
  524. {holado-0.2.1.dist-info → holado-0.2.3.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,1303 @@
1
+
2
+ #################################################
3
+ # HolAdo (Holistic Automation do)
4
+ #
5
+ # (C) Copyright 2021-2025 by Eric Klumpp
6
+ #
7
+ # Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
8
+ #
9
+ # The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
10
+
11
+ # The Software is provided “as is”, without warranty of any kind, express or implied, including but not limited to the warranties of merchantability, fitness for a particular purpose and noninfringement. In no event shall the authors or copyright holders be liable for any claim, damages or other liability, whether in an action of contract, tort or otherwise, arising from, out of or in connection with the software or the use or other dealings in the Software.
12
+ #################################################
13
+
14
+
15
+ #################################################
16
+ #
17
+ # Patches are done to follow ITU recommendation:
18
+ # https://www.e-navigation.nl/sites/default/files/R-REC-M.1371-5-201402-I!!PDF-E_1.pdf
19
+ #
20
+ #################################################
21
+
22
+
23
+ import logging
24
+ from bitarray import bitarray
25
+ import attr
26
+ import typing
27
+ import pyais
28
+ from pyais.messages import Payload, bit_field, from_mmsi, NMEA_VALUE, CommunicationStateMixin, TagBlock, ASTERISK, from_turn, to_turn, from_speed, to_speed,\
29
+ from_lat_lon, to_lat_lon, from_10th, to_10th, from_lat_lon_600, to_lat_lon_600
30
+ from pyais.util import get_int, from_bytes_signed, from_bytes, bits2bytes, checksum, chunks, compute_checksum, str_to_bin, bytes2bits
31
+ from pyais.exceptions import InvalidDataTypeException
32
+ from pyais.encode import AIS_SENTENCES, DATA_DICT, get_ais_type, data_to_payload
33
+ import math
34
+ from pyais.constants import NavigationStatus, TurnRate, ManeuverIndicator, EpfdType, ShipType, NavAid, StationType, TransmitMode, StationIntervals
35
+ import functools
36
+
37
+ logger = logging.getLogger(__name__)
38
+
39
+
40
+
41
+ # Add possibility to specify the seq_id in AIS sentence
42
+ # Note: parameter seq_id is just added in some methods of pyais.encode module
43
+
44
+ def HA_ais_to_nmea_0183(payload: str, ais_talker_id: str, radio_channel: str, fill_bits: int, seq_id: str = None) -> AIS_SENTENCES:
45
+ """
46
+ Splits the AIS payload into sentences, ASCII encodes the payload, creates
47
+ and sends the relevant NMEA 0183 sentences. Messages have a maximum length
48
+ of 82 characters, including the $ or ! starting character and the ending <LF>.
49
+
50
+ HINT:
51
+ This method takes care of splitting large payloads (larger than 60 characters)
52
+ into multiple sentences. With a total of 80 maximum chars excluding end of line
53
+ per sentence, and 20 chars head + tail in the nmea 0183 carrier protocol, 60
54
+ chars remain for the actual payload.
55
+
56
+ @param payload: Armored AIs payload.
57
+ @param ais_talker_id: AIS talker ID (AIVDO or AIVDM)
58
+ @param radio_channel: Radio channel (either A or B)
59
+ @param fill_bits: The number of fill bits requires to pad the data payload to a 6 bit boundary.
60
+ @return: A list of relevant AIS sentences.
61
+ """
62
+ messages = []
63
+ max_len = 60
64
+ frag_cnt = math.ceil(len(payload) / max_len)
65
+ if seq_id is None:
66
+ seq_id = '0' if frag_cnt > 1 else ''
67
+ elif frag_cnt == 1:
68
+ seq_id = ''
69
+
70
+ if len(ais_talker_id) != 5:
71
+ raise ValueError("AIS talker is must have exactly 6 characters. E.g. AIVDO")
72
+
73
+ if len(radio_channel) != 1:
74
+ raise ValueError("Radio channel must be a single character")
75
+
76
+ for frag_num, chunk in enumerate(chunks(payload, max_len), start=1):
77
+ tpl = "!{},{},{},{},{},{},{}*{:02X}"
78
+ fill_bits_frag = fill_bits if frag_num == frag_cnt else 0 # Make sure we set fill bits only for last fragment
79
+ dummy_message = tpl.format(ais_talker_id, frag_cnt, frag_num, seq_id, radio_channel, chunk, fill_bits_frag, 0)
80
+ checksum = compute_checksum(dummy_message)
81
+ msg = tpl.format(ais_talker_id, frag_cnt, frag_num, seq_id, radio_channel, chunk, fill_bits_frag, checksum)
82
+ messages.append(msg)
83
+
84
+ return messages
85
+
86
+ pyais.ais_to_nmea_0183 = HA_ais_to_nmea_0183
87
+
88
+
89
+ def HA_encode_dict(data: DATA_DICT, talker_id: str = "AIVDO", radio_channel: str = "A", seq_id: str = None) -> AIS_SENTENCES:
90
+ """
91
+ Takes a dictionary of data and some NMEA specific kwargs and returns the NMEA 0183 encoded AIS sentence.
92
+
93
+ Notes:
94
+ - the data dict should also contain the AIS message type (1-27) under the `type` key.
95
+ - different messages take different keywords. Refer to the payload classes above to get a glimpse
96
+ on what fields each AIS message can take.
97
+
98
+ @param data: The AIS data as a dictionary.
99
+ @param talker_id: AIS packets have the introducer "AIVDM" or "AIVDO";
100
+ AIVDM packets are reports from other ships and AIVDO packets are reports from your own ship.
101
+ @param radio_channel: The radio channel. Can be either 'A' (default) or 'B'.
102
+ @return: NMEA 0183 encoded AIS sentences.
103
+
104
+ """
105
+ if talker_id not in ("AIVDM", "AIVDO"):
106
+ raise ValueError("talker_id must be any of ['AIVDM', 'AIVDO']")
107
+
108
+ if radio_channel not in ('A', 'B'):
109
+ raise ValueError("radio_channel must be any of ['A', 'B']")
110
+
111
+ ais_type = get_ais_type(data)
112
+ payload = data_to_payload(ais_type, data)
113
+ armored_payload, fill_bits = payload.encode()
114
+ return pyais.ais_to_nmea_0183(armored_payload, talker_id, radio_channel, fill_bits, seq_id=seq_id)
115
+
116
+ pyais.encode_dict = HA_encode_dict
117
+
118
+
119
+ def HA_encode_msg(msg: Payload, talker_id: str = "AIVDO", radio_channel: str = "A", seq_id: str = None) -> AIS_SENTENCES:
120
+ if talker_id not in ("AIVDM", "AIVDO"):
121
+ raise ValueError("talker_id must be any of ['AIVDM', 'AIVDO']")
122
+
123
+ if radio_channel not in ('A', 'B'):
124
+ raise ValueError("radio_channel must be any of ['A', 'B']")
125
+
126
+ armored_payload, fill_bits = msg.encode()
127
+ return pyais.ais_to_nmea_0183(armored_payload, talker_id, radio_channel, fill_bits, seq_id=seq_id)
128
+
129
+ pyais.encode_msg = HA_encode_msg
130
+
131
+
132
+ # All @ at end of string are considered padding.
133
+ # Note: in pyais implementation, decode is stopped at first @.
134
+ def HA_decode_bin_as_ascii6(bit_arr: bitarray) -> str:
135
+ """
136
+ Decode binary data as 6 bit ASCII.
137
+ :param bit_arr: array of bits
138
+ :return: ASCII String
139
+ """
140
+ string: str = ""
141
+ c: bitarray
142
+ for c in chunks(bit_arr, 6): # type:ignore
143
+ n: int = from_bytes(c.tobytes()) >> 2
144
+
145
+ # Last entry may not have 6 bits
146
+ if len(c) != 6:
147
+ n >> (6 - len(c))
148
+
149
+ if n < 0x20:
150
+ n += 0x40
151
+
152
+ string += chr(n)
153
+
154
+ # Remove all @ at end since they correspond to padding
155
+ string = string.rstrip('@')
156
+
157
+ # Remove spaces as some encoders make padding with spaces instead of @
158
+ return string.strip()
159
+
160
+ pyais.util.decode_bin_as_ascii6 = HA_decode_bin_as_ascii6
161
+
162
+
163
+ def HA_int_to_bin(val: typing.Union[int, bool], width: int, signed: bool = True) -> bitarray:
164
+ """
165
+ Convert an integer or boolean value to binary.
166
+ Compared to pyais implementation, the behaviour is changed if the value is too great to fit into
167
+ `width` bits:
168
+ - in pyais, the maximum possible number that still fits is used,
169
+ - in this implementation, an exception is raised.
170
+
171
+ @param val: Any integer or boolean value.
172
+ @param width: The bit width. If less than width bits are required, leading zeros are added.
173
+ @param signed: Set to True/False if the value is signed or not.
174
+ @return: The binary representation of value with exactly width bits. Type is bitarray.
175
+ """
176
+ # Compute the total number of bytes required to hold up to `width` bits.
177
+ n_bytes, mod = divmod(width, 8)
178
+ if mod > 0:
179
+ n_bytes += 1
180
+
181
+ # If the value is too big, return a bitarray of all 1's
182
+ mask = (1 << width) - 1
183
+ if val > mask:
184
+ raise ValueError(f"Value {val} is too big for bit width {width} (max possible value: {mask})")
185
+
186
+ bits = bitarray(endian='big')
187
+ bits.frombytes(val.to_bytes(n_bytes, 'big', signed=signed))
188
+ return bits[8 - mod if mod else 0:]
189
+
190
+ pyais.util.int_to_bin = HA_int_to_bin
191
+ pyais.messages.int_to_bin = HA_int_to_bin
192
+
193
+
194
+ # Add spare field management
195
+
196
+ def bit_field(width: int, d_type: typing.Type[typing.Any],
197
+ from_converter: typing.Optional[typing.Callable[[typing.Any], typing.Any]] = None,
198
+ to_converter: typing.Optional[typing.Callable[[typing.Any], typing.Any]] = None,
199
+ default: typing.Optional[typing.Any] = None,
200
+ signed: bool = False,
201
+ variable_length: bool = False,
202
+ is_spare: bool = False,
203
+ **kwargs: typing.Any) -> typing.Any:
204
+ """Same as pyais bit_field function, but adds a metadata 'is_spare' at True.
205
+ Metadata 'is_spare' is used to know which fields must not be exported when converting message to dict or json.
206
+ """
207
+ return attr.ib(
208
+ metadata={
209
+ 'width': width,
210
+ 'd_type': d_type,
211
+ 'from_converter': from_converter,
212
+ 'to_converter': to_converter,
213
+ 'signed': signed,
214
+ 'default': default,
215
+ 'variable_length': variable_length,
216
+ 'is_spare': is_spare
217
+ },
218
+ **kwargs
219
+ )
220
+
221
+ pyais.messages.bit_field = bit_field
222
+
223
+
224
+ @attr.s(slots=True)
225
+ class HAPayload(Payload):
226
+ """Payload class with spare fields management.
227
+ """
228
+
229
+ def asdict(self, enum_as_int: bool = False, with_spare: bool = False) -> typing.Dict[str, typing.Optional[NMEA_VALUE]]:
230
+ res = super().asdict(enum_as_int)
231
+
232
+ # Remove spare fields
233
+ if not with_spare:
234
+ for field in self.fields():
235
+ if 'is_spare' in field.metadata and field.metadata['is_spare']:
236
+ del res[field.name]
237
+
238
+ return res
239
+
240
+ @classmethod
241
+ def from_bitarray(cls, bit_arr: bitarray) -> "ANY_MESSAGE":
242
+ cur: int = 0
243
+ end: int = 0
244
+ length: int = len(bit_arr)
245
+ kwargs: typing.Dict[str, typing.Any] = {}
246
+
247
+ # Manage field with a variable length
248
+ index_variable_length_field: int = None
249
+ cursor_variable_length_field_beg: int = None
250
+ cursor_variable_length_field_end: int = None
251
+
252
+ # Iterate over the bits until a variable length field or the last bit of the bitarray or all fields are fully decoded
253
+ for field_index, field in enumerate(cls.fields()):
254
+ # Stop if field has a variable length
255
+ if field.metadata['variable_length']:
256
+ index_variable_length_field = field_index
257
+ cursor_variable_length_field_beg = cur
258
+ break
259
+
260
+ if end >= length:
261
+ # All fields that did not fit into the bit array are None
262
+ kwargs[field.name] = None
263
+ continue
264
+
265
+ width = field.metadata['width']
266
+ end = min(length, cur + width)
267
+ bits = bit_arr[cur: end]
268
+
269
+ kwargs[field.name] = cls._bitarray_to_field_type(bits, field)
270
+ cur = end
271
+
272
+ if index_variable_length_field is not None:
273
+ # Iterate over fields in reverse order until variable length field
274
+ end = length
275
+ cur = length
276
+
277
+ last_fields = tuple(cls.fields())[index_variable_length_field+1:]
278
+ for field in reversed(last_fields):
279
+ if end <= cursor_variable_length_field_beg:
280
+ # All fields that did not fit into the bit array are None
281
+ kwargs[field.name] = None
282
+ continue
283
+
284
+ width = field.metadata['width']
285
+ cur = max(cursor_variable_length_field_beg, end - width)
286
+ bits = bit_arr[cur: end]
287
+
288
+ kwargs[field.name] = cls._bitarray_to_field_type(bits, field)
289
+ end = cur
290
+
291
+ # Add variable length field
292
+ cursor_variable_length_field_end = end
293
+ field = cls.fields()[index_variable_length_field]
294
+ bits = bit_arr[cursor_variable_length_field_beg: cursor_variable_length_field_end]
295
+ kwargs[field.name] = cls._bitarray_to_field_type(bits, field)
296
+
297
+ return cls(**kwargs) # type:ignore
298
+
299
+ @classmethod
300
+ def _bitarray_to_field_type(cls, bits, field) -> typing.Any:
301
+ val: typing.Any
302
+ d_type = field.metadata['d_type']
303
+ converter = field.metadata['to_converter']
304
+
305
+ # Get the correct data type and decoding function
306
+ if d_type == int or d_type == bool or d_type == float:
307
+ shift = (8 - (len(bits) % 8)) % 8
308
+ if field.metadata['signed']:
309
+ val = from_bytes_signed(bits) >> shift
310
+ else:
311
+ val = from_bytes(bits) >> shift
312
+
313
+ if d_type == float:
314
+ val = float(val)
315
+ elif d_type == bool:
316
+ val = bool(val)
317
+
318
+ elif d_type == str:
319
+ val = HA_decode_bin_as_ascii6(bits)
320
+ elif d_type == bytes:
321
+ val = bits2bytes(bits)
322
+ else:
323
+ raise InvalidDataTypeException(d_type)
324
+
325
+ val = converter(val) if converter is not None else val
326
+
327
+ return val
328
+
329
+ def to_bitarray(self) -> bitarray:
330
+ """
331
+ Convert all attributes of a given Payload/Message to binary.
332
+ """
333
+ out = bitarray()
334
+ for field in self.fields():
335
+ width = field.metadata['width']
336
+ d_type = field.metadata['d_type']
337
+ converter = field.metadata['from_converter']
338
+ signed = field.metadata['signed']
339
+ variable_length = field.metadata['variable_length']
340
+
341
+ val = getattr(self, field.name)
342
+ if val is None:
343
+ continue
344
+
345
+ val = converter(val) if converter is not None else val
346
+
347
+ try:
348
+ if d_type in (bool, int):
349
+ bits = HA_int_to_bin(val, width, signed=signed)
350
+ elif d_type == float:
351
+ val = int(val)
352
+ bits = HA_int_to_bin(val, width, signed=signed)
353
+ elif d_type == str:
354
+ trailing_spaces = not variable_length
355
+ bits = str_to_bin(val, width, trailing_spaces=trailing_spaces)
356
+ elif d_type == bytes:
357
+ bits = bytes2bits(val, default=bitarray('0' * width))
358
+ else:
359
+ raise InvalidDataTypeException(d_type)
360
+ except ValueError as exc:
361
+ raise ValueError(f"Invalid value for field '{field.name}': {exc}") from None
362
+
363
+ bits = bits[:width]
364
+ out += bits
365
+
366
+ return out
367
+
368
+
369
+ # Fix message types:
370
+ # - almost all types with new spare management
371
+ # - type 21: exclude full_name property from asdict result
372
+ # - type 26: fix create and from_bitarray methods
373
+
374
+ @attr.s(slots=True)
375
+ class HAMessageType1(HAPayload, CommunicationStateMixin):
376
+ """
377
+ AIS Vessel position report using SOTDMA (Self-Organizing Time Division Multiple Access)
378
+ """
379
+ msg_type = bit_field(6, int, default=1, signed=False)
380
+ repeat = bit_field(2, int, default=0, signed=False)
381
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
382
+ status = bit_field(4, int, default=0, converter=NavigationStatus.from_value, signed=False)
383
+ turn = bit_field(8, float, default=TurnRate.NO_TI_DEFAULT, signed=True, to_converter=to_turn, from_converter=from_turn)
384
+ speed = bit_field(10, float, from_converter=from_speed, to_converter=to_speed, default=0, signed=False)
385
+ accuracy = bit_field(1, bool, default=0, signed=False)
386
+ lon = bit_field(28, float, from_converter=from_lat_lon, to_converter=to_lat_lon, default=0, signed=True)
387
+ lat = bit_field(27, float, from_converter=from_lat_lon, to_converter=to_lat_lon, default=0, signed=True)
388
+ course = bit_field(12, float, from_converter=from_10th, to_converter=to_10th, default=0, signed=False)
389
+ heading = bit_field(9, int, default=0, signed=False)
390
+ second = bit_field(6, int, default=0, signed=False)
391
+ maneuver = bit_field(2, int, default=0, from_converter=ManeuverIndicator.from_value,
392
+ to_converter=ManeuverIndicator.from_value, signed=False)
393
+ spare_1 = bit_field(3, bytes, default=b'', is_spare=True)
394
+ raim = bit_field(1, bool, default=0)
395
+ radio = bit_field(19, int, default=0, signed=False)
396
+
397
+ pyais.messages.MessageType1 = HAMessageType1
398
+ pyais.messages.MSG_CLASS[1] = pyais.messages.MessageType1
399
+
400
+
401
+ class HAMessageType2(HAMessageType1):
402
+ """
403
+ AIS Vessel position report using SOTDMA (Self-Organizing Time Division Multiple Access)
404
+ """
405
+ msg_type = bit_field(6, int, default=2)
406
+
407
+ pyais.messages.MessageType2 = HAMessageType2
408
+ pyais.messages.MSG_CLASS[2] = pyais.messages.MessageType2
409
+
410
+
411
+ class HAMessageType3(HAMessageType1):
412
+ """
413
+ AIS Vessel position report using ITDMA (Incremental Time Division Multiple Access)
414
+ """
415
+ msg_type = bit_field(6, int, default=3)
416
+
417
+ pyais.messages.MessageType3 = HAMessageType3
418
+ pyais.messages.MSG_CLASS[3] = pyais.messages.MessageType3
419
+
420
+
421
+ @attr.s(slots=True)
422
+ class HAMessageType4(HAPayload, CommunicationStateMixin):
423
+ """
424
+ AIS Vessel position report using SOTDMA (Self-Organizing Time Division Multiple Access)
425
+ """
426
+ msg_type = bit_field(6, int, default=4, signed=False)
427
+ repeat = bit_field(2, int, default=0, signed=False)
428
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
429
+ year = bit_field(14, int, default=1970, signed=False)
430
+ month = bit_field(4, int, default=1, signed=False)
431
+ day = bit_field(5, int, default=1, signed=False)
432
+ hour = bit_field(5, int, default=0, signed=False)
433
+ minute = bit_field(6, int, default=0, signed=False)
434
+ second = bit_field(6, int, default=0, signed=False)
435
+ accuracy = bit_field(1, bool, default=0, signed=False)
436
+ lon = bit_field(28, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
437
+ lat = bit_field(27, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
438
+ epfd = bit_field(4, int, default=0, from_converter=EpfdType.from_value, to_converter=EpfdType.from_value,
439
+ signed=False)
440
+ spare_1 = bit_field(10, bytes, default=b'', is_spare=True)
441
+ raim = bit_field(1, bool, default=0)
442
+ radio = bit_field(19, int, default=0, signed=False)
443
+
444
+ pyais.messages.MessageType4 = HAMessageType4
445
+ pyais.messages.MSG_CLASS[4] = pyais.messages.MessageType4
446
+
447
+
448
+ @attr.s(slots=True)
449
+ class HAMessageType5(HAPayload):
450
+ """
451
+ Static and Voyage Related Data
452
+ """
453
+ msg_type = bit_field(6, int, default=5, signed=False)
454
+ repeat = bit_field(2, int, default=0, signed=False)
455
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
456
+ ais_version = bit_field(2, int, default=0, signed=False)
457
+ imo = bit_field(30, int, default=0, signed=False)
458
+ callsign = bit_field(42, str, default='')
459
+ shipname = bit_field(120, str, default='')
460
+ ship_type = bit_field(8, int, default=0, from_converter=ShipType.from_value, to_converter=ShipType.from_value)
461
+ to_bow = bit_field(9, int, default=0, signed=False)
462
+ to_stern = bit_field(9, int, default=0, signed=False)
463
+ to_port = bit_field(6, int, default=0, signed=False)
464
+ to_starboard = bit_field(6, int, default=0, signed=False)
465
+ epfd = bit_field(4, int, default=0, from_converter=EpfdType.from_value, to_converter=EpfdType.from_value)
466
+ month = bit_field(4, int, default=0, signed=False)
467
+ day = bit_field(5, int, default=0, signed=False)
468
+ hour = bit_field(5, int, default=0, signed=False)
469
+ minute = bit_field(6, int, default=0, signed=False)
470
+ draught = bit_field(8, float, from_converter=from_10th, to_converter=to_10th, default=0, signed=False)
471
+ destination = bit_field(120, str, default='')
472
+ dte = bit_field(1, bool, default=0, signed=False)
473
+ spare_1 = bit_field(1, bytes, default=b'', is_spare=True)
474
+
475
+ pyais.messages.MessageType5 = HAMessageType5
476
+ pyais.messages.MSG_CLASS[5] = pyais.messages.MessageType5
477
+
478
+
479
+ @attr.s(slots=True)
480
+ class HAMessageType6(HAPayload):
481
+ """
482
+ Binary Addresses Message
483
+ """
484
+ msg_type = bit_field(6, int, default=6)
485
+ repeat = bit_field(2, int, default=0, signed=False)
486
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
487
+ seqno = bit_field(2, int, default=0, signed=False)
488
+ dest_mmsi = bit_field(30, int, from_converter=from_mmsi)
489
+ retransmit = bit_field(1, bool, default=False, signed=False)
490
+ spare_1 = bit_field(1, bytes, default=b'', is_spare=True)
491
+ dac = bit_field(10, int, default=0, signed=False)
492
+ fid = bit_field(6, int, default=0, signed=False)
493
+ data = bit_field(920, bytes, default=b'', variable_length=True)
494
+
495
+ pyais.messages.MessageType6 = HAMessageType6
496
+ pyais.messages.MSG_CLASS[6] = pyais.messages.MessageType6
497
+
498
+
499
+ @attr.s(slots=True)
500
+ class HAMessageType7(HAPayload):
501
+ """
502
+ Binary Acknowledge
503
+ """
504
+ msg_type = bit_field(6, int, default=7, signed=False)
505
+ repeat = bit_field(2, int, default=0, signed=False)
506
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
507
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
508
+ mmsi1 = bit_field(30, int, default=0, from_converter=from_mmsi)
509
+ mmsiseq1 = bit_field(2, int, default=0, signed=False)
510
+ mmsi2 = bit_field(30, int, default=0, from_converter=from_mmsi)
511
+ mmsiseq2 = bit_field(2, int, default=0, signed=False)
512
+ mmsi3 = bit_field(30, int, default=0, from_converter=from_mmsi)
513
+ mmsiseq3 = bit_field(2, int, default=0, signed=False)
514
+ mmsi4 = bit_field(30, int, default=0, from_converter=from_mmsi)
515
+ mmsiseq4 = bit_field(2, int, default=0, signed=False)
516
+
517
+ pyais.messages.MessageType7 = HAMessageType7
518
+ pyais.messages.MSG_CLASS[7] = pyais.messages.MessageType7
519
+
520
+
521
+ @attr.s(slots=True)
522
+ class HAMessageType8(HAPayload):
523
+ """
524
+ Binary Acknowledge
525
+ """
526
+ msg_type = bit_field(6, int, default=8, signed=False)
527
+ repeat = bit_field(2, int, default=0, signed=False)
528
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
529
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
530
+ dac = bit_field(10, int, default=0, signed=False)
531
+ fid = bit_field(6, int, default=0, signed=False)
532
+ data = bit_field(952, bytes, default=b'', variable_length=True)
533
+
534
+ pyais.messages.MessageType8 = HAMessageType8
535
+ pyais.messages.MSG_CLASS[8] = pyais.messages.MessageType8
536
+
537
+
538
+ @attr.s(slots=True)
539
+ class HAMessageType9(HAPayload, CommunicationStateMixin):
540
+ """
541
+ Standard SAR Aircraft Position Report
542
+ """
543
+ msg_type = bit_field(6, int, default=9, signed=False)
544
+ repeat = bit_field(2, int, default=0, signed=False)
545
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
546
+
547
+ alt = bit_field(12, int, default=0, signed=False)
548
+ # speed over ground is in knots, not deciknots
549
+ speed = bit_field(10, float, default=0, signed=False)
550
+ accuracy = bit_field(1, bool, default=0, signed=False)
551
+ lon = bit_field(28, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
552
+ lat = bit_field(27, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
553
+ course = bit_field(12, float, from_converter=from_10th, to_converter=to_10th, default=0, signed=False)
554
+ second = bit_field(6, int, default=0, signed=False)
555
+
556
+ reserved_1 = bit_field(8, int, default=0)
557
+ dte = bit_field(1, bool, default=0)
558
+ spare_1 = bit_field(3, bytes, default=b'', is_spare=True)
559
+ assigned = bit_field(1, bool, default=0)
560
+ raim = bit_field(1, bool, default=0)
561
+ radio = bit_field(20, int, default=0, signed=False)
562
+
563
+ pyais.messages.MessageType9 = HAMessageType9
564
+ pyais.messages.MSG_CLASS[9] = pyais.messages.MessageType9
565
+
566
+
567
+ @attr.s(slots=True)
568
+ class HAMessageType10(HAPayload):
569
+ """
570
+ UTC/Date Inquiry
571
+ """
572
+ msg_type = bit_field(6, int, default=10, signed=False)
573
+ repeat = bit_field(2, int, default=0, signed=False)
574
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
575
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
576
+ dest_mmsi = bit_field(30, int, from_converter=from_mmsi)
577
+ spare_2 = bit_field(2, bytes, default=b'', is_spare=True)
578
+
579
+ pyais.messages.MessageType10 = HAMessageType10
580
+ pyais.messages.MSG_CLASS[10] = pyais.messages.MessageType10
581
+
582
+
583
+ class HAMessageType11(HAMessageType4):
584
+ """
585
+ UTC/Date Response
586
+ """
587
+ msg_type = bit_field(6, int, default=11, signed=False)
588
+
589
+ pyais.messages.MessageType11 = HAMessageType11
590
+ pyais.messages.MSG_CLASS[11] = pyais.messages.MessageType11
591
+
592
+
593
+ @attr.s(slots=True)
594
+ class HAMessageType12(HAPayload):
595
+ """
596
+ Addressed Safety-Related Message
597
+ """
598
+ msg_type = bit_field(6, int, default=12, signed=False)
599
+ repeat = bit_field(2, int, default=0, signed=False)
600
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
601
+ seqno = bit_field(2, int, default=0, signed=False)
602
+ dest_mmsi = bit_field(30, int, from_converter=from_mmsi)
603
+ retransmit = bit_field(1, bool, default=False, signed=False)
604
+ spare_1 = bit_field(1, bytes, default=b'', is_spare=True)
605
+ text = bit_field(936, str, default='', variable_length=True)
606
+
607
+ pyais.messages.MessageType12 = HAMessageType12
608
+ pyais.messages.MSG_CLASS[12] = pyais.messages.MessageType12
609
+
610
+
611
+ class HAMessageType13(HAMessageType7):
612
+ """
613
+ Identical to type 7
614
+ """
615
+ msg_type = bit_field(6, int, default=13, signed=False)
616
+
617
+ pyais.messages.MessageType13 = HAMessageType13
618
+ pyais.messages.MSG_CLASS[13] = pyais.messages.MessageType13
619
+
620
+
621
+ @attr.s(slots=True)
622
+ class HAMessageType14(HAPayload):
623
+ """
624
+ Safety-Related Broadcast Message
625
+ """
626
+ msg_type = bit_field(6, int, default=14, signed=False)
627
+ repeat = bit_field(2, int, default=0, signed=False)
628
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
629
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
630
+ text = bit_field(968, str, default='', variable_length=True)
631
+
632
+ pyais.messages.MessageType14 = HAMessageType14
633
+ pyais.messages.MSG_CLASS[14] = pyais.messages.MessageType14
634
+
635
+
636
+ @attr.s(slots=True)
637
+ class HAMessageType15(HAPayload):
638
+ """
639
+ Interrogation
640
+ """
641
+ msg_type = bit_field(6, int, default=15, signed=False)
642
+ repeat = bit_field(2, int, default=0, signed=False)
643
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
644
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
645
+ mmsi1 = bit_field(30, int, default=0, from_converter=from_mmsi)
646
+ type1_1 = bit_field(6, int, default=0, signed=False)
647
+ offset1_1 = bit_field(12, int, default=0, signed=False)
648
+ spare_2 = bit_field(2, bytes, default=b'', is_spare=True)
649
+ type1_2 = bit_field(6, int, default=0, signed=False)
650
+ offset1_2 = bit_field(12, int, default=0, signed=False)
651
+ spare_3 = bit_field(2, bytes, default=b'', is_spare=True)
652
+ mmsi2 = bit_field(30, int, default=0, from_converter=from_mmsi)
653
+ type2_1 = bit_field(6, int, default=0, signed=False)
654
+ offset2_1 = bit_field(12, int, default=0, signed=False)
655
+ spare_4 = bit_field(2, bytes, default=b'', is_spare=True)
656
+
657
+ pyais.messages.MessageType15 = HAMessageType15
658
+ pyais.messages.MSG_CLASS[15] = pyais.messages.MessageType15
659
+
660
+
661
+ @attr.s(slots=True)
662
+ class HAMessageType16DestinationA(HAPayload):
663
+ """
664
+ Assignment Mode Command
665
+ """
666
+ msg_type = bit_field(6, int, default=16, signed=False)
667
+ repeat = bit_field(2, int, default=0, signed=False)
668
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
669
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
670
+
671
+ mmsi1 = bit_field(30, int, default=0, from_converter=from_mmsi)
672
+ offset1 = bit_field(12, int, default=0, signed=False)
673
+ increment1 = bit_field(10, int, default=0, signed=False)
674
+ spare_2 = bit_field(4, bytes, default=b'', is_spare=True)
675
+
676
+ pyais.messages.MessageType16DestinationA = HAMessageType16DestinationA
677
+
678
+
679
+ @attr.s(slots=True)
680
+ class HAMessageType16DestinationAB(HAPayload):
681
+ """
682
+ Assignment Mode Command
683
+ """
684
+ msg_type = bit_field(6, int, default=16, signed=False)
685
+ repeat = bit_field(2, int, default=0, signed=False)
686
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
687
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
688
+
689
+ mmsi1 = bit_field(30, int, default=0, from_converter=from_mmsi)
690
+ offset1 = bit_field(12, int, default=0, signed=False)
691
+ increment1 = bit_field(10, int, default=0, signed=False)
692
+
693
+ mmsi2 = bit_field(30, int, default=0, from_converter=from_mmsi)
694
+ offset2 = bit_field(12, int, default=0, signed=False)
695
+ increment2 = bit_field(10, int, default=0, signed=False)
696
+
697
+ pyais.messages.MessageType16DestinationAB = HAMessageType16DestinationAB
698
+
699
+
700
+ @attr.s(slots=True)
701
+ class HAMessageType16(HAPayload):
702
+ @classmethod
703
+ def create(cls, **kwargs: typing.Union[str, float, int, bool, bytes]) -> "ANY_MESSAGE":
704
+ if 'mmsi2' in kwargs:
705
+ return HAMessageType16DestinationAB.create(**kwargs)
706
+ else:
707
+ return HAMessageType16DestinationA.create(**kwargs)
708
+
709
+ @classmethod
710
+ def from_bitarray(cls, bit_arr: bitarray) -> "ANY_MESSAGE":
711
+ if len(bit_arr) > 96:
712
+ return HAMessageType16DestinationAB.from_bitarray(bit_arr)
713
+ else:
714
+ return HAMessageType16DestinationA.from_bitarray(bit_arr)
715
+
716
+ pyais.messages.MessageType16 = HAMessageType16
717
+ pyais.messages.MSG_CLASS[16] = pyais.messages.MessageType16
718
+
719
+
720
+ @attr.s(slots=True)
721
+ class HAMessageType17(HAPayload):
722
+ """
723
+ DGNSS Broadcast Binary Message
724
+ """
725
+ msg_type = bit_field(6, int, default=17, signed=False)
726
+ repeat = bit_field(2, int, default=0, signed=False)
727
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
728
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
729
+ # Note that latitude and longitude are in units of a tenth of a minute
730
+ lon = bit_field(18, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
731
+ lat = bit_field(17, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
732
+ spare_2 = bit_field(5, bytes, default=b'', is_spare=True)
733
+ data = bit_field(736, bytes, default=b'', variable_length=True)
734
+
735
+ pyais.messages.MessageType17 = HAMessageType17
736
+ pyais.messages.MSG_CLASS[17] = pyais.messages.MessageType17
737
+
738
+
739
+ @attr.s(slots=True)
740
+ class HAMessageType19(HAPayload):
741
+ """
742
+ Extended Class B CS Position Report
743
+ """
744
+ msg_type = bit_field(6, int, default=19, signed=False)
745
+ repeat = bit_field(2, int, default=0, signed=False)
746
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
747
+ reserved_1 = bit_field(8, int, default=0)
748
+
749
+ speed = bit_field(10, float, from_converter=from_speed, to_converter=to_speed, default=0, signed=False)
750
+ accuracy = bit_field(1, bool, default=0, signed=False)
751
+ lon = bit_field(28, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
752
+ lat = bit_field(27, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
753
+ course = bit_field(12, float, from_converter=from_10th, to_converter=to_10th, default=0, signed=False)
754
+ heading = bit_field(9, int, default=0, signed=False)
755
+ second = bit_field(6, int, default=0, signed=False)
756
+ reserved_2 = bit_field(4, int, default=0, signed=False)
757
+ shipname = bit_field(120, str, default='')
758
+ ship_type = bit_field(8, int, default=0, from_converter=ShipType.from_value, to_converter=ShipType.from_value,
759
+ signed=False)
760
+ to_bow = bit_field(9, int, default=0, signed=False)
761
+ to_stern = bit_field(9, int, default=0, signed=False)
762
+ to_port = bit_field(6, int, default=0, signed=False)
763
+ to_starboard = bit_field(6, int, default=0, signed=False)
764
+ epfd = bit_field(4, int, default=0, from_converter=EpfdType.from_value, to_converter=EpfdType.from_value)
765
+ raim = bit_field(1, bool, default=0)
766
+ dte = bit_field(1, bool, default=0)
767
+ assigned = bit_field(1, bool, default=0, signed=False)
768
+ spare_1 = bit_field(4, bytes, default=b'', is_spare=True)
769
+
770
+ pyais.messages.MessageType19 = HAMessageType19
771
+ pyais.messages.MSG_CLASS[19] = pyais.messages.MessageType19
772
+
773
+
774
+ @attr.s(slots=True)
775
+ class HAMessageType20ReservationBlock1(HAPayload):
776
+ """
777
+ Data Link Management Message
778
+ """
779
+ msg_type = bit_field(6, int, default=20, signed=False)
780
+ repeat = bit_field(2, int, default=0, signed=False)
781
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
782
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
783
+
784
+ offset1 = bit_field(12, int, default=0, signed=False)
785
+ number1 = bit_field(4, int, default=0, signed=False)
786
+ timeout1 = bit_field(3, int, default=0, signed=False)
787
+ increment1 = bit_field(11, int, default=0, signed=False)
788
+ spare_2 = bit_field(2, bytes, default=b'', is_spare=True)
789
+
790
+ pyais.messages.MessageType20ReservationBlock1 = HAMessageType20ReservationBlock1
791
+
792
+
793
+ @attr.s(slots=True)
794
+ class HAMessageType20ReservationBlock12(HAPayload):
795
+ """
796
+ Data Link Management Message
797
+ """
798
+ msg_type = bit_field(6, int, default=20, signed=False)
799
+ repeat = bit_field(2, int, default=0, signed=False)
800
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
801
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
802
+
803
+ offset1 = bit_field(12, int, default=0, signed=False)
804
+ number1 = bit_field(4, int, default=0, signed=False)
805
+ timeout1 = bit_field(3, int, default=0, signed=False)
806
+ increment1 = bit_field(11, int, default=0, signed=False)
807
+
808
+ offset2 = bit_field(12, int, default=0, signed=False)
809
+ number2 = bit_field(4, int, default=0, signed=False)
810
+ timeout2 = bit_field(3, int, default=0, signed=False)
811
+ increment2 = bit_field(11, int, default=0, signed=False)
812
+ spare_2 = bit_field(4, bytes, default=b'', is_spare=True)
813
+
814
+ pyais.messages.MessageType20ReservationBlock12 = HAMessageType20ReservationBlock12
815
+
816
+
817
+ @attr.s(slots=True)
818
+ class HAMessageType20ReservationBlock123(HAPayload):
819
+ """
820
+ Data Link Management Message
821
+ """
822
+ msg_type = bit_field(6, int, default=20, signed=False)
823
+ repeat = bit_field(2, int, default=0, signed=False)
824
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
825
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
826
+
827
+ offset1 = bit_field(12, int, default=0, signed=False)
828
+ number1 = bit_field(4, int, default=0, signed=False)
829
+ timeout1 = bit_field(3, int, default=0, signed=False)
830
+ increment1 = bit_field(11, int, default=0, signed=False)
831
+
832
+ offset2 = bit_field(12, int, default=0, signed=False)
833
+ number2 = bit_field(4, int, default=0, signed=False)
834
+ timeout2 = bit_field(3, int, default=0, signed=False)
835
+ increment2 = bit_field(11, int, default=0, signed=False)
836
+
837
+ offset3 = bit_field(12, int, default=0, signed=False)
838
+ number3 = bit_field(4, int, default=0, signed=False)
839
+ timeout3 = bit_field(3, int, default=0, signed=False)
840
+ increment3 = bit_field(11, int, default=0, signed=False)
841
+ spare_2 = bit_field(6, bytes, default=b'', is_spare=True)
842
+
843
+ pyais.messages.MessageType20ReservationBlock123 = HAMessageType20ReservationBlock123
844
+
845
+
846
+ @attr.s(slots=True)
847
+ class HAMessageType20ReservationBlock1234(HAPayload):
848
+ """
849
+ Data Link Management Message
850
+ """
851
+ msg_type = bit_field(6, int, default=20, signed=False)
852
+ repeat = bit_field(2, int, default=0, signed=False)
853
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
854
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
855
+
856
+ offset1 = bit_field(12, int, default=0, signed=False)
857
+ number1 = bit_field(4, int, default=0, signed=False)
858
+ timeout1 = bit_field(3, int, default=0, signed=False)
859
+ increment1 = bit_field(11, int, default=0, signed=False)
860
+
861
+ offset2 = bit_field(12, int, default=0, signed=False)
862
+ number2 = bit_field(4, int, default=0, signed=False)
863
+ timeout2 = bit_field(3, int, default=0, signed=False)
864
+ increment2 = bit_field(11, int, default=0, signed=False)
865
+
866
+ offset3 = bit_field(12, int, default=0, signed=False)
867
+ number3 = bit_field(4, int, default=0, signed=False)
868
+ timeout3 = bit_field(3, int, default=0, signed=False)
869
+ increment3 = bit_field(11, int, default=0, signed=False)
870
+
871
+ offset4 = bit_field(12, int, default=0, signed=False)
872
+ number4 = bit_field(4, int, default=0, signed=False)
873
+ timeout4 = bit_field(3, int, default=0, signed=False)
874
+ increment4 = bit_field(11, int, default=0, signed=False)
875
+
876
+ pyais.messages.MessageType20ReservationBlock1234 = HAMessageType20ReservationBlock1234
877
+
878
+
879
+ @attr.s(slots=True)
880
+ class HAMessageType20(HAPayload):
881
+ @classmethod
882
+ def create(cls, **kwargs: typing.Union[str, float, int, bool, bytes]) -> "ANY_MESSAGE":
883
+ if 'offset4' in kwargs and int(kwargs['offset4']) > 0:
884
+ return HAMessageType20ReservationBlock1234.create(**kwargs)
885
+ elif 'offset3' in kwargs and int(kwargs['offset3']) > 0:
886
+ return HAMessageType20ReservationBlock123.create(**kwargs)
887
+ elif 'offset2' in kwargs and int(kwargs['offset2']) > 0:
888
+ return HAMessageType20ReservationBlock12.create(**kwargs)
889
+ else:
890
+ return HAMessageType20ReservationBlock1.create(**kwargs)
891
+
892
+ @classmethod
893
+ def from_bitarray(cls, bit_arr: bitarray) -> "ANY_MESSAGE":
894
+ if len(bit_arr) > 136:
895
+ return HAMessageType20ReservationBlock1234.from_bitarray(bit_arr)
896
+ elif len(bit_arr) > 104:
897
+ return HAMessageType20ReservationBlock123.from_bitarray(bit_arr)
898
+ elif len(bit_arr) > 72:
899
+ return HAMessageType20ReservationBlock12.from_bitarray(bit_arr)
900
+ else:
901
+ return HAMessageType20ReservationBlock1.from_bitarray(bit_arr)
902
+
903
+ pyais.messages.MessageType20 = HAMessageType20
904
+ pyais.messages.MSG_CLASS[20] = pyais.messages.MessageType20
905
+
906
+
907
+ @attr.s(slots=True)
908
+ class HAMessageType21(HAPayload):
909
+ """
910
+ Aid-to-Navigation Report
911
+ """
912
+ msg_type = bit_field(6, int, default=21, signed=False)
913
+ repeat = bit_field(2, int, default=0, signed=False)
914
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
915
+
916
+ aid_type = bit_field(5, int, default=0, from_converter=NavAid.from_value, to_converter=NavAid.from_value,
917
+ signed=False)
918
+ name = bit_field(120, str, default='')
919
+
920
+ accuracy = bit_field(1, bool, default=0, signed=False)
921
+ lon = bit_field(28, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
922
+ lat = bit_field(27, float, from_converter=from_lat_lon, to_converter=to_lat_lon, signed=True, default=0)
923
+ to_bow = bit_field(9, int, default=0, signed=False)
924
+ to_stern = bit_field(9, int, default=0, signed=False)
925
+ to_port = bit_field(6, int, default=0, signed=False)
926
+ to_starboard = bit_field(6, int, default=0, signed=False)
927
+
928
+ epfd = bit_field(4, int, default=0, from_converter=EpfdType.from_value, to_converter=EpfdType.from_value)
929
+ second = bit_field(6, int, default=0, signed=False)
930
+ off_position = bit_field(1, bool, default=0)
931
+ reserved_1 = bit_field(8, int, default=0, signed=False)
932
+ raim = bit_field(1, bool, default=0)
933
+ virtual_aid = bit_field(1, bool, default=0)
934
+ assigned = bit_field(1, bool, default=0)
935
+ spare_1 = bit_field(1, bytes, default=b'', is_spare=True)
936
+ name_ext = bit_field(88, str, default='')
937
+
938
+ @functools.cached_property
939
+ def full_name(self) -> str:
940
+ """The name field is up to 20 characters of 6-bit ASCII. If this field
941
+ is full (has no trailing @ characters) the decoder should interpret
942
+ the Name Extension field later in the message (no more than 14 6-bit
943
+ characters) and concatenate it to this one to obtain the full name."""
944
+ if self.name:
945
+ if self.name_ext:
946
+ return f"{self.name}{self.name_ext}"
947
+ return str(self.name)
948
+ return ""
949
+
950
+ # TODO: replace following override by a generic implementation in Payload.asdict that exports only fields
951
+ def asdict(self, enum_as_int: bool = False) -> typing.Dict[str, typing.Optional[NMEA_VALUE]]:
952
+ res = super().asdict(enum_as_int)
953
+
954
+ # Remove key 'full_name' if present
955
+ if 'full_name' in res:
956
+ del res['full_name']
957
+
958
+ return res
959
+
960
+ pyais.messages.MessageType21 = HAMessageType21
961
+ pyais.messages.MSG_CLASS[21] = pyais.messages.MessageType21
962
+
963
+
964
+ @attr.s(slots=True)
965
+ class HAMessageType22Addressed(HAPayload):
966
+ """
967
+ Channel Management
968
+ """
969
+ msg_type = bit_field(6, int, default=22, signed=False)
970
+ repeat = bit_field(2, int, default=0, signed=False)
971
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
972
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
973
+
974
+ channel_a = bit_field(12, int, default=0, signed=False)
975
+ channel_b = bit_field(12, int, default=0, signed=False)
976
+ txrx = bit_field(4, int, default=0, signed=False)
977
+ power = bit_field(1, bool, default=0) # 69 bits
978
+
979
+ # If it is addressed (addressed field is 1),
980
+ # the same span of data is interpreted as two 30-bit MMSIs
981
+ # beginning at bit offsets 69 and 104 respectively.
982
+ dest1 = bit_field(30, int, default=0, from_converter=from_mmsi)
983
+ empty_1 = bit_field(5, int, default=0)
984
+ dest2 = bit_field(30, int, default=0, from_converter=from_mmsi)
985
+ empty_2 = bit_field(5, int, default=0)
986
+
987
+ addressed = bit_field(1, bool, default=0)
988
+ band_a = bit_field(1, bool, default=0)
989
+ band_b = bit_field(1, bool, default=0)
990
+ zonesize = bit_field(3, int, default=0)
991
+ spare_2 = bit_field(23, bytes, default=b'', is_spare=True)
992
+
993
+ pyais.messages.MessageType22Addressed = HAMessageType22Addressed
994
+
995
+
996
+ @attr.s(slots=True)
997
+ class HAMessageType22Broadcast(HAPayload):
998
+ """
999
+ Channel Management
1000
+ """
1001
+ msg_type = bit_field(6, int, default=22, signed=False)
1002
+ repeat = bit_field(2, int, default=0, signed=False)
1003
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1004
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
1005
+
1006
+ channel_a = bit_field(12, int, default=0, signed=False)
1007
+ channel_b = bit_field(12, int, default=0, signed=False)
1008
+ txrx = bit_field(4, int, default=0, signed=False)
1009
+ power = bit_field(1, bool, default=0)
1010
+
1011
+ # If the message is broadcast (addressed field is 0),
1012
+ # the ne_lon, ne_lat, sw_lon, and sw_lat fields are the
1013
+ # corners of a rectangular jurisdiction area over which control parameter
1014
+ # ne_lon, ne_lat, sw_lon, and sw_lat fields are in 0.1 minutes
1015
+ ne_lon = bit_field(18, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1016
+ ne_lat = bit_field(17, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1017
+ sw_lon = bit_field(18, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1018
+ sw_lat = bit_field(17, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1019
+
1020
+ addressed = bit_field(1, bool, default=0)
1021
+ band_a = bit_field(1, bool, default=0)
1022
+ band_b = bit_field(1, bool, default=0)
1023
+ zonesize = bit_field(3, int, default=0, signed=False)
1024
+ spare_2 = bit_field(23, bytes, default=b'', is_spare=True)
1025
+
1026
+ pyais.messages.MessageType22Broadcast = HAMessageType22Broadcast
1027
+
1028
+
1029
+ @attr.s(slots=True)
1030
+ class HAMessageType23(HAPayload):
1031
+ """
1032
+ Group Assignment Command
1033
+ """
1034
+ msg_type = bit_field(6, int, default=23, signed=False)
1035
+ repeat = bit_field(2, int, default=0, signed=False)
1036
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1037
+ spare_1 = bit_field(2, bytes, default=b'', is_spare=True)
1038
+
1039
+ ne_lon = bit_field(18, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1040
+ ne_lat = bit_field(17, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1041
+ sw_lon = bit_field(18, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1042
+ sw_lat = bit_field(17, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1043
+
1044
+ station_type = bit_field(4, int, default=0, from_converter=StationType.from_value,
1045
+ to_converter=StationType.from_value)
1046
+ ship_type = bit_field(8, int, default=0, from_converter=ShipType.from_value, to_converter=ShipType.from_value)
1047
+ spare_2 = bit_field(22, bytes, default=b'', is_spare=True)
1048
+
1049
+ txrx = bit_field(2, int, default=0, from_converter=TransmitMode.from_value, to_converter=TransmitMode.from_value,
1050
+ signed=False)
1051
+ interval = bit_field(4, int, default=0, from_converter=StationIntervals.from_value,
1052
+ to_converter=StationIntervals.from_value)
1053
+ quiet = bit_field(4, int, default=0, signed=False)
1054
+ spare_3 = bit_field(6, bytes, default=b'', is_spare=True)
1055
+
1056
+ pyais.messages.MessageType23 = HAMessageType23
1057
+ pyais.messages.MSG_CLASS[23] = pyais.messages.MessageType23
1058
+
1059
+
1060
+ @attr.s(slots=True)
1061
+ class HAMessageType24PartA(HAPayload):
1062
+ msg_type = bit_field(6, int, default=24, signed=False)
1063
+ repeat = bit_field(2, int, default=0, signed=False)
1064
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1065
+
1066
+ # partno = bit_field(2, int, default=0, signed=False)
1067
+ reserved = bit_field(1, int, default=0, signed=False)
1068
+ partno = bit_field(1, int, default=0, signed=False)
1069
+ shipname = bit_field(120, str, default='')
1070
+ spare_1 = bit_field(8, bytes, default=b'', is_spare=True)
1071
+
1072
+ pyais.messages.MessageType24PartA = HAMessageType24PartA
1073
+
1074
+
1075
+ @attr.s(slots=True)
1076
+ class HAMessageType24PartB(HAPayload):
1077
+ msg_type = bit_field(6, int, default=24, signed=False)
1078
+ repeat = bit_field(2, int, default=0, signed=False)
1079
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1080
+
1081
+ partno = bit_field(2, int, default=0, signed=False)
1082
+ ship_type = bit_field(8, int, default=0, signed=False)
1083
+ vendorid = bit_field(18, str, default='', signed=False)
1084
+ model = bit_field(4, int, default=0, signed=False)
1085
+ serial = bit_field(20, int, default=0, signed=False)
1086
+ callsign = bit_field(42, str, default='')
1087
+
1088
+ to_bow = bit_field(9, int, default=0, signed=False)
1089
+ to_stern = bit_field(9, int, default=0, signed=False)
1090
+ to_port = bit_field(6, int, default=0, signed=False)
1091
+ to_starboard = bit_field(6, int, default=0, signed=False)
1092
+
1093
+ spare_1 = bit_field(6, bytes, default=b'', is_spare=True)
1094
+
1095
+ pyais.messages.MessageType24PartB = HAMessageType24PartB
1096
+
1097
+
1098
+ @attr.s(slots=True)
1099
+ class HAMessageType25AddressedStructured(HAPayload):
1100
+ msg_type = bit_field(6, int, default=25, signed=False)
1101
+ repeat = bit_field(2, int, default=0, signed=False)
1102
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1103
+
1104
+ addressed = bit_field(1, bool, default=0, signed=False)
1105
+ structured = bit_field(1, bool, default=0, signed=False)
1106
+
1107
+ dest_mmsi = bit_field(30, int, default=0, from_converter=from_mmsi, signed=False)
1108
+ spare = bit_field(2, int, default=0, signed=False, is_spare=True)
1109
+ app_id = bit_field(16, int, default=0, signed=False)
1110
+ data = bit_field(80, bytes, default=b'', variable_length=True)
1111
+
1112
+ pyais.messages.MessageType25AddressedStructured = HAMessageType25AddressedStructured
1113
+
1114
+
1115
+ @attr.s(slots=True)
1116
+ class HAMessageType25AddressedUnstructured(HAPayload):
1117
+ msg_type = bit_field(6, int, default=25, signed=False)
1118
+ repeat = bit_field(2, int, default=0, signed=False)
1119
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1120
+
1121
+ addressed = bit_field(1, bool, default=0, signed=False)
1122
+ structured = bit_field(1, bool, default=0, signed=False)
1123
+
1124
+ dest_mmsi = bit_field(30, int, default=0, from_converter=from_mmsi)
1125
+ spare = bit_field(2, int, default=0, signed=False, is_spare=True)
1126
+ data = bit_field(96, bytes, default=b'', variable_length=True)
1127
+
1128
+ pyais.messages.MessageType25AddressedUnstructured = HAMessageType25AddressedUnstructured
1129
+
1130
+
1131
+ @attr.s(slots=True)
1132
+ class HAMessageType26AddressedStructured(HAPayload, CommunicationStateMixin):
1133
+ msg_type = bit_field(6, int, default=26, signed=False)
1134
+ repeat = bit_field(2, int, default=0, signed=False)
1135
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1136
+
1137
+ addressed = bit_field(1, bool, default=0, signed=False)
1138
+ structured = bit_field(1, bool, default=0, signed=False)
1139
+
1140
+ dest_mmsi = bit_field(30, int, default=0, from_converter=from_mmsi)
1141
+ spare1 = bit_field(2, int, default=0, signed=False, is_spare=True)
1142
+ app_id = bit_field(16, int, default=0, signed=False)
1143
+ data = bit_field(952, bytes, default=b'', variable_length=True)
1144
+ spare2 = bit_field(4, int, default=0, signed=False, is_spare=True)
1145
+ radio = bit_field(20, int, default=0, signed=False)
1146
+
1147
+ pyais.messages.MessageType26AddressedStructured = HAMessageType26AddressedStructured
1148
+
1149
+
1150
+ @attr.s(slots=True)
1151
+ class HAMessageType26BroadcastStructured(HAPayload, CommunicationStateMixin):
1152
+ msg_type = bit_field(6, int, default=26, signed=False)
1153
+ repeat = bit_field(2, int, default=0, signed=False)
1154
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1155
+
1156
+ addressed = bit_field(1, bool, default=0, signed=False)
1157
+ structured = bit_field(1, bool, default=0, signed=False)
1158
+
1159
+ app_id = bit_field(16, int, default=0, signed=False)
1160
+ data = bit_field(984, bytes, default=b'', variable_length=True)
1161
+ spare2 = bit_field(4, int, default=0, signed=False, is_spare=True)
1162
+ radio = bit_field(20, int, default=0, signed=False)
1163
+
1164
+ pyais.messages.MessageType26BroadcastStructured = HAMessageType26BroadcastStructured
1165
+
1166
+
1167
+ @attr.s(slots=True)
1168
+ class HAMessageType26AddressedUnstructured(HAPayload, CommunicationStateMixin):
1169
+ msg_type = bit_field(6, int, default=26, signed=False)
1170
+ repeat = bit_field(2, int, default=0, signed=False)
1171
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1172
+
1173
+ addressed = bit_field(1, bool, default=0, signed=False)
1174
+ structured = bit_field(1, bool, default=0, signed=False)
1175
+
1176
+ dest_mmsi = bit_field(30, int, default=0, from_converter=from_mmsi)
1177
+ spare1 = bit_field(2, int, default=0, signed=False, is_spare=True)
1178
+ data = bit_field(968, bytes, default=b'', variable_length=True)
1179
+ spare2 = bit_field(4, int, default=0, signed=False, is_spare=True)
1180
+ radio = bit_field(20, int, default=0, signed=False)
1181
+
1182
+ pyais.messages.MessageType26AddressedUnstructured = HAMessageType26AddressedUnstructured
1183
+
1184
+
1185
+ @attr.s(slots=True)
1186
+ class HAMessageType26BroadcastUnstructured(HAPayload, CommunicationStateMixin):
1187
+ msg_type = bit_field(6, int, default=26, signed=False)
1188
+ repeat = bit_field(2, int, default=0, signed=False)
1189
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1190
+
1191
+ addressed = bit_field(1, bool, default=0, signed=False)
1192
+ structured = bit_field(1, bool, default=0, signed=False)
1193
+
1194
+ data = bit_field(1000, bytes, default=b'', variable_length=True)
1195
+ spare2 = bit_field(4, int, default=0, signed=False, is_spare=True)
1196
+ radio = bit_field(20, int, default=0, signed=False)
1197
+
1198
+ pyais.messages.MessageType26BroadcastUnstructured = HAMessageType26BroadcastUnstructured
1199
+
1200
+
1201
+ class HAMessageType26(HAPayload):
1202
+ """
1203
+ Multiple Slot Binary Message
1204
+
1205
+ NOTE: This message type is quite uncommon and
1206
+ I was not able find any real world occurrence of the type.
1207
+ Also documentation seems to vary. Use with caution.
1208
+ """
1209
+
1210
+ @classmethod
1211
+ def create(cls, **kwargs: typing.Union[str, float, int, bool, bytes]) -> "ANY_MESSAGE":
1212
+ addressed = kwargs.get('addressed', False)
1213
+ structured = kwargs.get('structured', False)
1214
+
1215
+ if addressed:
1216
+ if structured:
1217
+ return HAMessageType26AddressedStructured.create(**kwargs)
1218
+ else:
1219
+ return HAMessageType26AddressedUnstructured.create(**kwargs)
1220
+ else:
1221
+ if structured:
1222
+ return HAMessageType26BroadcastStructured.create(**kwargs)
1223
+ else:
1224
+ return HAMessageType26BroadcastUnstructured.create(**kwargs)
1225
+
1226
+ @classmethod
1227
+ def from_bitarray(cls, bit_arr: bitarray) -> "ANY_MESSAGE":
1228
+ addressed: int = get_int(bit_arr, 38, 39)
1229
+ structured: int = get_int(bit_arr, 39, 40)
1230
+
1231
+ if addressed:
1232
+ if structured:
1233
+ return HAMessageType26AddressedStructured.from_bitarray(bit_arr)
1234
+ else:
1235
+ return HAMessageType26AddressedUnstructured.from_bitarray(bit_arr)
1236
+ else:
1237
+ if structured:
1238
+ return HAMessageType26BroadcastStructured.from_bitarray(bit_arr)
1239
+ else:
1240
+ return HAMessageType26BroadcastUnstructured.from_bitarray(bit_arr)
1241
+
1242
+ pyais.messages.MessageType26 = HAMessageType26
1243
+ pyais.messages.MSG_CLASS[26] = pyais.messages.MessageType26
1244
+
1245
+
1246
+ @attr.s(slots=True)
1247
+ class HAMessageType27(HAPayload):
1248
+ """
1249
+ Long Range AIS Broadcast message
1250
+ """
1251
+ msg_type = bit_field(6, int, default=27, signed=False)
1252
+ repeat = bit_field(2, int, default=0, signed=False)
1253
+ mmsi = bit_field(30, int, from_converter=from_mmsi)
1254
+
1255
+ accuracy = bit_field(1, bool, default=0, signed=False)
1256
+ raim = bit_field(1, bool, default=0, signed=False)
1257
+ status = bit_field(4, int, default=0, from_converter=NavigationStatus, to_converter=NavigationStatus, signed=False)
1258
+ lon = bit_field(18, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1259
+ lat = bit_field(17, float, from_converter=from_lat_lon_600, to_converter=to_lat_lon_600, default=0, signed=True)
1260
+ speed = bit_field(6, float, default=0, signed=False)
1261
+ course = bit_field(9, float, default=0, signed=False)
1262
+ gnss = bit_field(1, bool, default=0, signed=False)
1263
+ spare_1 = bit_field(1, bytes, default=b'', is_spare=True)
1264
+
1265
+ pyais.messages.MessageType27 = HAMessageType27
1266
+ pyais.messages.MSG_CLASS[27] = pyais.messages.MessageType27
1267
+
1268
+
1269
+ # Manage tag blocks
1270
+
1271
+ class HATagBlock(TagBlock):
1272
+ def __init__(self, raw: bytes = None) -> None:
1273
+ super().__init__(raw)
1274
+
1275
+ def to_raw(self):
1276
+ fields = []
1277
+ if self._group is not None:
1278
+ fields.append(f"g:{self._group}")
1279
+ if self._source_station is not None:
1280
+ fields.append(f"s:{self._source_station}")
1281
+ if self._receiver_timestamp is not None:
1282
+ fields.append(f"c:{self._receiver_timestamp}")
1283
+ if self._destination_station is not None:
1284
+ fields.append(f"d:{self._destination_station}")
1285
+ if self._line_count is not None:
1286
+ fields.append(f"n:{self._line_count}")
1287
+ if self._relative_time is not None:
1288
+ fields.append(f"r:{self._relative_time}")
1289
+ if self._text is not None:
1290
+ fields.append(f"t:{self._text}")
1291
+
1292
+ payload_str = ','.join(fields)
1293
+ payload = payload_str.encode()
1294
+
1295
+ chk_int = checksum(payload)
1296
+ chk = f"{chk_int:02X}".encode()
1297
+
1298
+ return payload + ASTERISK + chk
1299
+
1300
+ pyais.messages.TagBlock = HATagBlock
1301
+
1302
+
1303
+