| #include <fcntl.h> |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| #include <sys/stat.h> |
| #include <unistd.h> |
| |
| #include "RAS_lib.h" |
| |
| #define RAS_CMD_MASK 0x07 |
| #define RAS_START_CMD 0x04 |
| #define RAS_DATA_TIC1_CMD 0x01 |
| #define RAS_STOP_CMD 0x02 |
| #define RAS_DATA_RAW_CMD 0x03 |
| |
| #define FRAME_TYPE(data) (data[3] & RAS_CMD_MASK) |
| |
| #define PDU_LENGTH 20 + 20 + 20 + 20 |
| |
| // read_with_length reads a byte from the provided fd, then reads that many |
| // bytes into buf, unless more bytes are to be read than size. The number of |
| // bytes actually read is returned. On error, a value less than 0 is returned. |
| int read_with_length(int fd, char *buf, int size) { |
| char to_read; |
| |
| int len = read(fd, &to_read, 1); |
| if (len != 1) { |
| printf("read_with_length: read %d bytes, expecting 1\n", len); |
| return 0; |
| } |
| |
| if (size < to_read) { |
| printf( |
| "read_with_length: file wants to read in %d bytes, but there is only " |
| "space for %d\n", |
| to_read, size); |
| // This puts the file in a bad state (the next byte is no longer a length |
| // byte), but good enough for now. |
| return -1; |
| } |
| |
| len = read(fd, buf, to_read); |
| if (len < to_read) { |
| printf("read_with_length: got %d bytes, but wanted %d bytes\n", len, to_read); |
| return -1; |
| } |
| return len; |
| } |
| |
| int parse_pdu(char *pdu, int len) { |
| if (len < 4) { |
| return 0; |
| } |
| |
| int sequence = (pdu[3] >> 3) & 0x1f; |
| printf("pdu received: sequence %d\n", sequence); |
| |
| switch(FRAME_TYPE(pdu)) { |
| case RAS_START_CMD: |
| printf(" audio start\n"); |
| break; |
| case RAS_DATA_TIC1_CMD: |
| printf(" actual audio frame\n"); |
| break; |
| case RAS_STOP_CMD: |
| printf(" audio stop\n"); |
| break; |
| default: |
| printf(" unhandled pdu frame_type=%d\n", FRAME_TYPE(pdu)); |
| break; |
| } |
| |
| return 1; |
| } |
| |
| struct pdu_accumulator { |
| int seen_first_packet; |
| int cur_idx; |
| char pdu[PDU_LENGTH]; |
| }; |
| |
| void reset_pdu_accumulator(struct pdu_accumulator *a) { |
| a->seen_first_packet = 0; |
| a->cur_idx = 0; |
| memset(&(a->pdu), 0, PDU_LENGTH); |
| } |
| |
| |
| // accumulate_pdu accepts one 23 byte packet from the device, and returns true |
| // if a complete PDU has been assembled. |
| int accumulate_pdu(struct pdu_accumulator *a, char data[23]) { |
| // printf("seen_first=%d cur_idx=%d\n", a->seen_first_packet, a->cur_idx); |
| |
| if(!a->seen_first_packet) { |
| if(FRAME_TYPE(data) == RAS_DATA_TIC1_CMD) { |
| a->seen_first_packet = 1; |
| a->cur_idx++; |
| memcpy(a->pdu, data, 23); |
| } else { |
| printf(" ignoring unexpected packet (type %d)\n", FRAME_TYPE(data)); |
| } |
| return 0; |
| } |
| |
| if(a->seen_first_packet) { |
| // if(FRAME_TYPE(data) != RAS_DATA_RAW_CMD) { |
| // printf("expecting raw data, but got frame type %d\n", FRAME_TYPE(data)); |
| // reset_pdu_accumulator(a); |
| // return 0; |
| // } |
| |
| // copy everything but the first 3 bytes into the result packet 0, read |
| // above, is 23 bytes. the next 3 are 20 bytes (with the first 3 bytes |
| // ignored). those 4 packets make a complete PDU. |
| if(a->cur_idx > 0 && a->cur_idx < 4) { |
| memcpy(&(a->pdu[a->cur_idx*20]), &data[3], 20); |
| a->cur_idx++; |
| } else { |
| printf(" cur_idx %d out of range\n", a->cur_idx); |
| } |
| } |
| |
| return a->cur_idx > 3; |
| } |
| |
| |
| int main(int argc, char **argv) { |
| // TI ignores the error code from RAS_Init. I will too, I guess. |
| RAS_Init(1); |
| |
| int input = open("out", O_RDONLY); |
| if (input < 0) { |
| perror("open ./out"); |
| return 1; |
| } |
| |
| struct pdu_accumulator a; |
| reset_pdu_accumulator(&a); |
| char data[64]; |
| |
| chunk: |
| while (1) { |
| int read = read_with_length(input, data, sizeof(data)); |
| if (read < 1) { |
| return 1; |
| } |
| // printf("read %d bytes\n", read); |
| |
| switch (read) { |
| case 4: |
| parse_pdu(data, read); |
| reset_pdu_accumulator(&a); |
| break; |
| |
| case 23: |
| if(accumulate_pdu(&a, data)) { |
| parse_pdu(a.pdu, PDU_LENGTH); |
| reset_pdu_accumulator(&a); |
| } |
| break; |
| } |
| } |
| |
| return 0; |
| } |