Compare commits

...

221 Commits
v0.1 ... master

Author SHA1 Message Date
Gerolf Ziegenhain 2c2ff2d2ed raspi 2016-10-04 21:29:16 +02:00
Gerolf Ziegenhain 4c7442e3ea wip 2016-10-04 21:23:07 +02:00
Gerolf Ziegenhain 2c7de4792d wip 2016-10-04 21:21:59 +02:00
Gerolf Ziegenhain 496aa90bfe wip 2016-10-04 21:19:18 +02:00
Gerolf Ziegenhain 827798b86b wip 2016-10-04 21:19:06 +02:00
Gerolf Ziegenhain 5f9609ce0c wip 2016-10-04 21:18:09 +02:00
Gerolf Ziegenhain 75c77b0cac wip 2016-10-04 21:13:07 +02:00
Gerolf Ziegenhain 7bf9183401 wip 2016-10-04 21:10:34 +02:00
Gerolf Ziegenhain 746b1dcfe5 wip 2016-10-04 21:10:13 +02:00
Gerolf Ziegenhain 63300fa955 wip 2016-10-04 21:07:05 +02:00
Gerolf Ziegenhain a43019e565 wip 2016-10-04 21:05:21 +02:00
Gerolf Ziegenhain 370858ce8e wip 2016-10-04 21:02:06 +02:00
Gerolf Ziegenhain a62c28dcdf rm tx_method 2016-10-04 20:59:40 +02:00
Gerolf Ziegenhain d8815db878 serial_sep 2016-10-04 20:58:30 +02:00
Gerolf Ziegenhain d6d0679fb5 wip 2016-10-04 20:54:13 +02:00
Gerolf Ziegenhain 9d28c29a51 wip 2016-10-04 20:48:42 +02:00
Gerolf Ziegenhain 5d1ea8138b wip 2016-10-04 20:48:17 +02:00
Gerolf Ziegenhain af81f9a084 raspi 2016-10-04 20:45:48 +02:00
Gerolf Ziegenhain 1145e2769e wip 2016-10-04 19:07:03 +02:00
Gerolf Ziegenhain 516c1b4a57 wip 2016-10-04 19:06:37 +02:00
Gerolf Ziegenhain 1db2782667 wiring 2016-10-04 19:00:49 +02:00
Gerolf Ziegenhain ba6ece9ddd wiring 2016-10-04 18:53:27 +02:00
Gerolf Ziegenhain 4f9169d026 wiring 2016-10-04 18:52:52 +02:00
Gerolf Ziegenhain e36b01ce41 wiring 2016-10-04 18:48:43 +02:00
Gerolf Ziegenhain efeee5b0ee done 2016-10-04 18:37:28 +02:00
Gerolf Ziegenhain e01c86a248 add util files 2016-10-04 18:36:58 +02:00
Gerolf Ziegenhain 6163a138ce add util files 2016-10-04 18:35:56 +02:00
Gerolf Ziegenhain 5dad7c3f64 add util files 2016-10-04 18:34:50 +02:00
Gerolf Ziegenhain 8622552f86 add util files 2016-10-04 18:34:04 +02:00
Gerolf Ziegenhain 1d3b674ecc rm old linux code 2016-10-04 18:32:07 +02:00
Gerolf Ziegenhain 81316638fc adjust raspi latency 2016-10-04 18:27:45 +02:00
Gerolf Ziegenhain 83d152c2bc rm zero string warning 2016-10-04 18:26:05 +02:00
Gerolf Ziegenhain fddeaab8ed raspi clean header 2016-10-04 18:24:09 +02:00
Gerolf Ziegenhain 197ac3224e add raspi audio fix 2016-10-04 18:22:50 +02:00
Gerolf Ziegenhain 7ead5be229 add raspi audio fix 2016-10-04 18:22:16 +02:00
Gerolf Ziegenhain 46842ab42b revert changes - raspi identified 2016-10-04 18:20:09 +02:00
Gerolf Ziegenhain 86e7cc039b wip 2016-10-04 18:12:10 +02:00
Gerolf Ziegenhain 5e586d03d9 wip 2016-10-04 18:11:29 +02:00
Gerolf Ziegenhain bf0ebc9f6e wip 2016-10-04 18:10:23 +02:00
Gerolf Ziegenhain 8da5cc22d6 wip 2016-10-04 18:02:49 +02:00
Gerolf Ziegenhain ff773f1f4e wip 2016-10-04 18:01:29 +02:00
Gerolf Ziegenhain 05ad58cb09 wip 2016-10-04 17:59:33 +02:00
Gerolf Ziegenhain 08423de98c wip 2016-10-04 17:58:12 +02:00
Gerolf Ziegenhain a9371e16d4 wip 2016-10-04 17:56:07 +02:00
Gerolf Ziegenhain 57f6c84f88 wip 2016-10-04 17:54:36 +02:00
Gerolf Ziegenhain 15ab7fbbcc wip 2016-10-04 17:53:18 +02:00
Gerolf Ziegenhain c60842a89f wip 2016-10-04 17:52:49 +02:00
Gerolf Ziegenhain a5b7aed310 wip 2016-10-04 17:52:12 +02:00
Gerolf Ziegenhain 49d87c5cc8 wip 2016-10-04 17:50:37 +02:00
Gerolf Ziegenhain 1c1ef6ca4d wip 2016-10-04 17:49:09 +02:00
Gerolf Ziegenhain bd54a9cec4 wip 2016-10-04 17:48:46 +02:00
Gerolf Ziegenhain 5b51a3459a wip 2016-10-04 17:47:51 +02:00
Gerolf Ziegenhain ab06957571 wip 2016-10-04 17:47:18 +02:00
Gerolf Ziegenhain 108d04efd2 wip 2016-10-04 17:46:36 +02:00
Gerolf Ziegenhain aaf24cf35d wip 2016-10-04 17:34:24 +02:00
Gerolf Ziegenhain d77de7e47c wip 2016-10-04 17:34:17 +02:00
Gerolf Ziegenhain b2418e4aa6 wip 2016-10-04 17:32:56 +02:00
Gerolf Ziegenhain d4531a3f73 wip 2016-10-04 17:31:46 +02:00
Gerolf Ziegenhain 13a1af9ed4 wip 2016-10-04 17:31:03 +02:00
Gerolf Ziegenhain 43ac116425 wip 2016-10-04 17:30:33 +02:00
Gerolf Ziegenhain 08f5c20420 wip 2016-10-04 17:28:06 +02:00
Gerolf Ziegenhain e78a722025 wip 2016-10-04 17:27:38 +02:00
Gerolf Ziegenhain 2e975376dc wip 2016-10-04 17:24:05 +02:00
Gerolf Ziegenhain b227bd5d90 wip 2016-10-04 17:23:47 +02:00
Gerolf Ziegenhain 5ac4d0f63f wip 2016-10-04 17:22:11 +02:00
Gerolf Ziegenhain 9be4962d53 wip 2016-10-04 17:21:24 +02:00
Gerolf Ziegenhain 9fdfc71ab3 wip 2016-10-04 17:19:14 +02:00
Gerolf Ziegenhain 3c469edf69 wip 2016-10-04 17:14:43 +02:00
Gerolf Ziegenhain 4a2e3ca88f wip 2016-10-04 17:14:08 +02:00
Gerolf Ziegenhain 4f08a0c6c7 wip 2016-10-04 17:11:18 +02:00
Gerolf Ziegenhain eee931feb1 wip 2016-10-04 17:08:47 +02:00
Gerolf Ziegenhain 96264ece63 wip 2016-10-04 17:08:16 +02:00
Gerolf Ziegenhain 6e24a9e0ba wip 2016-10-04 17:02:16 +02:00
Gerolf Ziegenhain 1262a6abfd wip 2016-10-04 17:01:56 +02:00
Gerolf Ziegenhain 9dd1055495 wip 2016-10-04 17:00:43 +02:00
Gerolf Ziegenhain 96c1a5c030 wip 2016-10-04 16:59:59 +02:00
Gerolf Ziegenhain ae5dffa383 wip 2016-10-04 16:59:41 +02:00
Gerolf Ziegenhain 0d9924f9e6 wip 2016-10-04 16:56:31 +02:00
Gerolf Ziegenhain b398e6df30 wip 2016-10-04 16:55:30 +02:00
Gerolf Ziegenhain a56a475361 wip 2016-10-04 16:54:30 +02:00
Gerolf Ziegenhain b3938f5a5e wip 2016-10-04 16:53:37 +02:00
Gerolf Ziegenhain 28767e86a6 wip 2016-10-04 16:53:16 +02:00
Gerolf Ziegenhain 82611ac618 wip 2016-10-04 16:52:23 +02:00
Gerolf Ziegenhain 2c236c0b25 wip 2016-10-04 16:52:16 +02:00
Gerolf Ziegenhain 55f4a137b2 wip 2016-10-04 16:51:52 +02:00
Gerolf Ziegenhain 609a9e2b3c wip 2016-10-04 16:51:01 +02:00
Gerolf Ziegenhain bc66ce5855 wip 2016-10-04 16:50:10 +02:00
Gerolf Ziegenhain 592de3d5a9 wip 2016-10-04 16:49:43 +02:00
Gerolf Ziegenhain 5995b5e619 wip 2016-10-04 16:46:47 +02:00
Gerolf Ziegenhain d62992fdf1 wip 2016-10-04 16:45:58 +02:00
Gerolf Ziegenhain 0417c67854 wip 2016-10-04 16:44:37 +02:00
Gerolf Ziegenhain 6142bab18b wip 2016-10-04 16:41:45 +02:00
Gerolf Ziegenhain 8142e10343 wip 2016-10-04 16:40:57 +02:00
Gerolf Ziegenhain fc605357df wip 2016-10-04 16:39:46 +02:00
Gerolf Ziegenhain a61c528315 wip 2016-10-04 16:38:51 +02:00
Gerolf Ziegenhain b24c2d5bb3 wip 2016-10-04 16:38:04 +02:00
Gerolf Ziegenhain 2a72f535a7 wip 2016-10-04 16:37:06 +02:00
Gerolf Ziegenhain f3b0df241d wip 2016-10-04 16:35:21 +02:00
Gerolf Ziegenhain 06a2dec810 wip 2016-10-04 16:33:14 +02:00
Gerolf Ziegenhain 4c62e4f573 wip 2016-10-04 16:31:36 +02:00
Gerolf Ziegenhain e340b9f9be wip 2016-10-04 16:31:19 +02:00
Gerolf Ziegenhain 72ab6292fd wip 2016-10-04 16:29:58 +02:00
Gerolf Ziegenhain 8da3e55d8b wip 2016-10-04 16:27:25 +02:00
Gerolf Ziegenhain 0dbe192f7a wip 2016-10-04 16:26:49 +02:00
Gerolf Ziegenhain b3e2c0fa72 wip 2016-10-04 16:26:12 +02:00
Gerolf Ziegenhain 98ec981c98 wip 2016-10-04 16:25:50 +02:00
Gerolf Ziegenhain 934b28aa1f wip 2016-10-04 16:24:34 +02:00
Gerolf Ziegenhain 5d045fa8b4 beep close 2016-10-03 21:24:44 +02:00
Gerolf Ziegenhain e8b8e526f6 rm restart 2016-10-03 21:09:26 +02:00
Gerolf Ziegenhain a056678346 restarting beep 2016-10-03 21:08:29 +02:00
Gerolf Ziegenhain 40853a0d4c add close function wrapper 2016-10-03 21:05:44 +02:00
Gerolf Ziegenhain 2cfb08aa18 . 2016-10-03 17:59:43 +02:00
Gerolf Ziegenhain ab83ca4738 . 2016-10-03 17:58:42 +02:00
Gerolf Ziegenhain 436d30d5e1 raspi hack begin 2016-10-03 17:47:10 +02:00
Gerolf Ziegenhain c7e095b145 hack 2016-10-03 17:16:47 +02:00
Gerolf Ziegenhain c4a2a45805 get rid of known warnings 2016-10-03 17:08:09 +02:00
Gerolf Ziegenhain a76682e1ab raspi 2016-10-03 17:06:40 +02:00
Gerolf Ziegenhain ef4c54eeb9 cleanup 2016-10-03 17:06:22 +02:00
Gerolf Ziegenhain 84691e75bf osx dependencies 2016-10-03 17:04:04 +02:00
Gerolf Ziegenhain f77a4c5821 linux dependencies 2016-10-03 17:03:25 +02:00
Gerolf Ziegenhain 6d5f7173a3 reduce known warnings 2016-10-03 16:57:46 +02:00
Gerolf Ziegenhain 736ce016ad raspi build instructions 2016-10-03 16:56:38 +02:00
Gerolf Ziegenhain 19842349d9 add fct to header 2016-10-03 16:54:54 +02:00
Gerolf Ziegenhain a447eed37c arm 2016-10-03 16:53:11 +02:00
Gerolf Ziegenhain 183e60aa16 adjust interface number 2016-10-03 16:30:35 +02:00
Gerolf Ziegenhain fde22697d8 cleanup beep buzzer 2016-10-03 16:26:58 +02:00
Gerolf Ziegenhain 5286a77c70 reduced docu 2016-10-03 16:25:37 +02:00
Gerolf Ziegenhain b29dc7281a cleanup beep 2016-10-03 16:23:41 +02:00
Gerolf Ziegenhain ac49de555a new beep without jitter 2016-10-03 16:18:56 +02:00
Gerolf Ziegenhain 07d5b97912 wip 2016-10-03 16:15:34 +02:00
Gerolf Ziegenhain b8603fd9d0 wip 2016-10-03 16:13:59 +02:00
Gerolf Ziegenhain 6d8fee68f4 example 2016-10-03 16:02:17 +02:00
Gerolf Ziegenhain 9838719a50 protocol 2016-09-24 17:03:30 +02:00
Gerolf Ziegenhain c12478241a rename 2016-09-24 16:56:31 +02:00
Gerolf Ziegenhain 5842d754da wip 2016-09-24 16:55:57 +02:00
Gerolf Ziegenhain 54cb98634e sort functions 2016-09-24 16:55:36 +02:00
Gerolf Ziegenhain 0252a2803b wip 2016-09-24 16:34:20 +02:00
Gerolf Ziegenhain 2445a111f3 sort headers 2016-09-24 16:28:30 +02:00
Gerolf Ziegenhain d91a7b2a29 wip 2016-09-24 16:21:29 +02:00
Gerolf Ziegenhain 910b60eb37 rm commandmode 2016-09-24 15:59:41 +02:00
Gerolf Ziegenhain 8f7648f7f6 redo commandmode 2016-09-24 15:58:47 +02:00
Gerolf Ziegenhain 7b8e7a5e18 add morse lib 2016-09-23 22:33:19 +02:00
Gerolf Ziegenhain 405634e645 rm osx dir 2016-09-23 22:32:24 +02:00
Gerolf Ziegenhain ba4e67f0a4 add paex_sine.c 2015-07-08 23:24:41 +02:00
Gerolf Ziegenhain 36fa067cc5 cleanup 2015-07-08 22:38:29 +02:00
Gerolf Ziegenhain c464cc7dcb moip hp 2015-07-08 21:42:28 +02:00
Gerolf Ziegenhain 5295c33b74 add reference to moip website 2015-07-08 21:41:53 +02:00
Gerolf Ziegenhain b3bed56197 rm old screenshot 2015-07-08 21:40:30 +02:00
Gerolf Ziegenhain a4eed20392 pins 2015-07-08 21:38:58 +02:00
Gerolf Ziegenhain 51528cd34b table 2015-07-08 21:37:48 +02:00
Gerolf Ziegenhain c37c2b4a0d table 2015-07-08 21:37:29 +02:00
Gerolf Ziegenhain 594bb6006f table 2015-07-08 21:35:25 +02:00
Gerolf Ziegenhain 2d99d0deba table 2015-07-08 21:34:26 +02:00
Gerolf Ziegenhain 49a033f9a3 version description 2015-07-08 21:33:02 +02:00
Gerolf Ziegenhain 79b9ab5dc1 commandline options 2015-07-08 21:06:39 +02:00
Gerolf Ziegenhain a8b5ad29b7 Merge branch 'master' into dev 2015-07-07 22:45:46 +02:00
Gerolf Ziegenhain a8468dbe42 exclude obj 2015-07-07 22:45:38 +02:00
Gerolf Ziegenhain d2254a907b merged code cleanup 2015-07-07 22:44:21 +02:00
Gerolf Ziegenhain cc3bf0ae5a typo 2015-07-07 19:54:19 +02:00
Gerolf Ziegenhain bc62081ced typo 2015-07-07 19:53:40 +02:00
Gerolf Ziegenhain 24a5afa697 add screenshot 2015-04-29 21:37:50 +02:00
Gerolf Ziegenhain 7305e8a723 add osx screenshot 2015-04-29 21:36:28 +02:00
Gerolf Ziegenhain aa596c0c66 add screenshot on osx 2015-04-29 21:35:08 +02:00
Gerolf Ziegenhain 2d8ca13a22 rm old posting 2015-03-04 20:10:57 +01:00
Gerolf Ziegenhain f05f4ae2f7 add pins 2015-02-16 21:32:13 +01:00
Gerolf Ziegenhain 2f88687332 added test cases 2015-02-16 21:00:42 +01:00
Gerolf Ziegenhain 98d3b54d82 merged from dev 2015-02-16 18:41:26 +01:00
Gerolf Ziegenhain fbd96d2495 doc 2015-02-16 18:39:55 +01:00
Gerolf Ziegenhain 0ccfe55978 wip 2015-02-15 13:13:49 +01:00
Gerolf Ziegenhain eb1c87cb37 wip 2015-02-15 13:13:22 +01:00
Gerolf Ziegenhain 67acd163b6 wip 2015-02-15 13:11:40 +01:00
Gerolf Ziegenhain 2c71fe456d add doc by Les Kerr 2015-02-15 11:45:47 +01:00
8cH9azbsFifZ 0519826df2 Update README.md 2015-02-15 09:34:43 +01:00
Gerolf Ziegenhain e4a61ba4a9 code quality warning 2015-02-15 09:27:13 +01:00
Gerolf Ziegenhain 251fa57b32 add java morsekob for testing 2015-02-07 21:23:58 +01:00
Gerolf Ziegenhain b075427a3c more information on ext. hw 2015-02-07 21:21:33 +01:00
Gerolf Ziegenhain 77dc0cf117 formatting 2015-02-07 20:54:54 +01:00
Gerolf Ziegenhain 9319409282 wip 2015-02-03 23:29:32 +01:00
Gerolf Ziegenhain 572c6d93ac added jar for testing 2015-02-03 23:20:40 +01:00
Gerolf Ziegenhain dd0881a5d4 added wikipedia section 2015-02-03 22:47:12 +01:00
Gerolf Ziegenhain d73eb66b99 network trace for debug 2015-01-06 00:18:10 +01:00
Gerolf Ziegenhain ae779dc2f5 magic numbers 2015-01-04 15:32:43 +01:00
Gerolf Ziegenhain f028280963 cleanup 2015-01-04 15:29:26 +01:00
Gerolf Ziegenhain 765cb854ed initialization of packets 2015-01-04 15:26:52 +01:00
Gerolf Ziegenhain 12f2d905ce started separating protocol. 2015-01-04 15:02:18 +01:00
Gerolf Ziegenhain 1140c99193 started separating protocol. 2015-01-04 15:02:03 +01:00
Gerolf Ziegenhain 272d03cbc8 merged from master 2015-01-04 14:44:17 +01:00
Gerolf Ziegenhain d2f8a0b65f merged from master 2015-01-04 14:43:50 +01:00
Gerolf Ziegenhain 87dbb05d3e merged from master 2015-01-04 14:43:28 +01:00
Gerolf Ziegenhain 9599bae5a8 merged from master 2015-01-04 14:43:06 +01:00
Gerolf Ziegenhain dccf7e6cfc documented structures 2015-01-04 14:39:51 +01:00
Gerolf Ziegenhain b20d4efe9e removed unused structure 2015-01-04 14:36:48 +01:00
Gerolf Ziegenhain e0471a4c62 added dg6fl 2015-01-04 13:25:38 +01:00
Gerolf Ziegenhain 24a74dbd55 added changelog 2015-01-04 13:24:47 +01:00
Gerolf Ziegenhain cb783b97e1 added description of the protocol 2015-01-04 13:22:32 +01:00
Gerolf Ziegenhain 45716af4f9 magic number - sizes of packets 2015-01-04 13:21:35 +01:00
Gerolf Ziegenhain 9d540cf369 magic number - sizes of packets 2015-01-04 13:19:56 +01:00
Gerolf Ziegenhain a2200a4aa6 added links to usb serial drivers 2015-01-04 10:22:13 +01:00
Gerolf Ziegenhain 182be32401 added authors file 2015-01-04 10:19:11 +01:00
Gerolf Ziegenhain f222d65bd8 moved x86 stuff to src 2015-01-04 10:06:40 +01:00
Gerolf Ziegenhain 840bbd0c04 typo 2015-01-04 02:36:57 +01:00
Gerolf Ziegenhain 50dfd48602 additional information 2015-01-04 00:12:56 +01:00
Gerolf Ziegenhain 5ffefff868 additional information 2015-01-04 00:04:09 +01:00
Gerolf Ziegenhain dd72972a96 additional information 2015-01-03 23:59:18 +01:00
Gerolf Ziegenhain 572345d34b references 2015-01-03 23:45:14 +01:00
Gerolf Ziegenhain 04572c6c16 references 2015-01-03 23:42:00 +01:00
Gerolf Ziegenhain f7b1bf6e1e references 2015-01-03 23:39:12 +01:00
Gerolf Ziegenhain 4c02a54109 formatting 2015-01-03 23:28:04 +01:00
Gerolf Ziegenhain 7e8c1803af formatting 2015-01-03 23:26:48 +01:00
Gerolf Ziegenhain 247deb12dc formatting 2015-01-03 23:26:01 +01:00
Gerolf Ziegenhain 6e141246f6 formatting 2015-01-03 23:19:29 +01:00
Gerolf Ziegenhain 8f77f51fcf linux installation notes 2015-01-03 23:15:12 +01:00
Gerolf Ziegenhain c8105acca0 linux notes 2015-01-03 23:14:25 +01:00
Gerolf Ziegenhain b2f24af29e merged linux build 2015-01-03 23:12:02 +01:00
Gerolf Ziegenhain 0b242efc1a merged linux build 2015-01-03 23:11:45 +01:00
Gerolf Ziegenhain adeba195f6 merged makefiles 2015-01-03 23:00:47 +01:00
Gerolf Ziegenhain 0424b7e2d3 removed obsolete files 2015-01-03 22:59:08 +01:00
Gerolf Ziegenhain 87f8437b87 modified for wheezy - without sound.c 2015-01-03 22:58:48 +01:00
Gerolf Ziegenhain ecce799bb7 add osx build 2015-01-03 22:45:02 +01:00
Gerolf Ziegenhain a4bbec6497 osx port 2015-01-03 22:38:23 +01:00
Gerolf Ziegenhain 325d794b7c compile instructions debian 2015-01-03 22:36:21 +01:00
18 changed files with 872 additions and 585 deletions

