Skip to content

Commit

Permalink
serial port support for GNU/Linux
Browse files Browse the repository at this point in the history
  • Loading branch information
Nikita Orlov committed Jul 15, 2024
1 parent 5a8b149 commit ba757ea
Show file tree
Hide file tree
Showing 4 changed files with 176 additions and 13 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
isp55e0
isp55e0.o
165 changes: 153 additions & 12 deletions isp55e0.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@

#else
#include <err.h>
#include <termios.h>
#include <sys/ioctl.h>
#endif

#include <libusb-1.0/libusb.h>
Expand Down Expand Up @@ -610,13 +612,19 @@ static const struct option long_options[] = {
{ "data-flash", required_argument, 0, 'k' },
{ "data-verify", required_argument, 0, 'l' },
{ "data-dump", required_argument, 0, 'm' },
#ifndef WIN32
{ "port", required_argument, 0, 'p' },
#endif
{ 0, 0, 0, 0 }
};

static void usage(void)
{
printf("ISP programmer for some WinChipHead MCUs\n");
printf("Options:\n");
#ifndef WIN32
printf(" --port, -p use serial port instead of usb\n");
#endif
printf(" --code-flash, -f firmware to flash\n");
printf(" --code-verify, -c verify existing firwmare\n");
printf(" --data-flash, -k data to flash\n");
Expand All @@ -641,6 +649,80 @@ static void hexdump(const char *name, const void *data, int len)
printf("\n");
}

#ifndef WIN32
static void open_serial_device(struct device *dev, char *port)
{
int ret;
struct termios options;
int status;
speed_t baud = B115200;

if ((dev->fd = open(port, O_RDWR | O_NOCTTY)) == -1)
errx(EXIT_FAILURE, "Error occured while opening serial port '%s'", port);

ret = fcntl(dev->fd, F_SETFL, O_RDWR) ;
if (ret < 0)
goto fail;

ret = tcgetattr(dev->fd, &options);
if (ret < 0)
errx(EXIT_FAILURE, "Error occured while configuring serial port");

cfmakeraw(&options);

ret = cfsetispeed(&options, baud);
if (ret < 0)
goto fail;

ret = cfsetospeed(&options, baud);
if (ret < 0)
goto fail;

options.c_cflag |= (CLOCAL | CREAD) ;
options.c_cflag &= ~(PARENB | CSTOPB | CSIZE) ;
options.c_cflag |= CS8 ;
options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG) ;
options.c_oflag &= ~OPOST ;
/* Turn off s/w flow ctrl */
options.c_iflag &= ~(IXON | IXOFF | IXANY);
/* Disable any special handling of received bytes */
options.c_iflag &= ~(IGNBRK | BRKINT | PARMRK | ISTRIP | INLCR | IGNCR | ICRNL);

options.c_cc [VMIN] = 0;
options.c_cc [VTIME] = SERIAL_TIMEOUT;

ret = tcsetattr(dev->fd, TCSANOW, &options) ;
if (ret < 0)
goto fail;

ret = ioctl(dev->fd, TIOCMGET, &status);
if (ret < 0)
goto fail;

status |= TIOCM_DTR;
status |= TIOCM_RTS;

ret = ioctl(dev->fd, TIOCMSET, &status);
if (ret < 0)
goto fail;

return;
fail:
errx(EXIT_FAILURE, "Error occured while configuring serial port");
}

static unsigned char serial_crc(unsigned char *req, int req_len)
{
unsigned char crc = 0;

for(int i=0;i<req_len;i++){
crc += req[i];
}

return crc;
}
#endif

