From 6620fe6ba930c1af0ff78a6d36a836e6cd3eb7b6 Mon Sep 17 00:00:00 2001 From: TitanMKD Date: Sat, 9 Mar 2013 11:47:28 +0100 Subject: [PATCH] Add host(hackrf_info)/fw(usb_performance) IAP read part id/serial no(to be confirmed). --- firmware/common/rom_iap.c | 101 ++++++++++++++++ firmware/common/rom_iap.h | 121 +++++++++++++++++++ firmware/usb_performance/Makefile | 3 +- firmware/usb_performance/Makefile_rom_to_ram | 3 +- firmware/usb_performance/usb_performance.c | 45 ++++++- host/libhackrf/examples/hackrf_info.c | 18 ++- host/libhackrf/src/hackrf.c | 26 +++- host/libhackrf/src/hackrf.h | 7 ++ 8 files changed, 318 insertions(+), 6 deletions(-) create mode 100644 firmware/common/rom_iap.c create mode 100644 firmware/common/rom_iap.h diff --git a/firmware/common/rom_iap.c b/firmware/common/rom_iap.c new file mode 100644 index 00000000..a3ad3a55 --- /dev/null +++ b/firmware/common/rom_iap.c @@ -0,0 +1,101 @@ +/* + * Copyright 2013 Benjamin Vernoux + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + + #include "hackrf_core.h" +#include + +#include "rom_iap.h" + +#define ROM_IAP_ADDR (0x10400100) +#define ROM_IAP_UNDEF_ADDR (0x12345678) + +#define ROM_OTP_PART_ID_ADDR (0x40045000) +#define ROM_OTP_SERIAL_NO_ADDR (0x40045050) /* To be confirmed */ + +typedef void (* IAP_t)(uint32_t [],uint32_t[]); + +typedef struct { + const IAP_t IAP; /* If equal to 0x12345678 IAP not implemented */ + /* Other TBD */ +} *pENTRY_ROM_API_t; +#define pROM_API ((pENTRY_ROM_API_t)ROM_IAP_ADDR) + +/* + See Errata sheet ES_LPC43X0_A.pdf (LPC4350/30/20/10 Rev A) + 3.5 IAP.1: In-Application Programming API not present on flashless parts + Introduction: + The LPC43x0 microcontrollers contain an APIfor In-Application Programming of flash + memory. This API also allows identification of the part. + Problem: + On the LPC43x0 microcontrollers, the IAP API is not present. The ISP interface is present + which allows the part to be identified externally (via the UART) but part identification is not + possible internally using the IAP call because it is not implemented. + The first word of the Part ID can be read directly from OTP at 0x40045000. The second word of the Part ID is always +'0' on flashless parts. */ + +bool iap_is_implemented(void) +{ + bool res; + if( *((uint32_t*)ROM_IAP_ADDR) != ROM_IAP_UNDEF_ADDR ) + { + res = true; + }else + { + res = false; + } + return res; +} + +isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res) +{ + uint32_t* p_u32_data; + + if( iap_is_implemented() ) + { + pROM_API->IAP( (uint32_t*)&iap_cmd_res->cmd_param, (uint32_t*)&iap_cmd_res->status_res); + }else + { + /* Alternative way to retrieve Part Id & Serial No on MCU with no IAP */ + switch(iap_cmd_res->cmd_param.command_code) + { + case IAP_CMD_READ_PART_ID_NO: + p_u32_data = (uint32_t*)ROM_OTP_PART_ID_ADDR; + iap_cmd_res->status_res.iap_result[0] = p_u32_data[0]; + iap_cmd_res->status_res.iap_result[1] = p_u32_data[1]; + iap_cmd_res->status_res.status_ret = CMD_SUCCESS; + break; + + case IAP_CMD_READ_SERIAL_NO: + p_u32_data = (uint32_t*)ROM_OTP_SERIAL_NO_ADDR; + iap_cmd_res->status_res.iap_result[0] = p_u32_data[0]; + iap_cmd_res->status_res.iap_result[1] = p_u32_data[1]; + iap_cmd_res->status_res.iap_result[2] = p_u32_data[2]; + iap_cmd_res->status_res.iap_result[3] = p_u32_data[3]; + iap_cmd_res->status_res.status_ret = CMD_SUCCESS; + break; + + default: + iap_cmd_res->status_res.status_ret = ERROR_IAP_NOT_IMPLEMENTED; + break; + } + } + return iap_cmd_res->status_res.status_ret; +} diff --git a/firmware/common/rom_iap.h b/firmware/common/rom_iap.h new file mode 100644 index 00000000..69761dbe --- /dev/null +++ b/firmware/common/rom_iap.h @@ -0,0 +1,121 @@ +/* + * Copyright 2013 Benjamin Vernoux + * + * This file is part of HackRF. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; see the file COPYING. If not, write to + * the Free Software Foundation, Inc., 51 Franklin Street, + * Boston, MA 02110-1301, USA. + */ + +#ifndef __ROM_IAP__ +#define __ROM_IAP__ + +#include + +typedef enum +{ + /* TODO define other commands */ + + IAP_CMD_INIT_IAP = 49, + /* Command Init IAP + Input Command code: 49 (decimal) + Return Code CMD_SUCCESS + Result None + Description Initializes and prepares the flash for erase and write operations. + Stack usage 88 B */ + + IAP_CMD_READ_PART_ID_NO = 54, + /* Read part identification number + Command Read part identification number + Input Command code: 54 (decimal) + Parameters:None + Return Code CMD_SUCCESS | + Result Result0:Part Identification Number. + Result1:Part Identification Number. + Description This command is used to read the part identification number. See Table 1082 + “LPC43xx part identification numbers”. + The command returns two words: word0 followed by word1. Word 0 corresponds + to the part id and word1 indicates the flash configuration or contains 0x0 for + flashless parts. + Stack usage 8 B */ + + IAP_CMD_READ_SERIAL_NO = 58 + /* Read device serial number + Input Command code: 58 (decimal) + Parameters: None + Return Code CMD_SUCCESS + Result Result0:First 32-bit word of Device Identification Number (at the lowest address) + Result1:Second 32-bit word of Device Identification Number + Result2:Third 32-bit word of Device Identification Number + Result3:Fourth 32-bit word of Device Identification Number + Description This command is used to read the device identification number. The serial number + may be used to uniquely identify a single unit among all LPC43xx devices. + Stack usage 8 B */ +} iap_cmd_code_t; + +/* ISP/IAP Return Code */ +typedef enum +{ + CMD_SUCCESS = 0x00000000, /* CMD_SUCCESS Command is executed successfully. Sent by ISP handler only when command given by the host has been completely and successfully executed. */ + INVALID_COMMAND = 0x00000001, /* Invalid command. */ + SRC_ADDR_ERROR = 0x00000002, /* Source address is not on word boundary. */ + DST_ADDR_ERROR = 0x00000003, /* Destination address not on word or 256 byte boundary. */ + SRC_ADDR_NOT_MAPPED = 0x00000004, /* Source address is not mapped in the memory map. Count value is taken into consideration where applicable. */ + DST_ADDR_NOT_MAPPED = 0x00000005, /* Destination address is not mapped in the memory map. Count value is taken into consideration where applicable.*/ + COUNT_ERROR = 0x00000006, /* Byte count is not multiple of 4 or is not a permitted value. */ + INVALID_SECTOR = 0x00000007, /* Sector number is invalid or end sector number is greater than start sector number. */ + SECTOR_NOT_BLANK = 0x00000008, /* Sector is not blank. */ + SECTOR_NOT_PREP_WRITE_OP = 0x00000009, /* Command to prepare sector for write operation was not executed. */ + COMPARE_ERROR = 0x0000000A, /* Source and destination data not equal. */ + BUSY = 0x0000000B, /* Flash programming hardware interface is busy. */ + PARAM_ERROR = 0x0000000C, /* Insufficient number of parameters or invalid parameter. */ + ADDR_ERROR = 0x0000000D, /* Address is not on word boundary. */ + ADDR_NOT_MAPPED = 0x0000000E, /* Address is not mapped in the memory map. Count value is taken in to consideration where applicable. */ + CMD_LOCKED = 0x0000000F, /* Command is locked. */ + INVALID_CODE = 0x00000010, /* Unlock code is invalid. */ + INVALID_BAUD_RATE = 0x00000011, /* Invalid baud rate setting. */ + INVALID_STOP_BIT = 0x00000012, /* Invalid stop bit setting. */ + CODE_READ_PROTECTION_ENABLED = 0x00000013, /* Code read protection enabled. */ + INVALID_FLASH_UNIT = 0x00000014, /* Invalid flash unit. */ + USER_CODE_CHECKSUM = 0x00000015, + ERROR_SETTING_ACTIVE_PARTITION = 0x00000016, + + /* Special Error */ + ERROR_IAP_NOT_IMPLEMENTED = 0x00000100 /* IAP is not implemented in this part */ +} isp_iap_ret_code_t; + +typedef struct +{ + /* Input Command/Param */ + struct + { + iap_cmd_code_t command_code; + uint32_t iap_param[5]; + } cmd_param; + + /* Output Status/Result */ + struct + { + isp_iap_ret_code_t status_ret; + uint32_t iap_result[4]; + } status_res; +} iap_cmd_res_t; + +/* Check if IAP is implemented */ +bool iap_is_implemented(void); + +isp_iap_ret_code_t iap_cmd_call(iap_cmd_res_t* iap_cmd_res); + +#endif//__ROM_IAP__ diff --git a/firmware/usb_performance/Makefile b/firmware/usb_performance/Makefile index b13d29e2..b6324b25 100644 --- a/firmware/usb_performance/Makefile +++ b/firmware/usb_performance/Makefile @@ -38,6 +38,7 @@ SRC = $(BINARY).c \ ../common/cpld_jtag.c \ ../common/xapp058/lenval.c \ ../common/xapp058/micro.c \ - ../common/xapp058/ports.c + ../common/xapp058/ports.c \ + ../common/rom_iap.c include ../common/Makefile_inc.mk diff --git a/firmware/usb_performance/Makefile_rom_to_ram b/firmware/usb_performance/Makefile_rom_to_ram index 0ec7bb8e..ea246313 100644 --- a/firmware/usb_performance/Makefile_rom_to_ram +++ b/firmware/usb_performance/Makefile_rom_to_ram @@ -38,7 +38,8 @@ SRC = usb_performance.c \ ../common/cpld_jtag.c \ ../common/xapp058/lenval.c \ ../common/xapp058/micro.c \ - ../common/xapp058/ports.c + ../common/xapp058/ports.c \ + ../common/rom_iap.c LDSCRIPT = ../common/LPC4330_M4_rom_to_ram.ld include ../common/Makefile_inc.mk diff --git a/firmware/usb_performance/usb_performance.c b/firmware/usb_performance/usb_performance.c index b8a6815c..38e0e334 100644 --- a/firmware/usb_performance/usb_performance.c +++ b/firmware/usb_performance/usb_performance.c @@ -34,6 +34,7 @@ #include #include #include +#include #include "usb.h" #include "usb_type.h" @@ -667,6 +668,47 @@ usb_request_status_t usb_vendor_request_set_amp_enable( } } +typedef struct { + uint32_t part_id[2]; + uint32_t serial_no[4]; +} read_partid_serialno_t; + +usb_request_status_t usb_vendor_request_read_partid_serialno( + usb_endpoint_t* const endpoint, const usb_transfer_stage_t stage) +{ + uint8_t length; + read_partid_serialno_t read_partid_serialno; + iap_cmd_res_t iap_cmd_res; + + if (stage == USB_TRANSFER_STAGE_SETUP) + { + /* Read IAP Part Number Identification */ + iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_PART_ID_NO; + iap_cmd_call(&iap_cmd_res); + if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS) + return USB_REQUEST_STATUS_STALL; + + read_partid_serialno.part_id[0] = iap_cmd_res.status_res.iap_result[0]; + read_partid_serialno.part_id[1] = iap_cmd_res.status_res.iap_result[1]; + + /* Read IAP Serial Number Identification */ + iap_cmd_res.cmd_param.command_code = IAP_CMD_READ_SERIAL_NO; + iap_cmd_call(&iap_cmd_res); + if(iap_cmd_res.status_res.status_ret != CMD_SUCCESS) + return USB_REQUEST_STATUS_STALL; + + read_partid_serialno.serial_no[0] = iap_cmd_res.status_res.iap_result[0]; + read_partid_serialno.serial_no[1] = iap_cmd_res.status_res.iap_result[1]; + read_partid_serialno.serial_no[2] = iap_cmd_res.status_res.iap_result[2]; + read_partid_serialno.serial_no[3] = iap_cmd_res.status_res.iap_result[3]; + + length = (uint8_t)sizeof(read_partid_serialno_t); + usb_endpoint_schedule(endpoint->in, &read_partid_serialno, length); + usb_endpoint_schedule_ack(endpoint->out); + } + return USB_REQUEST_STATUS_OK; +} + static const usb_request_handler_fn vendor_request_handler[] = { NULL, usb_vendor_request_set_transceiver_mode, @@ -685,7 +727,8 @@ static const usb_request_handler_fn vendor_request_handler[] = { usb_vendor_request_read_board_id, usb_vendor_request_read_version_string, usb_vendor_request_set_freq, - usb_vendor_request_set_amp_enable + usb_vendor_request_set_amp_enable, + usb_vendor_request_read_partid_serialno }; static const uint32_t vendor_request_handler_count = diff --git a/host/libhackrf/examples/hackrf_info.c b/host/libhackrf/examples/hackrf_info.c index 387a83ef..d83b9696 100644 --- a/host/libhackrf/examples/hackrf_info.c +++ b/host/libhackrf/examples/hackrf_info.c @@ -32,6 +32,7 @@ int main(int argc, char** argv) int result = HACKRF_SUCCESS; uint8_t board_id = BOARD_ID_INVALID; char version[255 + 1]; + read_partid_serialno_t read_partid_serialno; result = hackrf_init(); if (result != HACKRF_SUCCESS) { @@ -55,7 +56,6 @@ int main(int argc, char** argv) hackrf_error_name(result), result); return EXIT_FAILURE; } - printf("Board ID Number: %d (%s)\n", board_id, hackrf_board_id_name(board_id)); @@ -65,9 +65,23 @@ int main(int argc, char** argv) hackrf_error_name(result), result); return EXIT_FAILURE; } - printf("Firmware Version: %s\n", version); + result = hackrf_board_partid_serialno_read(device, &read_partid_serialno); + if (result != HACKRF_SUCCESS) { + fprintf(stderr, "hackrf_board_partid_serialno_read() failed: %s (%d)\n", + hackrf_error_name(result), result); + return EXIT_FAILURE; + } + printf("Part ID Number: 0x%08x 0x%08x\n", + read_partid_serialno.part_id[0], + read_partid_serialno.part_id[1]); + printf("Serial Number: 0x%08x 0x%08x 0x%08x 0x%08x\n", + read_partid_serialno.serial_no[0], + read_partid_serialno.serial_no[1], + read_partid_serialno.serial_no[2], + read_partid_serialno.serial_no[3]); + result = hackrf_close(device); if (result != HACKRF_SUCCESS) { fprintf(stderr, "hackrf_close() failed: %s (%d)\n", diff --git a/host/libhackrf/src/hackrf.c b/host/libhackrf/src/hackrf.c index 5bb77745..bb323cde 100644 --- a/host/libhackrf/src/hackrf.c +++ b/host/libhackrf/src/hackrf.c @@ -46,7 +46,8 @@ typedef enum { HACKRF_VENDOR_REQUEST_BOARD_ID_READ = 14, HACKRF_VENDOR_REQUEST_VERSION_STRING_READ = 15, HACKRF_VENDOR_REQUEST_SET_FREQ = 16, - HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17 + HACKRF_VENDOR_REQUEST_AMP_ENABLE = 17, + HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ = 18 } hackrf_vendor_request; typedef enum { @@ -629,6 +630,29 @@ int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value) return HACKRF_SUCCESS; } } + +int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno) +{ + uint8_t length; + + length = sizeof(read_partid_serialno_t); + int result = libusb_control_transfer( + device->usb_device, + LIBUSB_ENDPOINT_IN | LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_RECIPIENT_DEVICE, + HACKRF_VENDOR_REQUEST_BOARD_PARTID_SERIALNO_READ, + 0, + 0, + (unsigned char*)read_partid_serialno, + length, + 0 + ); + + if (result < length) { + return HACKRF_ERROR_LIBUSB; + } else { + return HACKRF_SUCCESS; + } +} static void* transfer_threadproc(void* arg) { hackrf_device* device = (hackrf_device*)arg; diff --git a/host/libhackrf/src/hackrf.h b/host/libhackrf/src/hackrf.h index c8dea87d..5a1314e2 100644 --- a/host/libhackrf/src/hackrf.h +++ b/host/libhackrf/src/hackrf.h @@ -52,6 +52,11 @@ typedef struct { int valid_length; } hackrf_transfer; +typedef struct { + uint32_t part_id[2]; + uint32_t serial_no[4]; +} read_partid_serialno_t; + typedef int (*hackrf_sample_block_cb_fn)(hackrf_transfer* transfer); int hackrf_init(); @@ -97,6 +102,8 @@ int hackrf_set_freq(hackrf_device* device, const uint64_t freq_hz); int hackrf_set_amp_enable(hackrf_device* device, const uint8_t value); +int hackrf_board_partid_serialno_read(hackrf_device* device, read_partid_serialno_t* read_partid_serialno); + const char* hackrf_error_name(enum hackrf_error errcode); const char* hackrf_board_id_name(enum hackrf_board_id board_id);