2
.gitignore vendored
View File

@ -1 +1,3 @@
.DS_Store
irmc
*.o

8
AUTHORS Normal file
View File

@ -0,0 +1,8 @@
Fernan Bolando (VE4FEB)
Gerolf Ziegenhain (DG6FL)
MorseKOB:
Lex Kerr
CWCom Protocol:
John Samien (VK1EME)

View File

@ -1,41 +1,44 @@
=== WIP - Snipplets ===
How to use:
irmc - Internet Relay Morse Code
================================
IRMC stands for Internet Relay Morse Code and is an implementation of [MOIP](http://8ch9azbsfifz.github.io/moip/).
1 usage: irmc [hostname] [port] [channel] [id] [serialport]
./irmc mtc-kob.dyndns.org 7890 103 123 /dev/tty.usbserial
faeroes.sdf.org.7890
# Building
## On Linux
sudo apt-get install -y alsa-oss oss-compat build-essential autoconf libao-dev libtool libportaudio-dev portaudio19-dev
make
### On Raspi (GPIO Interface)
Follow: http://wiringpi.com/download-and-install/
make raspi
TBD: Driver:
serial - 2usb!
## On OSX
brew install portaudio
make
TBD: OSX - howto install dependencies
# Hardware interface options
A good description on how to build different interfaces (telegraph key, sounder or both)
is given on the [MorseKOB Website](http://kob.sdf.org/morsekob/interface.htm).
Landline telegraphs use "closed circuits" for communications; if you have built one at home,
you may also use the [loop interface](http://kob.sdf.org/morsekob/docs/loopinterface.pdf).
=== Original post ===
I have been using cwcom to practice sending morsecode, unfortunately my main computer at home is running openbsd and it has gotten harder to gain access to a reliable MS Windows machine. So I wrote my own client that works on openbsd.
This is written in C and although not tested it should compile under other OS. If any one wants to try it and send me feedback. you can download version 0.01 here http://fernan.bitbucket.org/irmc.tgz
Les Kerr of https://home.comcast.net/~morsekob/ has been very patient in answering my questions regarding the cwcom protocol and setting up a test server during debugging.
Connection of a morse key:
[layout of pins](http://techpubs.sgi.com/library/dynaweb_docs/0650/SGI_Admin/books/MUX_IG/sgi_html/figures/4-2.serial.port.con.gif)
There are few difference between this and the official cwcom client
1. It is a command line tool
2. It does not send the characters of the message to the receivers screen.
3. It does not translate CW for you. You can try fldigi if you just want see the transmission.
4. Tone pitch is currently hard coded to 650Hz
5. It does not have a way to show you who is listening.
Bugs
There are a few that I am working on right now, but feel free to send me feedback if you get a chance to try it out.
File(s)
http://fernan.bitbucket.org/irmc.tgz
| RS232 | DB9 | Function |
| :-------- |:-------| :------ |
| DTR | 4 | Manual Key / paddle common|
| DSR | 6 | Manual key / dot paddle|
| CTS | 8 | Dash paddle|
| RTS | 7 | Sounder output|
| SG | 5 | Sounder ground|
Resources
The following people have helped me a lot to learn the protocols and setting up test servers.
Les Kerr - https://home.comcast.net/~morsekob/
Bob Denny - http://morse-rss-news.sourceforge.net/
John Samin - http://www.mrx.com.au/
=== Source: http://fernski.blogspot.de/2013/03/internet-relay-morsecode.html ===
=== End Original Post ===
# Changelog
* v0.3 [zip](https://github.com/8cH9azbsFifZ/irmc/archive/v0.3.zip) - commandline option cleanup
* v0.2 [zip](https://github.com/8cH9azbsFifZ/irmc/archive/v0.2.zip) - ported to debian wheezy and osx yosemite, DG6FL
* v0.1 [zip](https://github.com/8cH9azbsFifZ/irmc/archive/v0.1.zip) - original version, VE7FEB
Code Quality
============
This is experimental code.

BIN
doc/cwcom.pdf Normal file

Binary file not shown.

BIN
doc/loopinterface.pdf Normal file

Binary file not shown.

450
irmc.c
View File

@ -1,450 +0,0 @@
/* irmc - internet relay morsecode client */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <math.h>
#include <fcntl.h>
#include <soundcard.h>
#include <signal.h>
#include <arpa/inet.h>
#include "sound.h"
#define MAXDATASIZE 1024 // max number of bytes we can get at once
#define DIS 0x0002
#define DAT 0x0003
#define CON 0x0004
#define ACK 0x0005
#define DEBUG 0
struct command_packet_format{
unsigned short command;
unsigned short channel;
};
struct data_packet_format{
unsigned short command;
unsigned short length;
char id[128];
char a1[4];
unsigned int sequence;
unsigned int a21;
unsigned int a22;
unsigned int a23;
signed int code[51];
unsigned int n;
char status[128]; /* This is called version in MorseKob */
char a4[8];
};
struct code_packet_format{
unsigned short command;
unsigned short length;
char id[128];
char a1[4];
unsigned int sequence;
unsigned int a21;
unsigned int a22;
unsigned int a23;
signed int code[51];
unsigned int n;
char a3[128];
char a4[8];
};
struct command_packet_format connect_packet;
struct command_packet_format disconnect_packet = {DIS, 0};
struct data_packet_format id_packet;
struct data_packet_format rx_data_packet;
struct data_packet_format tx_data_packet;
int serial_status = 0, fd_speaker, fd_serial, fd_socket, numbytes;
int tx_sequence = 0, rx_sequence;
double tx_timeout = 0;
long tx_timer = 0;
#define TX_WAIT 5000
#define TX_TIMEOUT 240.0
#define KEEPALIVE_CYCLE 100
char soundcard[] = "/dev/audio";
long key_press_t1;
long key_release_t1;
int last_message = 0;
char last_sender[16];
/* settings */
int translate = 0;
int audio_status = 1;
/* a better clock() in milliseconds */
long
fastclock(void)
{
struct timespec t;
long r;
clock_gettime(CLOCK_REALTIME, &t);
r = t.tv_sec * 1000;
r = r + t.tv_nsec / 1000000;
return r;
}
int kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select (STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}
/* get sockaddr, IPv4 or IPv6: */
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}
void
identifyclient(void)
{
tx_sequence++;
id_packet.sequence = tx_sequence;
send(fd_socket, &connect_packet, sizeof(connect_packet), 0);
send(fd_socket, &id_packet, 496, 0);
}
void
inthandler(int sig)
{
signal(sig, SIG_IGN);
send(fd_socket, &disconnect_packet, sizeof(disconnect_packet), 0);
close(fd_socket);
close(fd_speaker);
close(fd_serial);
exit(1);
}
void
txloop (void)
{
key_press_t1 = fastclock();
tx_timeout = 0;
for(;;){
tx_data_packet.n++;
tx_data_packet.code[tx_data_packet.n - 1] =
(int) ((key_press_t1 - key_release_t1) * -1);
//printf("space: %i\n", tx_data_packet.code[tx_data_packet.n -1]);
while(serial_status & TIOCM_DSR) ioctl(fd_serial, TIOCMGET, &serial_status);
key_release_t1 = fastclock();
tx_data_packet.n++;
tx_data_packet.code[tx_data_packet.n - 1] =
(int) ((key_release_t1 - key_press_t1) * 1);
//printf("mark: %i\n", tx_data_packet.code[tx_data_packet.n -1]);
while(1){
ioctl(fd_serial, TIOCMGET, &serial_status);
if(serial_status & TIOCM_DSR) break;
tx_timeout = fastclock() - key_release_t1;
if(tx_timeout > TX_TIMEOUT) return;
}
key_press_t1 = fastclock();
if(tx_data_packet.n == 50) {
printf("irmc: warning packet is full.\n");
return;
}
}
}
int
commandmode(void)
{
char cmd[32];
int i;
last_message = 0; /* reset status message */
printf(".");
fgets(cmd, 32, stdin);
if(strncmp(cmd, ".", 1) == 0){
printf("\n");
return 1;
}
if((strncmp(cmd, "latch", 3)) == 0){
tx_sequence++;
tx_data_packet.sequence = tx_sequence;
tx_data_packet.code[0] = -1;
tx_data_packet.code[1] = 1;
tx_data_packet.n = 2;
for(i = 0; i < 5; i++) send(fd_socket, &tx_data_packet, 496, 0);
tx_data_packet.n = 0;
return 0;
}
if((strncmp(cmd, "unlatch", 3)) == 0){
tx_sequence++;
tx_data_packet.sequence = tx_sequence;
tx_data_packet.code[0] = -1;
tx_data_packet.code[1] = 2;
tx_data_packet.n = 2;
for(i = 0; i < 5; i++) send(fd_socket, &tx_data_packet, 496, 0);
tx_data_packet.n = 0;
return 0;
}
if((strncmp(cmd, "ton", 3)) == 0){
translate = 1;
return 0;
}
if((strncmp(cmd, "toff", 3)) == 0){
translate = 0;
return 0;
}
if((strncmp(cmd, "aon", 3)) == 0){
audio_status = 1;
fd_speaker = open_audio_device(soundcard, O_WRONLY);
return 0;
}
if((strncmp(cmd, "aoff", 3)) == 0){
audio_status = 0;
close(fd_speaker);
return 0;
}
printf("?\n");
return 0;
}
void
message(int msg)
{
switch(msg){
case 1:
if(last_message == msg) return;
if(last_message == 2) printf("\n");
last_message = msg;
printf("irmc: transmitting...\n");
break;
case 2:
if(last_message == msg && strncmp(last_sender, rx_data_packet.id, 3) == 0) return;
else {
if(last_message == 2) printf("\n");
last_message = msg;
strncpy(last_sender, rx_data_packet.id, 3);
printf("irmc: receiving...(%s)\n", rx_data_packet.id);
}
break;
case 3:
printf("irmc: circuit was latched by %s.\n", rx_data_packet.id);
break;
case 4:
printf("irmc: circuit was unlatched by %s.\n", rx_data_packet.id);
break;
default:
break;
}
fflush(0);
}
int main(int argc, char *argv[])
{
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv, i;
char s[INET6_ADDRSTRLEN];
int keepalive_t = 0;
char hostname[64];
char port[16];
int channel;
char id[128];
char serialport[64];
if (argc < 4) {
fprintf(stderr," %i usage: irmc [hostname] [port] [channel] [id] [serialport]\n", argc);
exit(1);
}
snprintf(hostname, 64, argv[1], "%s");
snprintf(port, 16, argv[2], "%s");
channel = atoi(argv[3]);
if(argc > 4) snprintf(id, 128, argv[4], "%s");
else snprintf(id, 128, "irmc");
if(argc > 5) snprintf(serialport, 64, argv[5], "%s");
id_packet.command = DAT;
id_packet.length = 492;
snprintf(id_packet.id, 128, id, "%s");
id_packet.sequence = 0;
id_packet.n = 0;
snprintf(id_packet.status, 128, "irmc v0.02");
id_packet.a21 = 1; /* These magic numbers was provided by Les Kerr */
id_packet.a22 = 755;
id_packet.a23 = 65535;
tx_data_packet.command = DAT;
tx_data_packet.length = 492;
snprintf(tx_data_packet.id, 128, id, "%s");
tx_data_packet.sequence = 0;
tx_data_packet.n = 0;
for(i = 1; i < 51; i++)tx_data_packet.code[i] = 0;
tx_data_packet.a21 = 0; /* These magic numbers was provided by Les Kerr */
tx_data_packet.a22 = 755;
tx_data_packet.a23 = 16777215;
snprintf(tx_data_packet.status, 128, "?");
connect_packet.command = CON;
connect_packet.channel = channel;
signal(SIGINT, inthandler);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(hostname, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
/* Find the first free socket */
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((fd_socket = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("irmc: socket");
continue;
}
if (connect(fd_socket, p->ai_addr, p->ai_addrlen) == -1) {
close(fd_socket);
perror("irmc: connect");
continue;
}
break;
}
fcntl(fd_socket, F_SETFL, O_NONBLOCK);
if (p == NULL) {
fprintf(stderr, "irmc: failed to connect\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
printf("irmc: connected to %s\n", s);
fd_speaker = open_audio_device(soundcard, O_WRONLY);
fd_serial = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd_serial == -1) {
printf("irmc: unable to open serial port.\n");
}
freeaddrinfo(servinfo); /* all done with this structure */
key_release_t1 = fastclock();
init_sound();
identifyclient();
/* Main Loop */
for(;;) {
if(tx_timer == 0)
if((numbytes = recv(fd_socket, buf, MAXDATASIZE-1, 0)) == -1)
usleep(250);
if(numbytes == 496 && tx_timer == 0){
memcpy(&rx_data_packet, buf, 496);
#if DEBUG
printf("length: %i\n", rx_data_packet.length);
printf("id: %s\n", rx_data_packet.id);
printf("sequence no.: %i\n", rx_data_packet.sequence);
printf("version: %s\n", rx_data_packet.status);
printf("n: %i\n", rx_data_packet.n);
printf("code:\n");
for(i = 0; i < 51; i++)printf("%i ", rx_data_packet.code[i]); printf("\n");
#endif
if(rx_data_packet.n > 0 && rx_sequence != rx_data_packet.sequence){
message(2);
if(translate == 1){
printf("%s", rx_data_packet.status);
fflush(0);
}
rx_sequence = rx_data_packet.sequence;
for(i = 0; i < rx_data_packet.n; i++){
switch(rx_data_packet.code[i]){
case 1:
message(3);
break;
case 2:
message(4);
break;
default:
if(audio_status == 1)
play_code_element (rx_data_packet.code[i]);
break;
}
}
}
}
if(tx_timer > 0) tx_timer--;
if(tx_data_packet.n > 1 ){
tx_sequence++;
tx_data_packet.sequence = tx_sequence;
for(i = 0; i < 5; i++) send(fd_socket, &tx_data_packet, 496, 0);
#if DEBUG
printf("irmc: sent data packet.\n");
#endif
tx_data_packet.n = 0;
}
ioctl(fd_serial,TIOCMGET, &serial_status);
if(serial_status & TIOCM_DSR){
txloop();
tx_timer = TX_WAIT;
message(1);
}
if(keepalive_t < 0 && tx_timer == 0){
#if DEBUG
printf("keep alive sent.\n");
#endif
identifyclient();
keepalive_t = KEEPALIVE_CYCLE;
}
if(tx_timer == 0) {
keepalive_t--;
usleep(50);
}
if(kbhit() && tx_timer == 0){
getchar(); /* flush the buffer */
if(commandmode()== 1)break;
}
} /* End of mainloop */
send(fd_socket, &disconnect_packet, sizeof(disconnect_packet), 0);
close(fd_socket);
close(fd_speaker);
close(fd_serial);
exit(0);
}

BIN
lib/morse-0.1.tar.gz Normal file

Binary file not shown.

94
sound.c
View File

@ -1,94 +0,0 @@
/* irmc - internet relay morsecode client */
#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <fcntl.h>
#include <soundcard.h>
#include <math.h>
#define SAMPLE_RATE 48000
int sample_rate = SAMPLE_RATE;
int fd_speaker;
int zinebuf[SAMPLE_RATE * 2];
int pitch = 650;
void
init_sound()
{
int i, pr;
pr = sample_rate / pitch;
for(i = 0; i < SAMPLE_RATE * 2; i++)
zinebuf[i] = 32767 * sin(2 * 3.1415 / pr * (double)i );
}
void
play_code_element (int length)
{
int i;
short buf[SAMPLE_RATE * 4];
int outsz;
outsz = abs(length) * SAMPLE_RATE / 1000;
if(length == 0 || abs(length) > 2000) return;
if(length < 0) { /* Space */
for (i = 0; i < outsz; i++) buf[i] = 0;
} else { /* Mark */
for (i = 0; i < outsz; i++) buf[i] = zinebuf[i];
}
if (write (fd_speaker, buf, outsz * 2) != (outsz * 2)){
perror ("Audio write");
exit (-1);
}
}
int
open_audio_device (char *name, int mode)
{
int tmp, fd;
if ((fd = open (name, mode, 0)) == -1){
perror (name);
//exit (-1);
}
tmp = AFMT_S16_NE; /* Native 16 bits */
if (ioctl (fd, SNDCTL_DSP_SETFMT, &tmp) == -1){
perror ("SNDCTL_DSP_SETFMT");
exit (-1);
}
if (tmp != AFMT_S16_NE){
fprintf (stderr,
"The device doesn't support the 16 bit sample format.\n");
exit (-1);
}
tmp = 1;
if (ioctl (fd, SNDCTL_DSP_CHANNELS, &tmp) == -1){
perror ("SNDCTL_DSP_CHANNELS");
exit (-1);
}
if (tmp != 1){
fprintf (stderr, "The device doesn't support mono mode.\n");
exit (-1);
}
//sample_rate = 48000;
if (ioctl (fd, SNDCTL_DSP_SPEED, &sample_rate) == -1){
perror ("SNDCTL_DSP_SPEED");
exit (-1);
}
return fd;
}

View File

@ -1,3 +0,0 @@
void init_sound (void);
void play_code_element (int);
int open_audio_device (char *, int);

View File

@ -1,7 +1,7 @@
SRC = irmc.c sound.c
SRC = irmc.c cwprotocol.c beep.c util.c
OBJ = ${SRC:.c=.o}
LDFLAGS = -lm -lossaudio
CFLAGS = -Wall
LDFLAGS = -lportaudio -lpthread -lm
CFLAGS = -Wall -Wno-format-zero-length
INSTALLDIR = ${HOME}/bin
all: options irmc
@ -21,9 +21,12 @@ irmc: ${OBJ}
@echo CC -o $@
@${CC} -o $@ ${OBJ} ${LDFLAGS}
hex: ${OBJ}
@echo avr-gcc -o $@
avr-gcc -o $@ ${OBJ} ${LDFLAGS}
raspi:
@${CC} -c -DRASPI ${CFLAGS} ${SRC}
@${CC} -o irmc ${OBJ} ${LDFLAGS} -lwiringPi
java:
java -jar test/MorseKOB.jar
clean:
@echo cleaning

170
src/beep.c Normal file
View File

@ -0,0 +1,170 @@
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <unistd.h> // for usleep()
#include <portaudio.h>
#include "beep.h"
#ifdef RASPI
#define RASPI_AUDIO_LATENCY_FIX (30./5.) // https://app.assembla.com/spaces/portaudio/tickets/246-paex_sine-choppy-on-raspberry-pi---defaultlowoutputlatency-too-low/details
#else
#define RASPI_AUDIO_LATENCY_FIX (1.)
#endif
// http://stackoverflow.com/questions/7678470/generating-sound-of-a-particular-frequency-using-gcc-in-ubuntu
static PaStream *stream;
static paTestData data;
/* This routine will be called by the PortAudio engine when audio is needed.
** It may called at interrupt level on some machines so don't do anything
** that could mess up the system like calling malloc() or free().
*/
static int patestCallback( const void *inputBuffer, void *outputBuffer,
unsigned long framesPerBuffer,
const PaStreamCallbackTimeInfo* timeInfo,
PaStreamCallbackFlags statusFlags,
void *userData )
{
paTestData *data = (paTestData*)userData;
uint8_t *out = (uint8_t*)outputBuffer;
unsigned long i;
uint32_t freq = data->freq;
(void) timeInfo; /* Prevent unused variable warnings. */
(void) statusFlags;
(void) inputBuffer;
for( i=0; i<framesPerBuffer; i++ )
{
if(data->up_count > 0 && data->total_count == data->up_count) {
*out++ = 0x00;
continue;
}
data->total_count++;
if(freq != data->prev_freq) {
data->counter = 0;
}
if(freq) {
int overflow_max = SAMPLE_RATE / freq;
uint32_t data_cnt = data->counter % overflow_max;
if(data_cnt > overflow_max/2)
*out++ = 0xff;
else {
*out++ = 0x00;
}
data->counter++;
}
else {
data->counter = 0;
*out++ = 0;
}
data->prev_freq = freq;
}
return paContinue;
}
void buzzer_set_freq(int frequency)
{
data.up_count = 0; // do not stop!
data.freq = frequency;
}
void buzzer_beep(int frequency, int msecs)
{
data.total_count = 0;
data.up_count = SAMPLE_RATE * msecs / 1000;
data.freq = frequency;
}
int buzzer_start(void)
{
PaStreamParameters outputParameters;
PaError err;
err = Pa_Initialize();
if( err != paNoError ) goto error;
outputParameters.device = Pa_GetDefaultOutputDevice(); /* default output device */
outputParameters.channelCount = 1; /* stereo output */
outputParameters.sampleFormat = paUInt8; /* 32 bit floating point output */
outputParameters.suggestedLatency = Pa_GetDeviceInfo( outputParameters.device )->defaultLowOutputLatency * RASPI_AUDIO_LATENCY_FIX;
outputParameters.hostApiSpecificStreamInfo = NULL;
err = Pa_OpenStream(
&stream,
NULL, /* no input */
&outputParameters,
SAMPLE_RATE,
FRAMES_PER_BUFFER,
paClipOff, /* we won't output out of range samples so don't bother clipping them */
patestCallback,
&data );
if( err != paNoError ) goto error;
err = Pa_StartStream( stream );
if( err != paNoError ) goto error;
return err;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
int buzzer_stop()
{
PaError err = 0;
err = Pa_StopStream( stream );
if( err != paNoError ) goto error;
err = Pa_CloseStream( stream );
if( err != paNoError ) goto error;
Pa_Terminate();
return err;
error:
Pa_Terminate();
fprintf( stderr, "An error occured while using the portaudio stream\n" );
fprintf( stderr, "Error number: %d\n", err );
fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( err ) );
return err;
}
void msleep(int d){
usleep(d*1000);
}
int beep(double freq_hz, double duration_sec)
{
buzzer_set_freq(freq_hz);
msleep(duration_sec*1000.);
buzzer_set_freq(0.);
return 0;
}
int beep_init()
{
buzzer_start();
return 0;
}
int beep_test(void)
{
buzzer_start();
buzzer_set_freq(261);
msleep(250);
buzzer_set_freq(0);
buzzer_stop();
return 0;
}

32
src/beep.h Normal file
View File

@ -0,0 +1,32 @@
#include <stdio.h>
#include <math.h>
#include "portaudio.h"
#define NUM_SECONDS (5)
#define SAMPLE_RATE (44100)
#define FRAMES_PER_BUFFER (64)
#ifndef M_PI
#define M_PI (3.14159265)
#endif
typedef struct
{
uint32_t total_count;
uint32_t up_count;
uint32_t counter;
uint32_t prev_freq;
uint32_t freq;
} paTestData;
void buzzer_set_freq(int frequency);
void buzzer_beep(int frequency, int msecs);
int buzzer_start(void);
int buzzer_stop();
void msleep(int d);
int beep_test(void);
// compatibility to old interface
int beep(double freq_hz, double duration_sec);
int beep_init();

85
src/cwprotocol.c Normal file
View File

@ -0,0 +1,85 @@
#include <stdio.h>
#include <sys/socket.h>
#include "cwprotocol.h"
/* Global variables */
struct command_packet_format connect_packet = {CON, DEFAULT_CHANNEL};
struct command_packet_format disconnect_packet = {DIS, 0};
struct data_packet_format id_packet;
struct data_packet_format rx_data_packet;
struct data_packet_format tx_data_packet;
int tx_sequence = 0, rx_sequence;
int fd_socket;
int prepare_id (struct data_packet_format *id_packet, char *id)
{
id_packet->command = DAT;
id_packet->length = SIZE_DATA_PACKET_PAYLOAD;
snprintf(id_packet->id, SIZE_ID, id, "%s");
id_packet->sequence = 0;
id_packet->n = 0;
snprintf(id_packet->status, SIZE_ID, INTERFACE_VERSION);
id_packet->a21 = 1; /* These magic numbers was provided by Les Kerr */
id_packet->a22 = 755;
id_packet->a23 = 65535;
return 0;
}
int prepare_tx (struct data_packet_format *tx_packet, char *id)
{
int i;
tx_packet->command = DAT;
tx_packet->length = SIZE_DATA_PACKET_PAYLOAD;
snprintf(tx_packet->id, SIZE_ID, id, "%s");
tx_packet->sequence = 0;
tx_packet->n = 0;
for(i = 1; i < 51; i++)tx_packet->code[i] = 0;
tx_packet->a21 = 0; /* These magic numbers was provided by Les Kerr */
tx_packet->a22 = 755;
tx_packet->a23 = 16777215;
snprintf(tx_packet->status, SIZE_STATUS, "?"); // this shall include the sent character
return 0;
}
// connect to server and send my id.
void identifyclient(void)
{
tx_sequence++;
id_packet.sequence = tx_sequence;
send(fd_socket, &connect_packet, SIZE_COMMAND_PACKET, 0);
send(fd_socket, &id_packet, SIZE_DATA_PACKET, 0);
}
int send_latch (void)
{
int i;
tx_sequence++;
tx_data_packet.sequence = tx_sequence;
tx_data_packet.code[0] = -1;
tx_data_packet.code[1] = 1;
tx_data_packet.n = 2;
for(i = 0; i < 5; i++) send(fd_socket, &tx_data_packet, SIZE_DATA_PACKET, 0);
tx_data_packet.n = 0;
return 0;
}
int send_unlatch (void)
{
int i;
tx_sequence++;
tx_data_packet.sequence = tx_sequence;
tx_data_packet.code[0] = -1;
tx_data_packet.code[1] = 2;
tx_data_packet.n = 2;
for(i = 0; i < 5; i++) send(fd_socket, &tx_data_packet, SIZE_DATA_PACKET, 0);
tx_data_packet.n = 0;
return 0;
}

62
src/cwprotocol.h Normal file
View File

@ -0,0 +1,62 @@
#define INTERFACE_VERSION "irmc v0.3.3"
// Structures for the packets: unsigned short command
#define DIS 0x0002 // disconnect
#define DAT 0x0003
#define CON 0x0004 // connect
#define ACK 0x0005
#define SIZE_COMMAND_PACKET 4
#define SIZE_DATA_PACKET 496
#define SIZE_DATA_PACKET_PAYLOAD 492 // = SIZE_DATA_PACKET - SIZE_COMMAND_PACKET
#define SIZE_ID 128
#define SIZE_STATUS 128
#define SIZE_CODE 51
// This structure will be used to (dis-)connect to KOB servers
struct command_packet_format{
unsigned short command; // CON / DIS
unsigned short channel; // Channel number
};
// This structure will be used for id, rx and tx packets
struct data_packet_format{
unsigned short command;
unsigned short length;
char id[SIZE_ID];
char a1[4];
unsigned int sequence;
unsigned int a21;
unsigned int a22;
unsigned int a23;
signed int code[SIZE_CODE];
unsigned int n;
char status[SIZE_STATUS]; /* This is called version in MorseKob, in cwcom this transmits the sent character?! */
char a4[8];
};
// Define the packets used
#define DEFAULT_CHANNEL 103
/* Define functions provided by cwprotocol */
int prepare_id (struct data_packet_format *id_packet, char *id);
int prepare_tx (struct data_packet_format *tx_packet, char *id);
void identifyclient (void);
int send_latch (void);
int send_unlatch (void);
/* Define external struct for global variables */
extern struct command_packet_format connect_packet;
extern struct command_packet_format disconnect_packet;
extern struct data_packet_format id_packet;
extern struct data_packet_format rx_data_packet;
extern struct data_packet_format tx_data_packet;
extern int tx_sequence, rx_sequence;
extern int fd_socket;

382
src/irmc.c Normal file
View File

@ -0,0 +1,382 @@
/* irmc - internet relay morsecode client */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <math.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <arpa/inet.h>
#define MAXDATASIZE 1024 // max number of bytes we can get at once
#include "cwprotocol.h"
#include "beep.h"
#include "util.h"
// http://raspberrypiguide.de/howtos/raspberry-pi-gpio-how-to/
#ifdef RASPI
#include <wiringPi.h>
#define TX_RASPI_PIN 5
#endif
int serial_status = 0, fd_serial, numbytes;
double tx_timeout = 0;
long tx_timer = 0;
#define TX_WAIT 5000
#define TX_TIMEOUT 240.0
#define KEEPALIVE_CYCLE 100
/* TX Methods */
#define TX_NONE 0
//#define TX_SERIAL 1
//#define TX_KEYBOARD 2 // not implemented yet
#define TX_RASPI 3
long key_press_t1;
long key_release_t1;
int last_message = 0;
char last_sender[16];
/* settings */
int translate = 1;
int audio_status = 1;
// disconnect from the server
void inthandler(int sig)
{
signal(sig, SIG_IGN);
send(fd_socket, &disconnect_packet, SIZE_COMMAND_PACKET, 0);
close(fd_socket);
#ifdef TX_SERIAL
close(fd_serial);
#endif
exit(1);
}
void txloop (void)
{
key_press_t1 = fastclock();
tx_timeout = 0;
for(;;){
tx_data_packet.n++;
tx_data_packet.code[tx_data_packet.n - 1] =
(int) ((key_press_t1 - key_release_t1) * -1);
#ifdef DEBUG
printf("space: %i\n", tx_data_packet.code[tx_data_packet.n -1]);
#endif
#ifdef TX_SERIAL
while(serial_status & TIOCM_DSR) ioctl(fd_serial, TIOCMGET, &serial_status);
#endif
#ifdef RASPI
while(digitalRead(TX_RASPI_PIN)==1) { }
#endif
key_release_t1 = fastclock();
tx_data_packet.n++;
tx_data_packet.code[tx_data_packet.n - 1] =
(int) ((key_release_t1 - key_press_t1) * 1);
#ifdef DEBUG
printf("mark: %i\n", tx_data_packet.code[tx_data_packet.n -1]);
#endif
while(1){
#ifdef TX_SERIAL
ioctl(fd_serial, TIOCMGET, &serial_status);
if(serial_status & TIOCM_DSR) break;
#endif
#ifdef RASPI
if(digitalRead(TX_RASPI_PIN)==1) break;
#endif
tx_timeout = fastclock() - key_release_t1;
if(tx_timeout > TX_TIMEOUT) return;
}
key_press_t1 = fastclock();
if(tx_data_packet.n == SIZE_CODE) {
printf("irmc: warning packet is full.\n");
return;
}
}
}
void message(int msg)
{
switch(msg){
case 1:
if(last_message == msg) return;
if(last_message == 2) printf("\n");
last_message = msg;
printf("irmc: transmitting...\n");
break;
case 2:
if(last_message == msg && strncmp(last_sender, rx_data_packet.id, 3) == 0) return;
else {
if(last_message == 2) printf("\n");
last_message = msg;
strncpy(last_sender, rx_data_packet.id, 3);
printf("irmc: receiving...(%s)\n", rx_data_packet.id);
}
break;
case 3:
printf("irmc: circuit was latched by %s.\n", rx_data_packet.id);
break;
case 4:
printf("irmc: circuit was unlatched by %s.\n", rx_data_packet.id);
break;
default:
break;
}
fflush(0);
}
/* Main Loop */
int main(int argc, char *argv[])
{
char buf[MAXDATASIZE];
struct addrinfo hints, *servinfo, *p;
int rv, i;
char s[INET6_ADDRSTRLEN];
int keepalive_t = 0;
char hostname[64];
char port[16];
int channel;
char id[SIZE_ID];
char serialport[64];
// Set default values
snprintf(hostname, 64, "mtc-kob.dyndns.org");
snprintf(port, 16, "7890");
channel = 103;
snprintf(id, SIZE_ID, "irmc-default");
snprintf(serialport, 64, "");
// Read commandline
opterr = 0;
int c;
while ((c = getopt (argc, argv, "h:p:c:i:s:")) != -1)
{
switch (c)
{
case 'h':
snprintf(hostname, 64, "%s", optarg);
break;
case 'p':
snprintf(port, 16, "%s", optarg);
break;
case 'c':
channel = atoi (optarg);
break;
case 'i':
snprintf(id, SIZE_ID, "%s", optarg);
break;
case 's':
snprintf(serialport, 64, "%s", optarg);
break;
case '?':
fprintf(stderr, "irmc - Internet Relay Morse Code\n\n");
fprintf(stderr, "usage: irmc [arguments]\n\n");
fprintf(stderr, "Arguments:\n\n");
fprintf(stderr, " -h [hostname] Hostname of morsekob server. Default: %s\n", hostname);
fprintf(stderr, " -p [port] Port of morsekob server. Default: %s\n", port);
fprintf(stderr, " -c [channel] Channel. Default: %d\n", channel);
fprintf(stderr, " -i [id] My ID. Default: %s\n", id);
fprintf(stderr, " -s [serialport] Serial port device name. Example: /dev/tty.usbserial Default: \"%s\"\n", serialport);
return 1;
default:
abort ();
}
}
// Preparing connection
fprintf(stderr, "irmc - Internet Relay Morse Code\n\n");
fprintf(stderr, "Connecting to %s:%s on channel %d with ID %s.\n", hostname, port, channel, id);
prepare_id (&id_packet, id);
prepare_tx (&tx_data_packet, id);
connect_packet.channel = channel;
signal(SIGINT, inthandler);
memset(&hints, 0, sizeof hints);
hints.ai_family = AF_UNSPEC; /* ipv4 or ipv6 */
hints.ai_socktype = SOCK_DGRAM;
if ((rv = getaddrinfo(hostname, port, &hints, &servinfo)) != 0) {
fprintf(stderr, "getaddrinfo: %s\n", gai_strerror(rv));
return 1;
}
/* Find the first free socket */
for(p = servinfo; p != NULL; p = p->ai_next) {
if ((fd_socket = socket(p->ai_family, p->ai_socktype,
p->ai_protocol)) == -1) {
perror("irmc: socket");
continue;
}
if (connect(fd_socket, p->ai_addr, p->ai_addrlen) == -1) {
close(fd_socket);
perror("irmc: connect");
continue;
}
break;
}
fcntl(fd_socket, F_SETFL, O_NONBLOCK);
if (p == NULL) {
fprintf(stderr, "Failed to connect.\n");
return 2;
}
inet_ntop(p->ai_family, get_in_addr((struct sockaddr *)p->ai_addr),
s, sizeof s);
fprintf(stderr, "Connected to %s.\n", s);
#ifdef TX_SERIAL
fd_serial = open(serialport, O_RDWR | O_NOCTTY | O_NDELAY);
if(fd_serial == -1) {
fprintf(stderr,"Unable to open serial port %s.\n", serialport);
}
#endif
#ifdef RASPI
if (wiringPiSetup() == -1)
{
fprintf(stderr,"Unable to setup wiringPi for PIN %d\n", TX_RASPI_PIN);
exit (1);
}
pinMode(TX_RASPI_PIN, INPUT);
#endif
freeaddrinfo(servinfo); /* all done with this structure */
key_release_t1 = fastclock();
identifyclient();
beep_init();
/* Main Loop */
for(;;) {
if(tx_timer == 0)
if((numbytes = recv(fd_socket, buf, MAXDATASIZE-1, 0)) == -1)
usleep(250);
if(numbytes == SIZE_DATA_PACKET && tx_timer == 0){
memcpy(&rx_data_packet, buf, SIZE_DATA_PACKET);
#if DEBUG
printf("length: %i\n", rx_data_packet.length);
printf("id: %s\n", rx_data_packet.id);
printf("sequence no.: %i\n", rx_data_packet.sequence);
printf("version: %s\n", rx_data_packet.status);
printf("n: %i\n", rx_data_packet.n);
printf("code:\n");
for(i = 0; i < SIZE_CODE; i++)printf("%i ", rx_data_packet.code[i]); printf("\n");
#endif
if(rx_data_packet.n > 0 && rx_sequence != rx_data_packet.sequence){
message(2);
if(translate == 1){
printf("%s", rx_data_packet.status);
fflush(0);
}
rx_sequence = rx_data_packet.sequence;
for(i = 0; i < rx_data_packet.n; i++){
switch(rx_data_packet.code[i]){
case 1:
message(3);
break;
case 2:
message(4);
break;
default:
if(audio_status == 1)
{
int length = rx_data_packet.code[i];
if(length == 0 || abs(length) > 2000) {
}
else
{
if(length < 0) {
beep(0.0, abs(length)/1000.);
}
else
{
beep(1000.0, length/1000.);
}
}
}
break;
}
}
}
}
if(tx_timer > 0) tx_timer--;
if(tx_data_packet.n > 1 ){
tx_sequence++;
tx_data_packet.sequence = tx_sequence;
for(i = 0; i < 5; i++) send(fd_socket, &tx_data_packet, SIZE_DATA_PACKET, 0);
#if DEBUG
printf("irmc: sent data packet.\n");
#endif
tx_data_packet.n = 0;
}
#ifdef TX_SERIAL
ioctl(fd_serial,TIOCMGET, &serial_status);
if(serial_status & TIOCM_DSR){
txloop();
tx_timer = TX_WAIT;
message(1);
}
#endif
#ifdef RASPI
if(digitalRead(5)==1){
txloop();
tx_timer = TX_WAIT;
message(1);
}
#endif
if(keepalive_t < 0 && tx_timer == 0){
#if DEBUG
printf("keep alive sent.\n");
#endif
identifyclient();
keepalive_t = KEEPALIVE_CYCLE;
}
if(tx_timer == 0) {
keepalive_t--;
usleep(50);
}
if(kbhit() && tx_timer == 0){
getchar(); /* flush the buffer */
}
} /* End of mainloop */
send(fd_socket, &disconnect_packet, SIZE_COMMAND_PACKET, 0);
close(fd_socket);
#ifdef TX_SERIAL
close(fd_serial);
#endif
buzzer_stop();
exit(0);
}

BIN
src/test/MorseKOB.jar Executable file

Binary file not shown.

57
src/util.c Normal file
View File

@ -0,0 +1,57 @@
#include "util.h"
/* portable time, as listed in https://gist.github.com/jbenet/1087739 */
void current_utc_time(struct timespec *ts) {
#ifdef __MACH__ // OS X does not have clock_gettime, use clock_get_time
clock_serv_t cclock;
mach_timespec_t mts;
host_get_clock_service(mach_host_self(), CALENDAR_CLOCK, &cclock);
clock_get_time(cclock, &mts);
mach_port_deallocate(mach_task_self(), cclock);
ts->tv_sec = mts.tv_sec;
ts->tv_nsec = mts.tv_nsec;
#else
clock_gettime(CLOCK_REALTIME, ts);
#endif
}
/* a better clock() in milliseconds */
long fastclock(void)
{
struct timespec t;
long r;
current_utc_time (&t);
r = t.tv_sec * 1000;
r = r + t.tv_nsec / 1000000;
return r;
}
int kbhit (void)
{
struct timeval tv;
fd_set rdfs;
tv.tv_sec = 0;
tv.tv_usec = 0;
FD_ZERO(&rdfs);
FD_SET (STDIN_FILENO, &rdfs);
select (STDIN_FILENO+1, &rdfs, NULL, NULL, &tv);
return FD_ISSET(STDIN_FILENO, &rdfs);
}
/* get sockaddr, IPv4 or IPv6: */
void *get_in_addr(struct sockaddr *sa)
{
if (sa->sa_family == AF_INET) {
return &(((struct sockaddr_in*)sa)->sin_addr);
}
return &(((struct sockaddr_in6*)sa)->sin6_addr);
}

30
src/util.h Normal file
View File

@ -0,0 +1,30 @@
#include <time.h>
#include <sys/time.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include <netdb.h>
#include <sys/types.h>
#include <netinet/in.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
#include <math.h>
#include <fcntl.h>
#include <pthread.h>
#include <signal.h>
#include <arpa/inet.h>
#ifdef __MACH__
#include <mach/clock.h>
#include <mach/mach.h>
#endif
void current_utc_time(struct timespec *ts);
long fastclock(void);
int kbhit (void);
void *get_in_addr(struct sockaddr *sa);