diff options
Diffstat (limited to 'src/fodtmf-send.c')
| -rw-r--r-- | src/fodtmf-send.c | 557 |
1 files changed, 276 insertions, 281 deletions
diff --git a/src/fodtmf-send.c b/src/fodtmf-send.c index 0c3709e..2fbe70c 100644 --- a/src/fodtmf-send.c +++ b/src/fodtmf-send.c @@ -51,12 +51,12 @@ /** * The process's name. */ -static const char* argv0; +static const char *argv0; /** * Audio descriptor. */ -static snd_pcm_t* sound_handle = NULL; +static snd_pcm_t *sound_handle = NULL; /** * Audio playback buffer for each nibble. @@ -70,7 +70,7 @@ static int parity = 3; /** * Whether to add an additional parity tone (of all - * data tones) in addition to those numerated by `parity`. + * data tones) in addition to those enumerated by `parity`. */ static int use_extra_parity = 0; @@ -87,12 +87,12 @@ static double redundant_freq_mul = 0; /** * Data buffer used for error correcting code support. */ -static int* data; +static int *data; /** * Code buffer used for error correcting code support. */ -static int* code; +static int *code; /** * The number elements that can be stored in `data`. @@ -109,7 +109,7 @@ static int code_n; * rather than sending it to the audio subsystem. * * This is available for developers of the receiver. - * It is not intend to be used for anything else. + * It is not intended to be used for anything else. */ static int output_fd = -1; @@ -121,9 +121,10 @@ static int output_fd = -1; * * @param signo The received signal. */ -static void signoop(int signo) +static void +signoop(int signo) { - (void) signo; + (void) signo; } @@ -134,44 +135,48 @@ static void signoop(int signo) * @param low Output parameter for the lower frequency. * @param high Output parameter for the higher frequency. */ -static void get_freq(int nibble, int* low, int* high) +static void +get_freq(int nibble, int *low, int *high) { - static const int LOW[] = { 697, 770, 852, 941 }; - static const int HIGH[] = { 1209, 1336, 1477, 1663 }; - - *low = LOW[(nibble >> 0) & 0x03]; - *high = HIGH[(nibble >> 2) & 0x03]; + static const int LOW[] = { 697, 770, 852, 941 }; + static const int HIGH[] = { 1209, 1336, 1477, 1663 }; + + *low = LOW[(nibble >> 0) & 0x03]; + *high = HIGH[(nibble >> 2) & 0x03]; } /** * Initialise to before for each nibble. */ -static void init_buffers(void) +static void +init_buffers(void) { #define GENERATE_TONE(tone) sin(2 * M_PI * ((double)i / (SAMPLE_RATE / (tone)))) - - size_t i; - UTYPE* buffer; - int j, low, high; - - for (j = 0; j < 16; j++) - { - buffer = buffers[j]; - get_freq(j, &low, &high); - - if (use_redundant_freq) - for (i = 0; i < N; i++) - buffer[i] = (GENERATE_TONE(low) + - GENERATE_TONE(high) + - GENERATE_TONE(low * redundant_freq_mul) + - GENERATE_TONE(high * redundant_freq_mul)) * - (SMAX / 4) - SMIN; - else - for (i = 0; i < N; i++) - buffer[i] = (GENERATE_TONE(low) + GENERATE_TONE(high)) * - (SMAX / 2) - SMIN; - } + + size_t i; + UTYPE *buffer; + int j, low, high; + + for (j = 0; j < 16; j++) { + buffer = buffers[j]; + get_freq(j, &low, &high); + + if (use_redundant_freq) { + for (i = 0; i < N; i++) { + buffer[i] = (GENERATE_TONE(low) + + GENERATE_TONE(high) + + GENERATE_TONE(low * redundant_freq_mul) + + GENERATE_TONE(high * redundant_freq_mul)) * + (SMAX / 4) - SMIN; + } + } else { + for (i = 0; i < N; i++) { + buffer[i] = (GENERATE_TONE(low) + GENERATE_TONE(high)) * + (SMAX / 2) - SMIN; + } + } + } } @@ -181,40 +186,38 @@ static void init_buffers(void) * @param n The nibble. * @return 0 on success, -1 on error. */ -static int send_nibble(int n) +static int +send_nibble(int n) { - UTYPE* buffer = buffers[n]; - snd_pcm_sframes_t frames; - int r; - - if (output_fd >= 0) - { - char* buf = (char*)buffer; - size_t ptr = 0; - ssize_t wrote; - while (ptr < N) - { - wrote = write(output_fd, buf + ptr, N - ptr); - if (wrote < 0) - return -1; - ptr += (size_t)write; + UTYPE *buffer = buffers[n]; + snd_pcm_sframes_t frames; + int r; + + if (output_fd >= 0) { + char *buf = (char *)buffer; + size_t ptr = 0; + ssize_t wrote; + while (ptr < N) { + wrote = write(output_fd, buf + ptr, N - ptr); + if (wrote < 0) + return -1; + ptr += (size_t)wrote; + } + return 0; } - return 0; - } - - r = frames = snd_pcm_writei(sound_handle, buffer, N); - if (frames < 0) - r = frames = snd_pcm_recover(sound_handle, r, 0 /* do not print error reason? */); - if (r < 0) - { - fprintf(stderr, "%s: snd_pcm_writei: %s\n", argv0, snd_strerror(r)); - errno = 0; - return -1; - } - if ((r > 0) && ((size_t)r < N)) - printf("%s: short write: expected %zu, wrote %zu\n", argv0, N, (size_t)frames); - - return 0; + + r = frames = snd_pcm_writei(sound_handle, buffer, N); + if (frames < 0) + r = frames = snd_pcm_recover(sound_handle, r, 0 /* do not print error reason? */); + if (r < 0) { + fprintf(stderr, "%s: snd_pcm_writei: %s\n", argv0, snd_strerror(r)); + errno = 0; + return -1; + } + if (r > 0 && (size_t)r < N) + printf("%s: short write: expected %zu, wrote %zu\n", argv0, N, (size_t)frames); + + return 0; } @@ -224,14 +227,15 @@ static int send_nibble(int n) * @param c The byte. * @return 0 on success, -1 on error. */ -static int send_byte(int c) +static int +send_byte(int c) { #ifdef DEBUG - fprintf(stderr, "%s: sending byte: %i\n", argv0, c); + fprintf(stderr, "%s: sending byte: %i\n", argv0, c); #endif - if (send_nibble((c >> 0) & 0x0F)) return -1; - if (send_nibble((c >> 4) & 0x0F)) return -1; - return 0; + if (send_nibble((c >> 0) & 0x0F)) return -1; + if (send_nibble((c >> 4) & 0x0F)) return -1; + return 0; } @@ -245,68 +249,67 @@ static int send_byte(int c) * * @param c The byte, the negative of that byte (intended * only for `CHAR_END` and `CHAR_CANCEL`) to fill - * the remained of the buffer with the byte. + * the remainder of the buffer with the byte. * Note that if a negative value is used, it is - * no necessary that anything will happen. + * not necessary that anything will happen. * @return 0 on success, -1 on error. */ -static int send_byte_with_ecc(int c) +static int +send_byte_with_ecc(int c) { - static int ptr = 0; - int i, j, d, p; - - if (parity < 2) - { - if (c < 0) + static int ptr = 0; + int i, j, d, p; + + if (parity < 2) { + if (c < 0) + return 0; + if (send_byte(c)) + return -1; + if (parity) + if (send_byte(c)) + return -1; + if (use_extra_parity) + if (send_byte(c)) + return -1; + return 0; + } + + /* Fill buffer. */ + if (c < 0) { + if (ptr > 0) + while (ptr < data_n) + data[ptr++] = -c; + } + else { + data[ptr++] = c; + } + + /* Is it full? */ + if (ptr < data_n) + return 0; + ptr = 0; + + /* Hamming code. */ + memset(code, 0, code_n * sizeof(*code)); + for (i = 1, j = 0; i <= (1 << parity) - 1; i++) { + if ((i & -i) == i) + continue; + for (d = i, p = 0; d; d >>= 1, p++) + if (d & 1) + code[(1 << p) - 1] ^= data[j]; + code[i - 1] = data[j]; + j++; + } + if (use_extra_parity) + for (i = 0; i < data_n; i++) + code[(1 << parity) - 1] ^= data[i]; + + /* Transmit. */ + for (i = 0; i < code_n; i++) + if (send_byte(code[i])) + return -1; + return 0; - if (send_byte(c)) - return -1; - if (parity) - if (send_byte(c)) - return -1; - if (use_extra_parity) - if (send_byte(c)) - return -1; - return 0; - } - - /* Fill buffer. */ - if (c < 0) - { - if (ptr > 0) - while (ptr < data_n) - data[ptr++] = -c; - } - else - data[ptr++] = c; - - /* Is it full? */ - if (ptr < data_n) - return 0; - ptr = 0; - - /* Hamming code. */ - memset(code, 0, code_n * sizeof(*code)); - for (i = 1, j = 0; i <= (1 << parity) - 1; i++) - { - if ((i & -i) == i) - continue; - for (d = i, p = 0; d; d >>= 1, p++) - if (d & 1) - code[(1 << p) - 1] ^= data[j]; - code[i - 1] = data[j]; - j++; - } - if (use_extra_parity) - for (i = 0; i < data_n; i++) - code[(1 << parity) - 1] ^= data[i]; - - /* Transmit. */ - for (i = 0; i < code_n; i++) - if (send_byte(code[i])) - return -1; - - return 0; } @@ -317,26 +320,26 @@ static int send_byte_with_ecc(int c) * @param n The number of bytes in the chunk. * @return 0 on success, -1 on failure. */ -static int send_chunk(char* buf, size_t n) +static int +send_chunk(char *buf, size_t n) { - size_t i; - int c; - - for (i = 0; i < n; i++) - { - c = buf[i]; - if ((c == CHAR_ESCAPE) || (c == CHAR_CANCEL) || (c == CHAR_END)) - if (send_byte_with_ecc(CHAR_ESCAPE)) - goto qfile; - if (send_byte_with_ecc(c)) - goto qfile; - } - - return 0; - qfile: - errno = 0; - fail: - return -1; + size_t i; + int c; + + for (i = 0; i < n; i++) { + c = buf[i]; + if (c == CHAR_ESCAPE || c == CHAR_CANCEL || c == CHAR_END) + if (send_byte_with_ecc(CHAR_ESCAPE)) + goto qfile; + if (send_byte_with_ecc(c)) + goto qfile; + } + + return 0; +qfile: + errno = 0; +fail: + return -1; } @@ -345,23 +348,23 @@ static int send_chunk(char* buf, size_t n) * * @return 0 on success, -1 on failure. */ -static int send_file(void) +static int +send_file(void) { - char buf[1024]; - ssize_t n; - - for (;;) - { - n = read(STDIN_FILENO, buf, sizeof(buf)); - if (n < 0) goto fail; - if (n == 0) break; - if (send_chunk(buf, (size_t)n)) - goto fail; - } - - return 0; - fail: - return -1; + char buf[1024]; + ssize_t n; + + for (;;) { + n = read(STDIN_FILENO, buf, sizeof(buf)); + if (n < 0) goto fail; + if (n == 0) break; + if (send_chunk(buf, (size_t)n)) + goto fail; + } + + return 0; +fail: + return -1; } @@ -370,39 +373,39 @@ static int send_file(void) * * @return 0 on success, -1 on failure. */ -static int send_term(void) +static int +send_term(void) { - char* buf = NULL; - size_t size = 0; - size_t ptr = 0; - ssize_t n; - void* new; - int saved_errno; - - for (;;) - { - if (ptr == size) - { - size = size ? (size << 1) : 128; - new = realloc(buf, size); - if (new == NULL) - goto fail; - buf = new; + char *buf = NULL; + size_t size = 0; + size_t ptr = 0; + ssize_t n; + void *new; + int saved_errno; + + for (;;) { + if (ptr == size) { + size = size ? (size << 1) : 128; + new = realloc(buf, size); + if (!new) + goto fail; + buf = new; + } + n = read(STDIN_FILENO, buf + ptr, size - ptr); + if (n < 0) goto fail; + if (n == 0) break; + ptr += (size_t)n; } - n = read(STDIN_FILENO, buf + ptr, size - ptr); - if (n < 0) goto fail; - if (n == 0) break; - ptr += (size_t)n; - } - if (send_chunk(buf, ptr)) - goto fail; + if (send_chunk(buf, ptr)) + goto fail; - return 0; - fail: - saved_errno = errno; - free(buf); - errno = saved_errno; - return -1; + return 0; + +fail: + saved_errno = errno; + free(buf); + errno = saved_errno; + return -1; } @@ -413,91 +416,83 @@ static int send_term(void) * @param argv Command line arguments. * @return 0 on success, 1 on failure. */ -int main(int argc, char* argv[]) +int +main(int argc, char *argv[]) { - struct sigaction act; - int r, rc = 1; - - /* Parse command line. */ - argv0 = argc ? argv[0] : ""; - for (;;) - { - r = getopt (argc, argv, "f:pr:o:"); - if (r == -1) - break; - else if (r == 'f') use_redundant_freq = 1, redundant_freq_mul = atof(optarg); - else if (r == 'p') use_extra_parity = 1; - else if (r == 'r') parity = atoi(optarg); - else if (r == 'o') output_fd = atoi(optarg); - else if (r != '?') - abort(); - } - - /* Set up signal handling. */ - siginterrupt(SIGTERM, 1); - siginterrupt(SIGQUIT, 1); - siginterrupt(SIGINT, 1); - siginterrupt(SIGHUP, 1); - sigemptyset(&(act.sa_mask)); - act.sa_handler = signoop; - act.sa_flags = 0; - sigaction(SIGTERM, &act, NULL); - sigaction(SIGQUIT, &act, NULL); - sigaction(SIGHUP, &act, NULL); - sigprocmask(SIG_SETMASK, &(act.sa_mask), NULL); - - /* Generate the tones to play. */ - init_buffers(); - /* Generate buffers for error correcting code. */ - data_n = (1 << parity) - parity - 1; - code_n = (1 << parity) - 1 + use_extra_parity; - data = alloca(data_n * sizeof(*data)); - code = alloca(code_n * sizeof(*code)); + struct sigaction act; + int r, rc = 1; - /* Set up audio. */ - if (output_fd >= 0) - goto no_audio; - r = snd_pcm_open(&sound_handle, "default", SND_PCM_STREAM_PLAYBACK, 0); - if (r < 0) - return fprintf(stderr, "%s: snd_pcm_open: %s\n", *argv, snd_strerror(r)), 1; - if (sound_handle == NULL) - perror("snd_pcm_open"); - /* Configure audio. */ - r = snd_pcm_set_params(sound_handle, FORMAT, SND_PCM_ACCESS_RW_INTERLEAVED, 1 /* channels */, - SAMPLE_RATE, 1 /* allow resampling? */, LATENCY); - if (r < 0) - return fprintf(stderr, "%s: snd_pcm_set_params: %s\n", *argv, snd_strerror(r)), 1; - no_audio: - - /* Send message. */ - if (isatty(STDIN_FILENO)) - { - if (send_term()) - goto fail; - } - else - if (send_file()) - goto fail; - - /* Mark end of transmission. */ - if (send_byte_with_ecc(CHAR_END)) goto cleanup; - if (send_byte_with_ecc(-CHAR_END)) goto cleanup; - - /* Done! */ - rc = 0; - goto cleanup; - fail: - if (errno) - perror(argv0); - cleanup: - /* Mark aborted transmission. */ - if (rc) - { - send_byte_with_ecc(CHAR_CANCEL); - send_byte_with_ecc(-CHAR_CANCEL); - } - if (output_fd >= 0) - snd_pcm_close(sound_handle); - return rc; -} + /* Parse command line. */ + argv0 = argc ? argv[0] : ""; + for (;;) { + r = getopt (argc, argv, "f:pr:o:"); + if (r == -1) + break; + else if (r == 'f') use_redundant_freq = 1, redundant_freq_mul = atof(optarg); + else if (r == 'p') use_extra_parity = 1; + else if (r == 'r') parity = atoi(optarg); + else if (r == 'o') output_fd = atoi(optarg); + else if (r != '?') + abort(); + } + + /* Set up signal handling. */ + siginterrupt(SIGTERM, 1); + siginterrupt(SIGQUIT, 1); + siginterrupt(SIGINT, 1); + siginterrupt(SIGHUP, 1); + sigemptyset(&(act.sa_mask)); + act.sa_handler = signoop; + act.sa_flags = 0; + sigaction(SIGTERM, &act, NULL); + sigaction(SIGQUIT, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigprocmask(SIG_SETMASK, &(act.sa_mask), NULL); + + /* Generate the tones to play. */ + init_buffers(); + /* Generate buffers for error correcting code. */ + data_n = (1 << parity) - parity - 1; + code_n = (1 << parity) - 1 + use_extra_parity; + data = alloca(data_n * sizeof(*data)); + code = alloca(code_n * sizeof(*code)); + + /* Set up audio. */ + if (output_fd >= 0) + goto no_audio; + r = snd_pcm_open(&sound_handle, "default", SND_PCM_STREAM_PLAYBACK, 0); + if (r < 0) + return fprintf(stderr, "%s: snd_pcm_open: %s\n", *argv, snd_strerror(r)), 1; + if (sound_handle == NULL) + perror("snd_pcm_open"); + /* Configure audio. */ + r = snd_pcm_set_params(sound_handle, FORMAT, SND_PCM_ACCESS_RW_INTERLEAVED, 1 /* channels */, + SAMPLE_RATE, 1 /* allow resampling? */, LATENCY); + if (r < 0) + return fprintf(stderr, "%s: snd_pcm_set_params: %s\n", *argv, snd_strerror(r)), 1; +no_audio: + /* Send message. */ + if (isatty(STDIN_FILENO) ? send_term() : send_file()) + goto fail; + + /* Mark end of transmission. */ + if (send_byte_with_ecc(CHAR_END)) goto cleanup; + if (send_byte_with_ecc(-CHAR_END)) goto cleanup; + + /* Done! */ + rc = 0; + goto cleanup; +fail: + if (errno) + perror(argv0); +cleanup: + /* Mark aborted transmission. */ + if (rc) { + send_byte_with_ecc(CHAR_CANCEL); + send_byte_with_ecc(-CHAR_CANCEL); + } + if (output_fd >= 0) + snd_pcm_close(sound_handle); + return rc; +} |
