Detect RD-5R radio.
It identifies itself ad 'BF-5R'.
This commit is contained in:
parent
dfe210a54c
commit
1a60618c0e
8
Makefile
8
Makefile
@ -2,15 +2,17 @@ CC = gcc
|
|||||||
|
|
||||||
VERSION = 0.7
|
VERSION = 0.7
|
||||||
GITCOUNT = $(shell git rev-list HEAD --count)
|
GITCOUNT = $(shell git rev-list HEAD --count)
|
||||||
|
UNAME = $(shell uname)
|
||||||
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
CFLAGS = -g -O -Wall -Werror -DVERSION='"$(VERSION).$(GITCOUNT)"'
|
||||||
LDFLAGS = -g
|
LDFLAGS = -g
|
||||||
|
|
||||||
OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o
|
OBJS = main.o util.o radio.o dfu-libusb.o uv380.o md380.o
|
||||||
LIBS = -lusb-1.0
|
LIBS = -lusb-1.0
|
||||||
|
|
||||||
# Mac OS X
|
# Linux
|
||||||
#CFLAGS += -I/usr/local/opt/gettext/include
|
ifeq ($(UNAME),Linux)
|
||||||
#LIBS += -L/usr/local/opt/gettext/lib -lintl
|
OBJS += hid-libusb.o
|
||||||
|
endif
|
||||||
|
|
||||||
all: dmrconfig
|
all: dmrconfig
|
||||||
|
|
||||||
|
@ -291,11 +291,13 @@ const char *dfu_init(unsigned vid, unsigned pid)
|
|||||||
|
|
||||||
dev = libusb_open_device_with_vid_pid(ctx, vid, pid);
|
dev = libusb_open_device_with_vid_pid(ctx, vid, pid);
|
||||||
if (!dev) {
|
if (!dev) {
|
||||||
|
if (trace_flag) {
|
||||||
fprintf(stderr, "Cannot find USB device %04x:%04x\n",
|
fprintf(stderr, "Cannot find USB device %04x:%04x\n",
|
||||||
vid, pid);
|
vid, pid);
|
||||||
|
}
|
||||||
libusb_exit(ctx);
|
libusb_exit(ctx);
|
||||||
ctx = 0;
|
ctx = 0;
|
||||||
exit(-1);
|
return 0;
|
||||||
}
|
}
|
||||||
if (libusb_kernel_driver_active(dev, 0)) {
|
if (libusb_kernel_driver_active(dev, 0)) {
|
||||||
libusb_detach_kernel_driver(dev, 0);
|
libusb_detach_kernel_driver(dev, 0);
|
||||||
|
269
hid-libusb.c
Normal file
269
hid-libusb.c
Normal file
@ -0,0 +1,269 @@
|
|||||||
|
/*
|
||||||
|
* HID routines for Linux, via libusb-1.0.
|
||||||
|
*
|
||||||
|
* Copyright (C) 2018 Serge Vakulenko, KK6ABQ
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright
|
||||||
|
* notice, this list of conditions and the following disclaimer in the
|
||||||
|
* documentation and/or other materials provided with the distribution.
|
||||||
|
* 3. The name of the author may not be used to endorse or promote products
|
||||||
|
* derived from this software without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||||
|
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
|
||||||
|
* EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
|
||||||
|
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
|
||||||
|
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
|
||||||
|
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
|
||||||
|
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
|
||||||
|
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
|
||||||
|
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
*/
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <libusb-1.0/libusb.h>
|
||||||
|
#include "util.h"
|
||||||
|
|
||||||
|
static libusb_context *ctx = NULL; // libusb context
|
||||||
|
static libusb_device_handle *dev; // libusb device
|
||||||
|
static unsigned char receive_buf[42]; // receive buffer
|
||||||
|
static volatile int nbytes_received = 0; // receive result
|
||||||
|
|
||||||
|
#define HID_INTERFACE 0 // interface index
|
||||||
|
#define TIMEOUT_MSEC 500 // receive timeout
|
||||||
|
|
||||||
|
//
|
||||||
|
// Callback function for asynchronous receive.
|
||||||
|
// Needs to fill the receive_buf and set nbytes_received.
|
||||||
|
//
|
||||||
|
static void read_callback(struct libusb_transfer *transfer)
|
||||||
|
{
|
||||||
|
switch (transfer->status) {
|
||||||
|
case LIBUSB_TRANSFER_COMPLETED:
|
||||||
|
//fprintf(stderr, "%s: Transfer complete, %d bytes\n", __func__, transfer->actual_length);
|
||||||
|
memcpy(receive_buf, transfer->buffer, transfer->actual_length);
|
||||||
|
nbytes_received = transfer->actual_length;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case LIBUSB_TRANSFER_CANCELLED:
|
||||||
|
//fprintf(stderr, "%s: Transfer cancelled\n", __func__);
|
||||||
|
nbytes_received = LIBUSB_ERROR_INTERRUPTED;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case LIBUSB_TRANSFER_NO_DEVICE:
|
||||||
|
//fprintf(stderr, "%s: No device\n", __func__);
|
||||||
|
nbytes_received = LIBUSB_ERROR_NO_DEVICE;
|
||||||
|
return;
|
||||||
|
|
||||||
|
case LIBUSB_TRANSFER_TIMED_OUT:
|
||||||
|
//fprintf(stderr, "%s: Timeout (normal)\n", __func__);
|
||||||
|
nbytes_received = LIBUSB_ERROR_TIMEOUT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
//fprintf(stderr, "%s: Unknown transfer code: %d\n", __func__, transfer->status);
|
||||||
|
nbytes_received = LIBUSB_ERROR_IO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Write data to the device and receive reply.
|
||||||
|
// Return negative status on error.
|
||||||
|
// Return received byte count of success.
|
||||||
|
// On timeout, repeat the transaction.
|
||||||
|
// Need to use callback for receive interrupt transfer.
|
||||||
|
//
|
||||||
|
static int write_read(const unsigned char *data, unsigned length, unsigned char *reply, unsigned rlength)
|
||||||
|
{
|
||||||
|
struct libusb_transfer *transfer = libusb_alloc_transfer(0);
|
||||||
|
again:
|
||||||
|
nbytes_received = 0;
|
||||||
|
libusb_fill_interrupt_transfer(transfer, dev,
|
||||||
|
LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_IN,
|
||||||
|
reply, rlength, read_callback, 0, TIMEOUT_MSEC);
|
||||||
|
libusb_submit_transfer(transfer);
|
||||||
|
|
||||||
|
int result = libusb_control_transfer(dev,
|
||||||
|
LIBUSB_REQUEST_TYPE_CLASS|LIBUSB_RECIPIENT_INTERFACE|LIBUSB_ENDPOINT_OUT,
|
||||||
|
0x09/*HID Set_Report*/, (2/*HID output*/ << 8) | 0,
|
||||||
|
HID_INTERFACE, (unsigned char*)data, length, TIMEOUT_MSEC);
|
||||||
|
|
||||||
|
if (result < 0) {
|
||||||
|
fprintf(stderr, "Error %d transmitting data via control transfer: %s\n",
|
||||||
|
result, libusb_strerror(result));
|
||||||
|
libusb_cancel_transfer(transfer);
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (nbytes_received == 0) {
|
||||||
|
result = libusb_handle_events(ctx);
|
||||||
|
if (result < 0) {
|
||||||
|
/* Break out of this loop only on fatal error.*/
|
||||||
|
if (result != LIBUSB_ERROR_BUSY &&
|
||||||
|
result != LIBUSB_ERROR_TIMEOUT &&
|
||||||
|
result != LIBUSB_ERROR_OVERFLOW &&
|
||||||
|
result != LIBUSB_ERROR_INTERRUPTED) {
|
||||||
|
fprintf(stderr, "Error %d receiving data via interrupt transfer: %s\n",
|
||||||
|
result, libusb_strerror(result));
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (nbytes_received == LIBUSB_ERROR_TIMEOUT) {
|
||||||
|
//fprintf(stderr, "Timed out!\n");
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
libusb_free_transfer(transfer);
|
||||||
|
return nbytes_received;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Send a request to the device.
|
||||||
|
// Store the reply into the rdata[] array.
|
||||||
|
// Terminate in case of errors.
|
||||||
|
//
|
||||||
|
void hid_send_recv(const unsigned char *data, unsigned nbytes, unsigned char *rdata, unsigned rlength)
|
||||||
|
{
|
||||||
|
unsigned char buf[42];
|
||||||
|
unsigned char reply[42];
|
||||||
|
unsigned k;
|
||||||
|
int reply_len;
|
||||||
|
|
||||||
|
memset(buf, 0, sizeof(buf));
|
||||||
|
buf[0] = 1;
|
||||||
|
buf[1] = 0;
|
||||||
|
buf[2] = nbytes;
|
||||||
|
buf[3] = nbytes >> 8;
|
||||||
|
if (nbytes > 0)
|
||||||
|
memcpy(buf+4, data, nbytes);
|
||||||
|
nbytes += 4;
|
||||||
|
|
||||||
|
if (trace_flag > 0) {
|
||||||
|
fprintf(stderr, "---Send");
|
||||||
|
for (k=0; k<nbytes; ++k) {
|
||||||
|
if (k != 0 && (k & 15) == 0)
|
||||||
|
fprintf(stderr, "\n ");
|
||||||
|
fprintf(stderr, " %02x", buf[k]);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
reply_len = write_read(buf, sizeof(buf), reply, sizeof(reply));
|
||||||
|
if (reply_len < 0) {
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (reply_len != sizeof(reply)) {
|
||||||
|
fprintf(stderr, "Short read: %d bytes instead of %d!\n",
|
||||||
|
reply_len, (int)sizeof(reply));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (trace_flag > 0) {
|
||||||
|
fprintf(stderr, "---Recv");
|
||||||
|
for (k=0; k<reply_len; ++k) {
|
||||||
|
if (k != 0 && (k & 15) == 0)
|
||||||
|
fprintf(stderr, "\n ");
|
||||||
|
fprintf(stderr, " %02x", reply[k]);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "\n");
|
||||||
|
}
|
||||||
|
if (reply[0] != 3 || reply[1] != 0 || reply[3] != 0) {
|
||||||
|
fprintf(stderr, "incorrect reply\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
if (reply[2] != rlength) {
|
||||||
|
fprintf(stderr, "incorrect reply length %d, expected %d\n",
|
||||||
|
reply[2], rlength);
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
memcpy(rdata, reply+4, rlength);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Connect to the specified device.
|
||||||
|
// Initiate the programming session.
|
||||||
|
// Query and return the device identification string.
|
||||||
|
//
|
||||||
|
const char *hid_init(unsigned vid, unsigned pid)
|
||||||
|
{
|
||||||
|
int error = libusb_init(&ctx);
|
||||||
|
if (error < 0) {
|
||||||
|
fprintf(stderr, "libusb init failed: %d: %s\n",
|
||||||
|
error, libusb_strerror(error));
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
dev = libusb_open_device_with_vid_pid(ctx, vid, pid);
|
||||||
|
if (!dev) {
|
||||||
|
if (trace_flag) {
|
||||||
|
fprintf(stderr, "Cannot find USB device %04x:%04x\n",
|
||||||
|
vid, pid);
|
||||||
|
}
|
||||||
|
libusb_exit(ctx);
|
||||||
|
ctx = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (libusb_kernel_driver_active(dev, 0)) {
|
||||||
|
libusb_detach_kernel_driver(dev, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
error = libusb_claim_interface(dev, HID_INTERFACE);
|
||||||
|
if (error < 0) {
|
||||||
|
fprintf(stderr, "Failed to claim USB interface: %d: %s\n",
|
||||||
|
error, libusb_strerror(error));
|
||||||
|
libusb_close(dev);
|
||||||
|
libusb_exit(ctx);
|
||||||
|
ctx = 0;
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const unsigned char CMD_PRG[] = "\2PROGRA";
|
||||||
|
static const unsigned char CMD_PRG2[] = "M\2";
|
||||||
|
static const unsigned char CMD_ACK = 0x41;
|
||||||
|
static unsigned char reply[38];
|
||||||
|
|
||||||
|
hid_send_recv(CMD_PRG, 7, reply, 1);
|
||||||
|
if (reply[0] != CMD_ACK) {
|
||||||
|
fprintf(stderr, "Wrong reply %#x, expected %#x\n", reply[0], CMD_ACK);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
hid_send_recv(CMD_PRG2, 2, reply, 16);
|
||||||
|
|
||||||
|
// ---Send 01 00 07 00 02 50 52 4f 47 52 41
|
||||||
|
// ---Recv 03 00 01 00 41 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
// 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
// 00 00 00 00 00 00 00 00 00 00
|
||||||
|
// ---Send 01 00 02 00 4d 02
|
||||||
|
// ---Recv 03 00 10 00 42 46 2d 35 52 ff ff ff 56 32 31 30
|
||||||
|
// 00 04 80 04 00 00 00 00 00 00 00 00 00 00 00 00
|
||||||
|
// 00 00 00 00 00 00 00 00 00 00
|
||||||
|
|
||||||
|
// 42 46 2d 35 52 ff ff ff 56 32 31 30 00 04 80 04
|
||||||
|
// B F - 5 R V 2 1 0
|
||||||
|
|
||||||
|
// Terminate the string.
|
||||||
|
char *p = memchr(reply, 0xff, sizeof(reply));
|
||||||
|
if (p)
|
||||||
|
*p = 0;
|
||||||
|
return (char*)reply;
|
||||||
|
}
|
||||||
|
|
||||||
|
void hid_close()
|
||||||
|
{
|
||||||
|
if (ctx) {
|
||||||
|
libusb_release_interface(dev, HID_INTERFACE);
|
||||||
|
libusb_close(dev);
|
||||||
|
libusb_exit(ctx);
|
||||||
|
ctx = 0;
|
||||||
|
}
|
||||||
|
}
|
15
radio.c
15
radio.c
@ -80,10 +80,21 @@ void radio_print_version(FILE *out)
|
|||||||
//
|
//
|
||||||
void radio_connect()
|
void radio_connect()
|
||||||
{
|
{
|
||||||
// Only TYT MD family for now.
|
const char *ident;
|
||||||
const char *ident = dfu_init(0x0483, 0xdf11);
|
|
||||||
int i;
|
int i;
|
||||||
|
|
||||||
|
// Try TYT MD family.
|
||||||
|
ident = dfu_init(0x0483, 0xdf11);
|
||||||
|
if (! ident) {
|
||||||
|
// Try RD-5R.
|
||||||
|
ident = hid_init(0x15a2, 0x0073);
|
||||||
|
}
|
||||||
|
if (! ident) {
|
||||||
|
fprintf(stderr, "No radio detected.\n");
|
||||||
|
fprintf(stderr, "Check your USB cable!\n");
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
for (i=0; radio_tab[i].ident; i++) {
|
for (i=0; radio_tab[i].ident; i++) {
|
||||||
if (strcasecmp(ident, radio_tab[i].ident) == 0) {
|
if (strcasecmp(ident, radio_tab[i].ident) == 0) {
|
||||||
device = radio_tab[i].device;
|
device = radio_tab[i].device;
|
||||||
|
7
util.h
7
util.h
@ -65,6 +65,13 @@ void dfu_read_block(int bno, unsigned char *data, int nbytes);
|
|||||||
void dfu_write_block(int bno, unsigned char *data, int nbytes);
|
void dfu_write_block(int bno, unsigned char *data, int nbytes);
|
||||||
void dfu_reboot(void);
|
void dfu_reboot(void);
|
||||||
|
|
||||||
|
//
|
||||||
|
// HID functions.
|
||||||
|
//
|
||||||
|
const char *hid_init(unsigned vid, unsigned pid);
|
||||||
|
void hid_close(void);
|
||||||
|
int hid_write_read(const unsigned char *data, unsigned length, unsigned char *reply, unsigned rlength);
|
||||||
|
|
||||||
//
|
//
|
||||||
// Delay in milliseconds.
|
// Delay in milliseconds.
|
||||||
//
|
//
|
||||||
|
Loading…
Reference in New Issue
Block a user