Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
refactoring and target frequency is now settable at runtime
- Loading branch information
Showing
4 changed files
with
426 additions
and
89 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Original file line | Diff line number | Diff line change |
---|---|---|---|
@@ -1,96 +1,324 @@ | |||
/* License: Public domain. */ | /* License: Public domain. | ||
* | |||
* A free product developed by analog10 (http://analog10.com) | |||
* Check it out! | |||
* */ | |||
|
|||
#define _BSD_SOURCE | |||
#include <endian.h> | |||
#include <termios.h> | |||
#include <string.h> | |||
#include <stdio.h> | #include <stdio.h> | ||
#include <stdint.h> | |||
#include <fcntl.h> | |||
#include <stdlib.h> | #include <stdlib.h> | ||
#include <unistd.h> | #include <unistd.h> | ||
#include <errno.h> | |||
#include <signal.h> | #include <signal.h> | ||
#include <ftdi.h> | #include <poll.h> | ||
|
|||
#include "protocol.h" | |||
|
|||
enum { | |||
FIVE_ONES = 0x55 | |||
,FOUR_ONES = 0x15 | |||
,THREE_ONES = 0x05 | |||
,TWO_ONES = 0x01 | |||
,ONE_ONE = 0x00 | |||
}; | |||
|
|
||
static int keep_running = 1; | static int keep_running = 1; | ||
void sig_handler(int signum) { | void sig_handler(int signum) { | ||
keep_running = 0; | keep_running = 0; | ||
} | } | ||
|
|
||
int xmit_recv(int fd, char* dest, char send){ | |||
fprintf(stderr, "TX : %02hhx\n", send); | |||
|
|||
write(fd, &send, 1); | |||
|
|||
/* Wait for ack or err. */ | |||
|
|||
struct pollfd pfd; | |||
pfd.events = POLLIN; | |||
pfd.fd = fd; | |||
|
|||
/* Wait 500 ms for response. */ | |||
int ret = poll(&pfd, 1, 1000); | |||
if(-1 == ret){ | |||
fprintf(stderr, "err poll: %s\n", strerror(errno)); | |||
return -1; | |||
} | |||
|
|||
if(0 == ret){ | |||
fprintf(stderr, "timed out...\n"); | |||
return -2; | |||
} | |||
|
|||
ret = read(fd, dest, 1); | |||
if(-1 == ret){ | |||
fprintf(stderr, "read err: %s\n", strerror(errno)); | |||
return -1; | |||
} | |||
|
|||
if(OUT_RX_ERR == (*dest & 0xF0)){ | |||
fprintf(stderr, "recv err: %02hhx\n", *dest); | |||
return -3; | |||
} | |||
|
|||
fprintf(stderr, "RX : %02hhx\n", *dest); | |||
return 0; | |||
} | |||
|
|||
int main(int argc, char **argv) { | int main(int argc, char **argv) { | ||
struct ftdi_context *ftdi; | |||
int ret; | int ret; | ||
unsigned baudrate = 9600; | unsigned baudrate = 9600; | ||
uint32_t target_freq = 16000000; | |||
|
|||
if(argc < 2){ | |||
fprintf(stderr, "Usage: TTY_DEV_NODE [BAUD_RATE] [TARGET_FREQUENCY] \n"); | |||
return 1; | |||
} | |||
|
|
||
/* Get the baudrate from the command line. */ | /* Get the baudrate from the command line. */ | ||
if(argc > 1){ | if(argc > 2){ | ||
char* endptr; | char* endptr; | ||
baudrate = strtoul(argv[1], &endptr, 0); | baudrate = strtoul(argv[2], &endptr, 0); | ||
if(*endptr){ | if(*endptr){ | ||
fprintf(stderr, "err invalid baud rate parameter\n"); | fprintf(stderr, "err invalid baud rate parameter\n"); | ||
return 1; | return 1; | ||
} | } | ||
} | } | ||
|
|
||
if((ftdi = ftdi_new()) == 0){ | if(argc > 3){ | ||
fprintf(stderr, "err ftdi_new\n"); | char* endptr; | ||
target_freq = strtoul(argv[3], &endptr, 0); | |||
if(*endptr || !target_freq){ | |||
fprintf(stderr, "err invalid target frequency parameter\n"); | |||
return 1; | |||
} | |||
} | |||
|
|||
int fd = open(argv[1], O_RDWR); | |||
struct termios ser_options; | |||
ret = tcgetattr(fd, &ser_options); | |||
if(ret < 0){ | |||
fprintf(stderr, "err tcgetattr: %s\n", strerror(errno)); | |||
return 1; | return 1; | ||
} | } | ||
|
|
||
// Select interface | /* Set Baud speed. */ | ||
ftdi_set_interface(ftdi, INTERFACE_ANY); | switch(baudrate){ | ||
case 50: | |||
baudrate = B50; | |||
break; | |||
|
|
||
/* Using FT230X here, obtained from lsusb. */ | case 75: | ||
ret = ftdi_usb_open(ftdi, 0x403, 0x6015); | baudrate = B75; | ||
break; | |||
|
|
||
case 110: | |||
baudrate = B110; | |||
break; | |||
|
|||
case 134: | |||
baudrate = B134; | |||
break; | |||
|
|||
case 150: | |||
baudrate = B150; | |||
break; | |||
|
|||
case 200: | |||
baudrate = B200; | |||
break; | |||
|
|||
case 300: | |||
baudrate = B300; | |||
break; | |||
|
|||
case 600: | |||
baudrate = B600; | |||
break; | |||
|
|||
case 1200: | |||
baudrate = B1200; | |||
break; | |||
|
|||
case 1800: | |||
baudrate = B1800; | |||
break; | |||
|
|||
case 2400: | |||
baudrate = B2400; | |||
break; | |||
|
|||
case 4800: | |||
baudrate = B4800; | |||
break; | |||
|
|||
case 9600: | |||
baudrate = B9600; | |||
break; | |||
|
|||
case 19200: | |||
baudrate = B19200; | |||
break; | |||
|
|||
case 38400: | |||
baudrate = B38400; | |||
break; | |||
|
|||
case 57600: | |||
baudrate = B57600; | |||
break; | |||
|
|||
case 115200: | |||
baudrate = B115200; | |||
break; | |||
|
|||
case 230400: | |||
baudrate = B230400; | |||
break; | |||
|
|||
default: | |||
fprintf(stderr, "err bad baudrate\n"); | |||
return 1; | |||
} | |||
|
|||
ret = cfsetispeed(&ser_options, baudrate); | |||
if(ret < 0){ | |||
fprintf(stderr, "err cfsetispeed: %s\n", strerror(errno)); | |||
return 1; | |||
} | |||
|
|||
ret = cfsetospeed(&ser_options, baudrate); | |||
if(ret < 0){ | if(ret < 0){ | ||
fprintf(stderr, "err opening : %i %s\n", ret, ftdi_get_error_string(ftdi)); | fprintf(stderr, "err cfsetospeed: %s\n", strerror(errno)); | ||
return 1; | return 1; | ||
} | } | ||
|
|
||
// Set baudrate | /* Setup for raw binary comms. */ | ||
ret = ftdi_set_baudrate(ftdi, baudrate); | cfmakeraw(&ser_options); | ||
|
|||
/* Reset options for communications. */ | |||
ser_options.c_cflag &= ~(PARODD | PARENB | CS5 | CS6 | CS7 | CS8 | CSTOPB); | |||
|
|||
ret = tcsetattr(fd, TCSAFLUSH, &ser_options); | |||
if(ret < 0){ | if(ret < 0){ | ||
fprintf(stderr, "err set baudrate: %d (%s)\n", ret, ftdi_get_error_string(ftdi)); | fprintf(stderr, "err tcsetattr: %s\n", strerror(errno)); | ||
return 1; | return 1; | ||
} | } | ||
|
|
||
signal(SIGINT, sig_handler); | signal(SIGINT, sig_handler); | ||
|
|
||
uint8_t output = 0x55; | /* Shift frequency up to its MSB. | ||
while(keep_running){ | * Reset the frequency register and assign the value. */ | ||
/* Wait for init packet. */ | unsigned bits_remaining = 32; | ||
uint8_t rx; | while(!(target_freq & 0x80000000)){ | ||
ret = ftdi_read_data(ftdi, &rx, 1); | target_freq <<= 1; | ||
if(ret < 0){ | --bits_remaining; | ||
fprintf(stderr, "Read error"); | } | ||
return 1; |
|
||
/* Empty RX buffer. */ | |||
{ | |||
uint8_t buffer[1024]; | |||
struct pollfd pfd; | |||
pfd.events = POLLIN; | |||
pfd.fd = fd; | |||
ret = 1024; | |||
while(1024 == ret){ | |||
ret = poll(&pfd, 1, 500); | |||
if(-1 == ret){ | |||
fprintf(stderr, "err poll: %s\n", strerror(errno)); | |||
return -1; | |||
} | |||
|
|||
ret = read(fd, buffer, ret); | |||
} | |||
if(-1 == ret){ | |||
fprintf(stderr, "err emptying buff: %s\n", strerror(errno)); | |||
return -1; | |||
} | } | ||
} | |||
|
|||
uint8_t rx = 0; | |||
|
|||
/* Reset register. */ | |||
ret = xmit_recv(fd, &rx, FOUR_ONES); | |||
if(ret) | |||
return ret; | |||
if(rx != (OUT_RX_ACK | 4)){ | |||
return -4; | |||
} | |||
|
|||
/* Set register value. */ | |||
while(bits_remaining){ | |||
uint8_t xmit = (target_freq & 0x80000000) | |||
? ONE_ONE : TWO_ONES; | |||
ret = xmit_recv(fd, &rx, xmit); | |||
if(ret) | |||
return ret; | |||
|
|||
/* Make sure we got proper ack back. */ | |||
if((xmit == ONE_ONE) && rx != (OUT_RX_ACK | 0x1)) | |||
return -4; | |||
|
|||
if((xmit == TWO_ONES) && rx != (OUT_RX_ACK | 0x2)) | |||
return -4; | |||
|
|||
target_freq <<= 1; | |||
--bits_remaining; | |||
} | |||
|
|||
/* Register is set, now initiate calibration. */ | |||
ret = xmit_recv(fd, &rx, THREE_ONES); | |||
if(ret) | |||
return ret; | |||
if(rx != (OUT_RX_ACK | 0x3)) | |||
return -4; | |||
|
|
||
fprintf(stderr, "Got %02hhx, %i\n", rx, ret); | |||
|
|
||
if(0xcc == rx){ | while(keep_running){ | ||
ret = xmit_recv(fd, &rx, 0x55); | |||
if(ret) | |||
return ret; | |||
|
|||
if(OUT_INCREMENT == rx){ | |||
} | |||
else if(OUT_DECREMENT == rx){ | |||
} | |||
else if(OUT_FINISH == rx){ | |||
/* Read dco, bcs values. */ | /* Read dco, bcs values. */ | ||
uint8_t vals[2]; | struct { | ||
uint32_t estimate; | |||
uint32_t last_diff; | |||
uint8_t dco; | |||
uint8_t bcs; | |||
} result; | |||
|
|||
unsigned count = 0; | unsigned count = 0; | ||
while(count < 2){ | while(count < 10){ | ||
ret = ftdi_read_data(ftdi, vals + count, 2 - count); | ret = read(fd, (uint8_t*)(&result) + count, sizeof(result) - count); | ||
fprintf(stderr, "Read back %i\n", ret); | fprintf(stderr, "Read back %i\n", ret); | ||
count += ret; | count += ret; | ||
} | } | ||
fprintf(stderr, "DCO BCS1CTL\n"); |
|
||
printf("%02hhx %02hhx\n", vals[0], vals[1]); | result.estimate = le32toh(result.estimate); | ||
fprintf(stderr, "DCO BCS1CTL ESTIMATE ERROR\n"); | |||
printf("%02hhx %02hhx %8u %8u\n" | |||
,result.dco ,result.bcs ,result.estimate ,result.last_diff); | |||
break; | |||
} | |||
else{ | |||
fprintf(stderr, "BAD RX %02hhx\n", rx); | |||
break; | break; | ||
} | } | ||
|
|
||
usleep(100); | usleep(100); | ||
|
|||
/* Write */ | |||
ret = ftdi_write_data(ftdi, &output, 1); | |||
if(ret < 0){ | |||
fprintf(stderr, "Write error"); | |||
return 1; | |||
} | |||
} | } | ||
|
|
||
signal(SIGINT, SIG_DFL); | signal(SIGINT, SIG_DFL); | ||
|
|
||
ftdi_usb_close(ftdi); | |||
do_deinit: | |||
ftdi_free(ftdi); | |||
|
|||
return 0; | return 0; | ||
} | } |
Oops, something went wrong.