Commit b5ca350b authored by Peter Stuge's avatar Peter Stuge
Browse files

lmicdiusb: Import TI's BSD-licensed GDB TCP proxy source code

parent 44652679
//*****************************************************************************
//
// Makefile - to build lmicdiusb utility
//
// Copyright (c) 2011-2012 Texas Instruments Incorporated.
// All rights reserved.
//
// Software License Agreement
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 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.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "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 COPYRIGHT
// OWNER OR CONTRIBUTORS 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
//
//*****************************************************************************
ifeq ($(shell uname),Darwin)
LIBUSB_CFLAGS := -I/usr/local/include/libusb-1.0
LIBUSB_LIBDIR := /usr/local/lib
LIBUSB_LIBS := -lusb-1.0
LDFLAGS += -framework AppKit -framework Carbon -framework IOKit
endif
ifeq ($(shell uname),Linux)
LIBUSB_CFLAGS ?= $(shell pkg-config --cflags libusb-1.0)
LIBUSB_LIBDIR ?= $(shell pkg-config --variable=libdir libusb-1.0)
LIBUSB_LIBS ?= $(shell pkg-config --libs-only-l libusb-1.0)
endif
VPATH += $(LIBUSB_LIBDIR)
LDFLAGS += -L$(LIBUSB_LIBDIR) -g
CFLAGS += -Wall -g $(LIBUSB_CFLAGS)
all: lmicdi
lmicdi: lmicdi.o socket.o gdb.o $(LIBUSB_LIBS)
lmicdi.o socket.o: lmicdi.h
.PHONY: all clean
clean:
rm -rf lmicdi lmicdi.o socket.o gdb.o
This project demonstrates how to connect a TCP socket to
the USB Bulk device on an LMICDI part.
Once the socket and bulk xfer enpoints are connected,
one can connect to the socket with an arm-gdb client.
GDB to port 7777
It's that easy...
// This is the list of commands supported by the in circuit debugger on the
// Stellaris LM4F120 LaunchPad.
//Start Rcmd's
*debug
**mode - do nothing
**disable - disable DAP
**speed - argument < 5
**trace - do nothing
**unlock - Perform Debug mass erase (factory reset)
**sreset - System Reset
**creset - core reset only
**hreset - hardware pin reset
*set
**resettype - do nothing
**vectorcatch - set or clear vector catch bit in the DAP accepts 1 or 0
**stepirq - set or clear the step irq bit in the DAP
**xtal - set xtal value for Sandstorm, Fury and DustDevil, NOP for other classes
*version - get version number of the firmware
*dfu-update - jump to DFU bootloader.
*mfg
**setu0 - set user 0 register, used for serial #'s and MAC's.
**setu1 - set user 1 register, used for serial #'s and MAC's.
**getu0 - get user 0 register, used for serial #'s and MAC's.
**getu1 - get user 1 register, used for serial #'s and MAC's.
//END Rcmd's
//Start regular commands
*! -> extend mode
*? -> halt core
*A -> nothing
*c -> start the core (continue)
*C -> start the core (continue)
*D -> Detach
*F -> break
*g -> send complete registers set
*G -> nothing
*H -> sends back empty response
*i -> nothing
*I -> nothing
*m -> read memory
*M -> write memory
*p -> read register
*P -> write register
*q -> same as 'Q'
*R -> reset and continue
*s -> read state of DHCS?
*S -> identical to s
*t -> nothing
*T -> nothing
*x -> read memory binary
*X -> write memory binary
*z -> remove breakpoint
*Z -> Add breakpoint
*v
**FlashErase
**FlashWrite
**FlashDone
**Cont? -> send empty respsonse
*Q -> query packets,
** supported -> gets info about the target and what it supports?
** Xfer -> send back the memory map
** Rcmd -> call GDBInterpretCommand which processes Rcmd's listed above.
//*****************************************************************************
//
// gdb.c - all the functions related to getting GDB protocol in and out of
// libusb
//
// Copyright (c) 2011-2012 Texas Instruments Incorporated.
// All rights reserved.
//
// Software License Agreement
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 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.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "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 COPYRIGHT
// OWNER OR CONTRIBUTORS 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 "lmicdi.h"
//****************************************************************************
//
// calculates the checksum across the last GDB payload. Returns 0 if the
// checksum is correct. 1 otherwise.
//
//****************************************************************************
static int
gdb_validate()
{
//
// TODO: Take payload and calculate checksum...
//
return 0;
}
static int
hexchartoi(char c)
{
if ((c >= '0') && (c <= '9'))
{
return '0' - c;
}
if ((c >= 'a') && (c <= 'f'))
{
return 'a' - c + 10;
}
if ((c >= 'a') && (c <= 'f'))
{
return 'A' - c + 10;
}
return 0;
}
//****************************************************************************
//
// handle 'len' bytes of 'pBuf' and advance the gdb state machine
// accordingly. Handle packets in the format of ....$<payload>#nn
//
// When a complete packet has been received, call pFn passing the GDB
// context structure and a boolean flag indicating whether or not the
// checksum was valid.
//
//****************************************************************************
void
gdb_statemachine(GDBCTX *pGdbCtx, unsigned char *pBuf, unsigned int len,
void(*pFn)(GDBCTX*, int))
{
while (len--)
{
switch(pGdbCtx->gdb_state)
{
case GDB_IDLE:
TRACE(0, "GDB_IDLE: '%c'\n", *pBuf);
if (*pBuf == '$')
{
pGdbCtx->gdb_state = GDB_PAYLOAD;
}
if (*pBuf == '+')
{
pGdbCtx->iAckCount++;
}
if (*pBuf == '-')
{
pGdbCtx->iNakCount++;
}
pGdbCtx->pResp[pGdbCtx->iRd++] = *pBuf;
pBuf++;
break;
case GDB_PAYLOAD:
TRACE(0, "GDB_PAYLOAD: '%c'\n", *pBuf);
pGdbCtx->pResp[pGdbCtx->iRd++] = *pBuf;
if (*pBuf == '#')
{
pGdbCtx->gdb_state = GDB_CSUM1;
}
pBuf++;
break;
case GDB_CSUM1:
TRACE(0, "GDB_CSUM1: '%c'\n", *pBuf);
pGdbCtx->csum = hexchartoi(*pBuf) << 4;
pGdbCtx->gdb_state = GDB_CSUM2;
pGdbCtx->pResp[pGdbCtx->iRd++] = *pBuf;
pBuf++;
break;
case GDB_CSUM2:
TRACE(0, "GDB_CSUM2: '%c'\n", *pBuf);
pGdbCtx->csum |= hexchartoi(*pBuf);
pGdbCtx->pResp[pGdbCtx->iRd++] = *pBuf;
if (pFn)
{
if (gdb_validate(pGdbCtx->pResp, pGdbCtx->csum) == 0)
{
pFn(pGdbCtx, 1);
}
else
{
pFn(pGdbCtx, 0);
}
}
pGdbCtx->iRd = 0;
pGdbCtx->gdb_state = GDB_IDLE;
pBuf++;
break;
}
}
}
//
// Grab the payload from the GDB context and call pass it over to the socket
// handling code.
//
static void gdb_packet_from_usb(GDBCTX *pGdbCtx, int bCsumValid)
{
pGdbCtx->pResp[pGdbCtx->iRd] = 0;
usbRxResp(pGdbCtx->pResp, pGdbCtx->iRd);
}
//****************************************************************************
//
// This is the USB callback that gets called whenever our background read
// operation RX'es anything from the USB devices (ie. the GDB server)
//
//****************************************************************************
void
usb_callback(struct libusb_transfer *pTrans)
{
int rc;
TRACE(1, "%s: enter\n", __FUNCTION__);
//
// Here we want to "digest" the received packet. Then, hopefully,
// we can resubmit this same pTrans structure for the next receive
//
switch(pTrans->status)
{
case LIBUSB_TRANSFER_COMPLETED:
//
// Process whatever data we've RX'ed by invoking the GDB state
// machine. When a complete GDB packet has been RX'ed the state
// machine will call gdb_packet_from_usb.
//
gdb_statemachine(pTrans->user_data, pTrans->buffer,
pTrans->actual_length, gdb_packet_from_usb);
//
// Requeue the async RX operation so that we catch the next packet
// from the USB device
//
rc = libusb_submit_transfer(pTrans);
if (rc != 0)
{
TRACE(ALWAYS, "%s: submit_transfer: rc = 0x%08x\n", __FUNCTION__, rc);
}
break;
default:
TRACE(ALWAYS, "%s: status = 0x%08x\n", __FUNCTION__, pTrans->status);
}
}
Copyright (c) 2011-2012 Texas Instruments Incorporated.
All rights reserved.
Software License Agreement
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
Redistributions of source code must retain the original copyright
notice, this list of conditions and the following disclaimer.
Redistributions in binary form must reproduce the original copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the
distribution.
Neither the name of Texas Instruments Incorporated nor the names of
its contributors may be used to endorse or promote products derived
from this software without specific prior written permission.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
"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 COPYRIGHT
OWNER OR CONTRIBUTORS 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.
//*****************************************************************************
//
// lmicdi.c -
//
// Copyright (c) 2011-2012 Texas Instruments Incorporated.
// All rights reserved.
//
// Software License Agreement
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions
// are met:
//
// Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
//
// 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.
//
// Neither the name of Texas Instruments Incorporated nor the names of
// its contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "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 COPYRIGHT
// OWNER OR CONTRIBUTORS 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 "lmicdi.h"
#include <unistd.h>
#include <time.h>
struct libusb_context *pCtx;
unsigned int gTraceLvl = 2;
const struct libusb_endpoint_descriptor *pdEndpIn, *pdEndpOut;
libusb_device_handle *phDev;
unsigned char pResp[MSGSIZE];
void
_dump_dev_strings(libusb_device_handle *phDev,
struct libusb_device_descriptor *pdDev,
const char *pIndent)
{
unsigned char pStr[256];
int rc;
memset(pStr, 0, sizeof(pStr));
rc = libusb_get_string_descriptor_ascii(phDev, pdDev->iManufacturer,
pStr, sizeof(pStr));
TRACE(2, "%sMFG'r string (index %d, len = %d) = '%s'\n",
pIndent,
pdDev->iManufacturer, rc, pStr);
rc = libusb_get_string_descriptor_ascii(phDev, pdDev->iProduct,
pStr, sizeof(pStr));
TRACE(2, "%sProduct string (index %d, len = %d) = '%s'\n",
pIndent,
pdDev->iProduct, rc, pStr);
rc = libusb_get_string_descriptor_ascii(phDev, pdDev->iSerialNumber,
pStr, sizeof(pStr));
TRACE(2, "%sProduct serial number (index %d, len = %d) = '%s'\n",
pIndent,
pdDev->iSerialNumber, rc, pStr);
}
void
_dump_cfg_strings(libusb_device_handle *phDev,
struct libusb_config_descriptor *pdCfg,
const char *pIndent)
{
unsigned char pStr[256];
int rc;
memset(pStr, 0, sizeof(pStr));
rc = libusb_get_string_descriptor_ascii(phDev, pdCfg->iConfiguration,
pStr, sizeof(pStr));
TRACE(1, "%sConfig name (index %d, len = %d) = '%s'\n",
pIndent,
pdCfg->iConfiguration, rc, pStr);
}
void
_dump_if_strings(libusb_device_handle *phDev,
const struct libusb_interface_descriptor *pdIf,
const char *pIndent)
{
unsigned char pStr[256];
int rc;
memset(pStr, 0, sizeof(pStr));
rc = libusb_get_string_descriptor_ascii(phDev, pdIf->iInterface,
pStr, sizeof(pStr));
TRACE(1, "%sInterface name (index %d, len = %d) = '%s'\n",
pIndent,
pdIf->iInterface, rc, pStr);
}
//
// This is the GDB context for GDB responses from the USB target
//
unsigned char pUsbResp[MSGSIZE];
GDBCTX gdbUsbCtx =
{
GDB_IDLE, // gdb_state
pUsbResp, // pResp
0, // iRd
0, // csum
0, // iAckCount
0 // iNakCount
};
//
// This is the transfer structure that maintains the USB read in
// the background.
//
struct libusb_transfer *pTrans;
//*****************************************************************************
//
//! Initializes the sample API.
//!
//! This function prepares the sample API for use by the application.
//!
//! \return None.
//
//*****************************************************************************
int
main(int argc, char *argv[])
{
int rc;
unsigned int iDev, iCfg, iIf, iAlt, iEndp;
ssize_t nDevs;
libusb_device **pDevices;
libusb_device *pDev;
struct libusb_config_descriptor *pdCfg;
struct libusb_device_descriptor dDev;
rc = libusb_init(&pCtx);
ASSERT(rc == 0);
// libusb_set_debug(pCtx, 5);
nDevs = libusb_get_device_list(pCtx, &pDevices);
TRACE(0, "nDevs = %d\n", (int)nDevs);
ASSERT(nDevs >= 0);
pDev = NULL;
for (iDev = 0; iDev < nDevs; iDev++)
{
TRACE(0, "Considering device %d\n", iDev);
//
// Get the device descriptor so we know how many configurations there are
//
rc = libusb_get_device_descriptor(pDevices[iDev], &dDev);
ASSERT(rc == 0);
if ((dDev.idVendor == LMICDI_VID) &&
(dDev.idProduct == LMICDI_PID))
{
pDev = pDevices[iDev];
TRACE(1, "Found device with matching VID and PID. pDev = %p\n", pDev);
break;
}
}
ASSERT(pDev != NULL);
rc = libusb_open(pDev, &phDev);
if (rc != 0)
{
TRACE(ALWAYS, "Failed to open device. rc = %d\n", rc);
}
//
// NOTE: If/When we get here dDev should still be valid
//
// For each configuration...
// for each interface...
// for each alternate config for the interface...
// for each endpoint...
//
for (iCfg = 0; iCfg < dDev.bNumConfigurations; iCfg++)
{
TRACE(1, D0 "iCfg = %d\n", iCfg);
rc = libusb_get_config_descriptor(pDev, iCfg, &pdCfg);
ASSERT(rc == 0);
//
// It seems as though we need to detach the kernel before we can read
// strings for ourselves.
//
#if 0
for (iIf = 0; iIf < pdCfg->bNumInterfaces; iIf++)
{
rc = libusb_kernel_driver_active(phDev, iIf);
TRACE(1, D1 "kernel_driver_active(if%d) = %d\n",
iIf, rc);
if (rc)
{
TRACE(1, D1 "Attempting to detach...");
rc = libusb_detach_kernel_driver(phDev, iIf);
if (rc)
{
TRACE(1, " failed (%d)\n", rc);
}
else
{
bKernel[iIf] = 1;
TRACE(1, " OK\n");
}
}
}
#endif
//
// if the MFGr string is coming back as 0 then the device is wedged.
//
if (dDev.iManufacturer == 0) exit(EXIT_FAILURE);
//
// TODO: Figure out why some string indexes are coming back as 0
//
// _dump_cfg_strings(phDev, pdCfg, D0);