/* Open and claim the USB device */
static void open_usb_device(struct device *dev)
{
Expand Down Expand Up @@ -672,22 +754,62 @@ static int transfer(struct device *dev, void *req, int req_len,
{
int len;
int ret;
#ifndef WIN32
int serial_transmitted;
unsigned char req_serial_prefix[2] = {SERIAL_REQ_MAGIC1, SERIAL_REQ_MAGIC2};
unsigned char req_serial_crc[1] = {serial_crc(req, req_len)};
unsigned char resp_serial_prefix[2];
unsigned char resp_serial_crc[1];

if (dev->fd) {
/* Serial port case */
serial_transmitted = write(dev->fd, req_serial_prefix, sizeof(req_serial_prefix));
serial_transmitted += write(dev->fd, req, req_len);
serial_transmitted += write(dev->fd, req_serial_crc, sizeof(req_serial_crc));

if (serial_transmitted != (sizeof(req_serial_prefix)+req_len+sizeof(req_serial_crc)))
errx(EXIT_FAILURE, "Serial port write error");

if (dev->debug)
hexdump("request", req, req_len);

serial_transmitted = read(dev->fd, resp_serial_prefix, sizeof(resp_serial_prefix));
if (serial_transmitted != sizeof(resp_serial_prefix) || resp_serial_prefix[0] != SERIAL_RESP_MAGIC1 || resp_serial_prefix[1] != SERIAL_RESP_MAGIC2)
errx(EXIT_FAILURE, "Serial port response magic read error");

serial_transmitted = read(dev->fd, resp, resp_len);
if (serial_transmitted != resp_len)
errx(EXIT_FAILURE, "Serial port response read error");

ret = libusb_bulk_transfer(dev->usb_h, EP_OUT, req, req_len,
serial_transmitted = read(dev->fd, resp_serial_crc, sizeof(resp_serial_crc));
if (serial_transmitted != sizeof(resp_serial_crc) || resp_serial_crc[0] != serial_crc(resp, resp_len))
errx(EXIT_FAILURE, "Serial port response crc read error");

if (dev->debug)
hexdump("response", resp, resp_len);

} else {
#endif
/* USB case */
ret = libusb_bulk_transfer(dev->usb_h, EP_OUT, req, req_len,
&len, USB_TIMEOUT);
if (ret)
return -EIO;
if (ret)
return -EIO;

if (dev->debug)
hexdump("request", req, len);
if (dev->debug)
hexdump("request", req, len);

ret = libusb_bulk_transfer(dev->usb_h, EP_IN, resp, resp_len,
ret = libusb_bulk_transfer(dev->usb_h, EP_IN, resp, resp_len,
&len, USB_TIMEOUT);
if (ret)
return -EIO;
if (ret)
return -EIO;

if (dev->debug)
hexdump("response", resp, len);
if (dev->debug)
hexdump("response", resp, len);

#ifndef WIN32
}
#endif

return 0;
}
Expand Down Expand Up @@ -1133,11 +1255,19 @@ int main(int argc, char *argv[])
bool do_data_dump = false;
int c;
int i;
#ifndef WIN32
char *port = NULL;
#endif

while (1) {
int option_index = 0;

c = getopt_long(argc, argv, "c:df:hk:l:m:",
#ifdef WIN32
#define SHORT_OPTS "c:df:hk:l:m:"
#else
#define SHORT_OPTS "c:df:hk:l:m:p:"
#endif
c = getopt_long(argc, argv, SHORT_OPTS,
long_options, &option_index);
if (c == -1)
break;
Expand Down Expand Up @@ -1174,6 +1304,11 @@ int main(int argc, char *argv[])
dev.data_dump.filename = optarg;
do_data_dump = true;
break;
#ifndef WIN32
case 'p':
port = optarg;
break;
#endif
case 'h':
usage();
return EXIT_SUCCESS;
Expand All @@ -1185,7 +1320,13 @@ int main(int argc, char *argv[])
if (optind < argc)
errx(EXIT_FAILURE, "Extra argument: %s", argv[optind]);

open_usb_device(&dev);
#ifndef WIN32
if (port)
open_serial_device(&dev, port);
else
#endif
open_usb_device(&dev);

read_chip_type(&dev);
printf("Found device %s\n", dev.profile->name);

Expand Down
12 changes: 11 additions & 1 deletion isp55e0.h
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@

#define XOR_KEY_LEN 8

/* Serial port wrapper magics */
#define SERIAL_REQ_MAGIC1 (0x57)
#define SERIAL_REQ_MAGIC2 (0xAB)
#define SERIAL_RESP_MAGIC1 (0x55)
#define SERIAL_RESP_MAGIC2 (0xAA)

/* Profile of a specific CH device */
struct ch_profile {
const char *name;
Expand Down Expand Up @@ -43,10 +49,14 @@ struct device {
uint8_t config_data[12];
uint8_t xor_key[XOR_KEY_LEN];
bool wait_reboot_resp; /* wait for reboot command response */
#ifndef WIN32
int fd; /* serial port descriptor */
#endif
};

/* Enough to erase the flash. */
#define USB_TIMEOUT 5000
#define USB_TIMEOUT 5000 // milliseconds
#define SERIAL_TIMEOUT 50 // deciseconds

#define CMD_CHIP_TYPE 0xa1
#define CMD_REBOOT 0xa2
Expand Down
10 changes: 10 additions & 0 deletions protocol.txt
Original file line number Diff line number Diff line change
Expand Up @@ -221,3 +221,13 @@ Similar to above, except for a few things.
- After flashing the last 56-byte block (or less than), the bootloader
must be sent a write with no data. Failing to do so results in a
failed firmware check.





WCH chips expose similar protocol via UART (UART0 or UART1).
The only difference is prefix and crc:
0x57 0xAB for request
0x55 0xAA for response
CRC is just 8bit all bytes sum except prefix.

0 comments on commit ba757ea

Please sign in to comment.