1
0
mirror of https://github.com/HEYAHONG/cc-tool.git synced 2025-05-09 04:00:59 +08:00
cc-tool/src/programmer/cc_programmer.cpp
2012-05-24 17:42:02 -07:00

382 lines
10 KiB
C++

/*
* cc_programmer.cpp
*
* Created on: Aug 4, 2011
* Author: George Stark <george-u@yandex.com>
*
* License: GNU GPL v2
*
*/
#include <stdio.h>
#include "cc_programmer.h"
#include "cc_251x_111x.h"
#include "cc_253x_2540.h"
#include "cc_243x.h"
#include "log.h"
const uint_t DEFAULT_TIMEOUT = 3000;
const uint_t MAX_ERASE_TIME = 8000;
const static USB_DeviceID DeviceTable[] = {
{ 0x0451, 0x16A2, "CC Debugger" },
{ 0x11A0, 0xDB20, "SmartRF04 Evaluation Board" },
{ 0x0451, 0x16A0, "SmartRF05 Evaluation Board" },
};
//==============================================================================
static void log_add_target_info(const UnitInfo &unit_info)
{
log_info("target, name: %s, chip ID: %02Xh, rev. %02Xh, flash: %u, ram: %u, flags: %02Xh",
unit_info.name.c_str(),
unit_info.internal_ID,
unit_info.revision,
unit_info.flash_size,
unit_info.ram_size,
unit_info.flags);
}
//==============================================================================
static void log_add_programmer_info(const CC_ProgrammerInfo &info)
{
log_info("device, name: %s, ID: %s, version: %04Xh, revision: %04Xh",
info.name.c_str(),
info.debugger_id.c_str(),
info.fw_version,
info.fw_revision);
}
//==============================================================================
CC_Programmer::CC_Programmer()
{
usb_device_.set_transfer_timeout(DEFAULT_TIMEOUT);
unit_drviers_.push_back(CC_UnitDriverPtr(new CC_253x_2540(usb_device_, pw_)));
unit_drviers_.push_back(CC_UnitDriverPtr(new CC_251x_111x(usb_device_, pw_)));
unit_drviers_.push_back(CC_UnitDriverPtr(new CC_243x(usb_device_, pw_)));
}
//==============================================================================
USB_DeviceIDVector CC_Programmer::supported_devices() const
{
USB_DeviceIDVector result;
foreach (const USB_DeviceID &item, DeviceTable)
result.push_back(item);
return result;
}
//==============================================================================
StringVector CC_Programmer::supported_unit_names() const
{
StringVector names;
foreach (const CC_UnitDriverPtr &item, unit_drviers_)
{
Unit_ID_List units;
item->supported_units(units);
foreach (Unit_ID &unit, units)
names.push_back(unit.name);
}
return names;
}
//==============================================================================
bool CC_Programmer::set_debug_interface_speed(CC_Programmer::InterfaceSpeed speed)
{
log_info("programmer, set debug interface speed %u", speed);
if (!opened())
return false;
const uint8_t USB_SET_DEBUG_INTERFACE_SPEED = 0xCF;
uint16_t value = (speed == CC_Programmer::IS_FAST) ? 0 : 1;
usb_device_.control_write(LIBUSB_REQUEST_TYPE_VENDOR,
USB_SET_DEBUG_INTERFACE_SPEED,
value, 0, NULL, 0);
return true;
}
//==============================================================================
bool CC_Programmer::programmer_info(CC_ProgrammerInfo &info)
{
if (opened())
{
info = programmer_info_;
return true;
}
return false;
}
//==============================================================================
void CC_Programmer::init_device()
{
usb_device_.set_configuration(1);
usb_device_.claim_interface(0);
request_device_info();
}
//==============================================================================
CC_Programmer::OpenResult CC_Programmer::open(uint_t bus, uint_t device)
{
if (!usb_device_.open_by_address(bus, device))
return OR_NOT_FOUND;
libusb_device_descriptor descriptor;
usb_device_.device_decriptor(descriptor);
foreach (const USB_DeviceID &item, DeviceTable)
{
if (descriptor.idProduct == item.product_id &&
descriptor.idVendor == item.vendor_id)
{
init_device();
return OR_OK;
}
}
return OR_NOT_SUPPORTED;
}
//==============================================================================
CC_Programmer::OpenResult CC_Programmer::open()
{
foreach (const USB_DeviceID &item, DeviceTable)
{
if (usb_device_.open_by_vid_pid(item.vendor_id, item.product_id))
{
programmer_info_.descripton = item.description;
break;
}
}
if (!usb_device_.opened())
return OR_NOT_FOUND;
init_device();
return OR_OK;
}
//==============================================================================
void CC_Programmer::close()
{ usb_device_.close(); }
//==============================================================================
bool CC_Programmer::opened() const
{ return usb_device_.opened(); }
//==============================================================================
void CC_Programmer::request_device_info()
{
libusb_device_descriptor device_descriptor;
usb_device_.device_decriptor(device_descriptor);
char DID[16];
sprintf(DID, "%02X%02X",
device_descriptor.bcdDevice >> 8,
device_descriptor.bcdDevice & 0xFF);
programmer_info_.debugger_id = DID;
usb_device_.string_descriptor_ascii(device_descriptor.iProduct, programmer_info_.name);
const uint8_t USB_REQUEST_GET_STATE = 0xC0;
log_info("programmer, request device state");
uint8_t info[8];
usb_device_.control_read(LIBUSB_REQUEST_TYPE_VENDOR, USB_REQUEST_GET_STATE,
0, 0, info, 8);
programmer_info_.fw_version = info[2] | info[3] << 8;
programmer_info_.fw_revision = info[4] | info[5] << 8;
unit_info_.ID = info[0] | info[1] << 8;
foreach (CC_UnitDriverPtr &driver, unit_drviers_)
{
Unit_ID_List units;
driver->supported_units(units);
foreach (Unit_ID &unit, units)
{
if (unit.ID == unit_info_.ID)
{
unit_info_.name = unit.name;
driver_ = driver;
break;
}
}
}
if (!driver_ && unit_info_.ID)
{
std::swap(info[0], info[1]);
unit_info_.name = "CC" + binary_to_hex(info, 2, "");
}
log_add_programmer_info(programmer_info_);
}
//==============================================================================
void CC_Programmer::unit_status(String &name, bool &supported) const
{
name = unit_info_.name;
supported = (driver_ != NULL);
}
//==============================================================================
void CC_Programmer::unit_close()
{ driver_->reset(false); }
//==============================================================================
void CC_Programmer::enter_debug_mode()
{
log_info("programmer, enter debug mode");
const uint8_t USB_PREPARE_DEBUG_MODE = 0xC5;
const uint8_t USB_SET_CHIP_INFO = 0xC8;
usb_device_.control_write(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
USB_PREPARE_DEBUG_MODE, 0, 0, NULL, 0);
ByteVector command(0x30, ' ');
memcpy(&command[0x00], unit_info_.name.c_str(), unit_info_.name.size());
memcpy(&command[0x10], "DID:", 4);
memcpy(&command[0x15], programmer_info_.debugger_id.c_str(), programmer_info_.debugger_id.size());
usb_device_.control_write(LIBUSB_REQUEST_TYPE_VENDOR | LIBUSB_ENDPOINT_OUT,
USB_SET_CHIP_INFO, 1, 1, &command[0], command.size());
}
//==============================================================================
bool CC_Programmer::unit_locked()
{
log_info("programmer, check if unit locked");
uint8_t status = 0;
driver_->read_debug_status(status);
return (status & DEBUG_STATUS_DEBUG_LOCKED);
}
//==============================================================================
bool CC_Programmer::unit_connect(UnitInfo &info)
{
log_info("programmer, connect target");
enter_debug_mode();
driver_->reset(true);
uint8_t status = 0;
driver_->read_debug_status(status);
if ((status & DEBUG_STATUS_DEBUG_LOCKED))
{
log_info("programmer, target is locked");
return true;
}
if (!(status & DEBUG_STATUS_CPU_HALTED))
{
log_info("programmer, halt failed");
return false;
}
driver_->write_debug_config(DEBUG_CONFIG_TIMER_SUSPEND | DEBUG_CONFIG_SOFT_POWER_MODE);
driver_->find_unit_info(unit_info_);
log_add_target_info(unit_info_);
info = unit_info_;
return true;
}
//==============================================================================
bool CC_Programmer::unit_reset()
{
driver_->reset(false);
return true;
}
//==============================================================================
bool CC_Programmer::unit_erase()
{
driver_->erase_start();
uint_t erase_timer = get_tick_count();
do
{
if (driver_->erase_check_comleted())
return true;
usleep(500 * 1000);
}
while ((get_tick_count() - erase_timer) <= MAX_ERASE_TIME);
return false; // erase timeout
}
//==============================================================================
void CC_Programmer::unit_read_info_page(ByteVector &info_page)
{
pw_.enable(false);
driver_->read_info_page(info_page);
}
//==============================================================================
void CC_Programmer::unit_mac_address_read(size_t index, ByteVector &mac_address)
{
pw_.enable(false);
driver_->mac_address_read(index, mac_address);
}
//==============================================================================
void CC_Programmer::unit_mac_address_write(ByteVector &mac_address)
{ }
//==============================================================================
void CC_Programmer::unit_flash_read(ByteVector &flash_data)
{
pw_.enable(true);
pw_.read_start(unit_info_.actual_flash_size());
driver_->flash_read_start();
driver_->flash_read_block(0, unit_info_.actual_flash_size(), flash_data);
driver_->flash_read_end();
pw_.read_finish();
}
//==============================================================================
bool CC_Programmer::unit_flash_verify(const DataSectionStore &sections,
CC_Programmer::VerifyMethod method)
{
log_info("programmer, verify flash, %u", method);
pw_.enable(true);
if (method == VM_BY_CRC)
return driver_->flash_verify_by_crc(sections);
return driver_->flash_verify_by_read(sections);
}
//==============================================================================
void CC_Programmer::unit_flash_write(const DataSectionStore &sections)
{
pw_.enable(true);
driver_->flash_write(sections);
}
//==============================================================================
bool CC_Programmer::unit_lock_write(const ByteVector &lock_data)
{
pw_.enable(false);
return driver_->lock_write(lock_data);
}
//==============================================================================
void CC_Programmer::do_on_flash_read_progress(
const ProgressWatcher::OnProgress::slot_type &slot)
{ pw_.do_on_read_progress(slot); }
//==============================================================================
void CC_Programmer::do_on_flash_write_progress(
const ProgressWatcher::OnProgress::slot_type &slot)
{ pw_.do_on_write_progress(slot); }