Compare commits

..

No commits in common. "master" and "v0.1" have entirely different histories.
master ... v0.1

18 changed files with 585 additions and 872 deletions

2
.gitignore vendored
View File

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

View File

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

View File

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

View File

@ -1,44 +1,41 @@
irmc - Internet Relay Morse Code
================================
IRMC stands for Internet Relay Morse Code and is an implementation of [MOIP](http://8ch9azbsfifz.github.io/moip/).
=== WIP - Snipplets ===
How to use:
# 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
1 usage: irmc [hostname] [port] [channel] [id] [serialport]
./irmc mtc-kob.dyndns.org 7890 103 123 /dev/tty.usbserial
faeroes.sdf.org.7890
## On OSX
brew install portaudio
make
TBD: Driver:
serial - 2usb!
# 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).
TBD: OSX - howto install dependencies
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)
=== 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.
| 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|
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
# 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
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 ===
Code Quality
============
This is experimental code.

Binary file not shown.

Binary file not shown.

450
irmc.c Normal file
View File

@ -0,0 +1,450 @@
/* 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);
}

Binary file not shown.

94
sound.c Normal file
View File

@ -0,0 +1,94 @@
/* 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;
}

3
sound.h Normal file
View File

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

View File

@ -1,170 +0,0 @@
#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;
}

View File

@ -1,32 +0,0 @@
#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();

View File

@ -1,85 +0,0 @@
#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;
}

View File

@ -1,62 +0,0 @@
#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;

View File

@ -1,382 +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 <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);
}

Binary file not shown.

View File

@ -1,57 +0,0 @@
#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);
}

View File

@ -1,30 +0,0 @@
#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);