10 Commits

Author SHA1 Message Date
Marius Greuel
02150bbb26 Bump version to 6.3.1.1-windows 2021-01-27 16:51:06 +01:00
Marius Greuel
7d87a12d57 Improve Micronucleus programmer error messages 2021-01-26 22:23:25 +01:00
Marius Greuel
03eb736a62 Add Linux udev rules hint to readme.md 2021-01-26 22:22:41 +01:00
Marius Greuel
cb6208939b Add support for Teensy bootloader 2021-01-26 22:21:52 +01:00
Marius Greuel
8dce9107df Various improvements for FTDI support 2020-11-14 17:59:33 +01:00
Marius Greuel
61310bf1a3 Add Windows version resource to avrdude project 2020-10-06 21:04:13 +02:00
Marius Greuel
e8d42fc993 Add LOG_APPNAME define to libusb project 2020-10-06 20:37:25 +02:00
Marius Greuel
a8916983a0 Implement ftdi_set_interface for avrftdi 2020-10-06 20:36:52 +02:00
Marius Greuel
bc0245e41b Add more APIs for libwinftdi 2020-10-06 20:35:43 +02:00
Marius Greuel
fa608b5ddf Allow %n in printf format string for MSVC 2020-10-06 20:33:48 +02:00
22 changed files with 17331 additions and 78 deletions

View File

@@ -180,6 +180,8 @@ libavrdude_a_SOURCES = \
stk500v2_private.h \
stk500generic.c \
stk500generic.h \
teensy.c \
teensy.h \
tpi.h \
usbasp.c \
usbasp.h \

View File

@@ -898,6 +898,15 @@ programmer
usbpid = 0x0753;
;
programmer
id = "teensy";
desc = "Teensy Bootloader";
type = "teensy";
connection_type = usb;
usbvid = 0x16C0;
usbpid = 0x0478;
;
programmer
id = "butterfly";
desc = "Atmel Butterfly Development Board";

View File

@@ -92,6 +92,9 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>DEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
<ClCompile>
@@ -104,6 +107,9 @@
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>DEBUG;_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
@@ -121,6 +127,9 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
<ClCompile>
@@ -138,6 +147,9 @@
<OptimizeReferences>true</OptimizeReferences>
<GenerateDebugInformation>true</GenerateDebugInformation>
</Link>
<ResourceCompile>
<PreprocessorDefinitions>_UNICODE;UNICODE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
</ResourceCompile>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="arduino.c" />
@@ -182,6 +194,7 @@
<ClCompile Include="stk500.c" />
<ClCompile Include="stk500generic.c" />
<ClCompile Include="stk500v2.c" />
<ClCompile Include="teensy.c" />
<ClCompile Include="term.c" />
<ClCompile Include="update.c" />
<ClCompile Include="usbasp.c" />
@@ -231,7 +244,9 @@
<ClInclude Include="msvc\IntegerHandleMap.h" />
<ClInclude Include="msvc\pthread.h" />
<ClInclude Include="msvc\ReaderWriterLock.h" />
<ClInclude Include="msvc\resource.h" />
<ClInclude Include="msvc\semaphore.h" />
<ClInclude Include="msvc\version.h" />
<ClInclude Include="my_ddk_hidsdi.h" />
<ClInclude Include="par.h" />
<ClInclude Include="pickit2.h" />
@@ -244,6 +259,7 @@
<ClInclude Include="stk500v2.h" />
<ClInclude Include="stk500v2_private.h" />
<ClInclude Include="stk500_private.h" />
<ClInclude Include="teensy.h" />
<ClInclude Include="term.h" />
<ClInclude Include="tpi.h" />
<ClInclude Include="usbasp.h" />
@@ -273,6 +289,17 @@
<Project>{22615ec5-9dbc-4538-9c01-2cd535b3810b}</Project>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="msvc\avrdude.rc" />
</ItemGroup>
<ItemGroup>
<None Include="msvc\res\resource.rc2">
<FileType>Text</FileType>
</None>
<None Include="msvc\res\version.rc2">
<FileType>Text</FileType>
</None>
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>

View File

@@ -12,10 +12,13 @@
<Filter Include="3 Generated Files">
<UniqueIdentifier>{be5ce6e6-223e-4d41-8915-29103d899c5a}</UniqueIdentifier>
</Filter>
<Filter Include="4 msvc">
<Filter Include="4 Resource Files">
<UniqueIdentifier>{a7668888-00c6-4911-9e47-7af645f31778}</UniqueIdentifier>
</Filter>
<Filter Include="5 msvc">
<UniqueIdentifier>{dbbd7498-e1e9-4d80-b91f-137dc5b988f1}</UniqueIdentifier>
</Filter>
<Filter Include="4 msvc\sys">
<Filter Include="5 msvc\sys">
<UniqueIdentifier>{1cc9d4fb-f03f-48cb-8af7-3e96681dc03b}</UniqueIdentifier>
</Filter>
</ItemGroup>
@@ -140,6 +143,9 @@
<ClCompile Include="stk500v2.c">
<Filter>1 Source Files</Filter>
</ClCompile>
<ClCompile Include="teensy.c">
<Filter>1 Source Files</Filter>
</ClCompile>
<ClCompile Include="term.c">
<Filter>1 Source Files</Filter>
</ClCompile>
@@ -168,22 +174,22 @@
<Filter>3 Generated Files</Filter>
</ClCompile>
<ClCompile Include="msvc\getopt.c">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClCompile>
<ClCompile Include="msvc\gettimeofday.c">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClCompile>
<ClCompile Include="msvc\unistd.cpp">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClCompile>
<ClCompile Include="msvc\usb_com_helper.cpp">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClCompile>
<ClCompile Include="msvc\pthread.cpp">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClCompile>
<ClCompile Include="msvc\semaphore.cpp">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
@@ -301,6 +307,9 @@
<ClInclude Include="stk500v2_private.h">
<Filter>2 Header Files</Filter>
</ClInclude>
<ClInclude Include="teensy.h">
<Filter>2 Header Files</Filter>
</ClInclude>
<ClInclude Include="term.h">
<Filter>2 Header Files</Filter>
</ClInclude>
@@ -326,34 +335,53 @@
<Filter>3 Generated Files</Filter>
</ClInclude>
<ClInclude Include="msvc\getopt.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\unistd.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\sys\time.h">
<Filter>4 msvc\sys</Filter>
<Filter>5 msvc\sys</Filter>
</ClInclude>
<ClInclude Include="msvc\msvc_compat.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\usb_com_helper.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\usb_com_locator.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\pthread.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\semaphore.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\ReaderWriterLock.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\IntegerHandleMap.h">
<Filter>4 msvc</Filter>
<Filter>5 msvc</Filter>
</ClInclude>
<ClInclude Include="msvc\resource.h">
<Filter>2 Header Files</Filter>
</ClInclude>
<ClInclude Include="msvc\version.h">
<Filter>4 Resource Files</Filter>
</ClInclude>
</ItemGroup>
<ItemGroup>
<ResourceCompile Include="msvc\avrdude.rc">
<Filter>4 Resource Files</Filter>
</ResourceCompile>
</ItemGroup>
<ItemGroup>
<None Include="msvc\res\resource.rc2">
<Filter>4 Resource Files</Filter>
</None>
<None Include="msvc\res\version.rc2">
<Filter>4 Resource Files</Filter>
</None>
</ItemGroup>
</Project>

View File

@@ -46,6 +46,7 @@ static ftdi_chip_type MapChipType(ULONG type)
return TYPE_AM;
}
}
static int SetError(struct ftdi_context* ftdi, int result, const char* error_str)
{
if (ftdi != nullptr)
@@ -82,6 +83,42 @@ void ftdi_free(struct ftdi_context* ftdi)
int ftdi_set_interface(struct ftdi_context* ftdi, enum ftdi_interface interface)
{
if (ftdi == nullptr)
{
return SetError(ftdi, -2, "USB device unavailable");
}
if (ftdi->usb_dev != nullptr)
{
if (ftdi->index != (interface != INTERFACE_ANY ? interface : INTERFACE_A))
{
return SetError(ftdi, -3, "Interface can not be changed on an already open device");
}
}
switch (interface)
{
case INTERFACE_ANY:
case INTERFACE_A:
ftdi->interface = 0;
ftdi->index = INTERFACE_A;
break;
case INTERFACE_B:
ftdi->interface = 1;
ftdi->index = INTERFACE_B;
break;
case INTERFACE_C:
ftdi->interface = 2;
ftdi->index = INTERFACE_C;
break;
case INTERFACE_D:
ftdi->interface = 3;
ftdi->index = INTERFACE_D;
break;
default:
return SetError(ftdi, -1, "Unknown interface");
}
return 0;
}
@@ -93,7 +130,7 @@ int ftdi_init(struct ftdi_context* ftdi)
void ftdi_deinit(struct ftdi_context* ftdi)
{
if (ftdi->usb_dev != nullptr)
if (ftdi != nullptr && ftdi->usb_dev != nullptr)
{
std::unique_ptr<FtdiDevice> device(reinterpret_cast<FtdiDevice*>(ftdi->usb_dev));
ftdi->usb_dev = nullptr;
@@ -139,14 +176,21 @@ int ftdi_usb_open_desc_index(struct ftdi_context* ftdi, int vendor, int product,
}
auto device = std::make_unique<FtdiDevice>();
auto status = device->OpenBySerialNumber(info.SerialNumber);
FT_STATUS status = device->OpenBySerialNumber(info.SerialNumber);
if (status == FT_OK)
{
device->ResetDevice();
device->Purge();
device->SetBitMode(0, 0);
device->SetTimeouts(5000, 5000);
status = device->SetEventNotification(FT_EVENT_RXCHAR);
}
if (status != FT_OK)
{
return SetError(ftdi, -3, "failed to open device");
}
device->SetEventNotification(FT_EVENT_RXCHAR);
ftdi->type = MapChipType(info.Type);
ftdi->usb_dev = reinterpret_cast<struct libusb_device_handle*>(device.release());
return 0;

View File

@@ -114,30 +114,36 @@ namespace LibWinFtdi
if (m_module != nullptr)
return S_FALSE;
m_module = LoadLibraryExW(L"ftd2xx.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (m_module == nullptr)
HMODULE module = LoadLibraryExW(L"ftd2xx.dll", nullptr, LOAD_LIBRARY_SEARCH_SYSTEM32);
if (module == nullptr)
{
return HRESULT_FROM_WIN32(GetLastError());
}
HRESULT hr = S_OK;
if (FAILED(hr = LoadImport("FT_CreateDeviceInfoList", &FT_CreateDeviceInfoList)) ||
FAILED(hr = LoadImport("FT_GetDeviceInfoList", &FT_GetDeviceInfoList)) ||
FAILED(hr = LoadImport("FT_OpenEx", &FT_OpenEx)) ||
FAILED(hr = LoadImport("FT_Close", &FT_Close)) ||
FAILED(hr = LoadImport("FT_Purge", &FT_Purge)) ||
FAILED(hr = LoadImport("FT_SetTimeouts", &FT_SetTimeouts)) ||
FAILED(hr = LoadImport("FT_SetBaudRate", &FT_SetBaudRate)) ||
FAILED(hr = LoadImport("FT_SetBitMode", &FT_SetBitMode)) ||
FAILED(hr = LoadImport("FT_SetLatencyTimer", &FT_SetLatencyTimer)) ||
FAILED(hr = LoadImport("FT_GetQueueStatus", &FT_GetQueueStatus)) ||
FAILED(hr = LoadImport("FT_SetEventNotification", &FT_SetEventNotification)) ||
FAILED(hr = LoadImport("FT_Read", &FT_Read)) ||
FAILED(hr = LoadImport("FT_Write", &FT_Write)))
if (FAILED(hr = LoadImport(module, "FT_CreateDeviceInfoList", &FT_CreateDeviceInfoList)) ||
FAILED(hr = LoadImport(module, "FT_GetDeviceInfoList", &FT_GetDeviceInfoList)) ||
FAILED(hr = LoadImport(module, "FT_OpenEx", &FT_OpenEx)) ||
FAILED(hr = LoadImport(module, "FT_Close", &FT_Close)) ||
FAILED(hr = LoadImport(module, "FT_ResetDevice", &FT_ResetDevice)) ||
FAILED(hr = LoadImport(module, "FT_ResetPort", &FT_ResetPort)) ||
FAILED(hr = LoadImport(module, "FT_CyclePort", &FT_ResetPort)) ||
FAILED(hr = LoadImport(module, "FT_Purge", &FT_Purge)) ||
FAILED(hr = LoadImport(module, "FT_SetTimeouts", &FT_SetTimeouts)) ||
FAILED(hr = LoadImport(module, "FT_SetBaudRate", &FT_SetBaudRate)) ||
FAILED(hr = LoadImport(module, "FT_SetBitMode", &FT_SetBitMode)) ||
FAILED(hr = LoadImport(module, "FT_SetLatencyTimer", &FT_SetLatencyTimer)) ||
FAILED(hr = LoadImport(module, "FT_GetQueueStatus", &FT_GetQueueStatus)) ||
FAILED(hr = LoadImport(module, "FT_SetEventNotification", &FT_SetEventNotification)) ||
FAILED(hr = LoadImport(module, "FT_SetUSBParameters", &FT_SetUSBParameters)) ||
FAILED(hr = LoadImport(module, "FT_Read", &FT_Read)) ||
FAILED(hr = LoadImport(module, "FT_Write", &FT_Write)))
{
FreeLibrary(module);
return hr;
}
m_module = module;
return S_OK;
}
@@ -154,11 +160,12 @@ namespace LibWinFtdi
private:
template<typename T>
HRESULT LoadImport(LPCSTR lpProcName, T** ptr)
static HRESULT LoadImport(HMODULE module, LPCSTR lpProcName, T** ptr)
{
auto proc = GetProcAddress(m_module, lpProcName);
auto proc = GetProcAddress(module, lpProcName);
if (proc == nullptr)
{
*ptr = nullptr;
return HRESULT_FROM_WIN32(GetLastError());
}
@@ -169,18 +176,22 @@ namespace LibWinFtdi
private:
HMODULE m_module = nullptr;
public:
protected:
FT_STATUS(WINAPI* FT_CreateDeviceInfoList)(LPDWORD lpdwNumDevs) = nullptr;
FT_STATUS(WINAPI* FT_GetDeviceInfoList)(DeviceInfo* pDest, LPDWORD lpdwNumDevs) = nullptr;
FT_STATUS(WINAPI* FT_OpenEx)(PVOID pArg1, DWORD Flags, FT_HANDLE* pHandle) = nullptr;
FT_STATUS(WINAPI* FT_Close)(FT_HANDLE ftHandle) = nullptr;
FT_STATUS(WINAPI* FT_Purge)(FT_HANDLE ftHandle, ULONG Mask) = nullptr;
FT_STATUS(WINAPI* FT_SetTimeouts)(FT_HANDLE ftHandle, ULONG ReadTimeout, ULONG WriteTimeout) = nullptr;
FT_STATUS(WINAPI* FT_SetBaudRate)(FT_HANDLE ftHandle, ULONG BaudRate) = nullptr;
FT_STATUS(WINAPI* FT_ResetDevice)(FT_HANDLE ftHandle) = nullptr;
FT_STATUS(WINAPI* FT_ResetPort)(FT_HANDLE ftHandle) = nullptr;
FT_STATUS(WINAPI* FT_CyclePort)(FT_HANDLE ftHandle) = nullptr;
FT_STATUS(WINAPI* FT_Purge)(FT_HANDLE ftHandle, DWORD dwMask) = nullptr;
FT_STATUS(WINAPI* FT_SetTimeouts)(FT_HANDLE ftHandle, DWORD dwReadTimeout, DWORD dwWriteTimeout) = nullptr;
FT_STATUS(WINAPI* FT_SetBaudRate)(FT_HANDLE ftHandle, DWORD dwBaudRate) = nullptr;
FT_STATUS(WINAPI* FT_SetBitMode)(FT_HANDLE ftHandle, UCHAR ucMask, UCHAR ucEnable) = nullptr;
FT_STATUS(WINAPI* FT_SetLatencyTimer)(FT_HANDLE ftHandle, UCHAR ucLatency) = nullptr;
FT_STATUS(WINAPI* FT_SetLatencyTimer)(FT_HANDLE ftHandle, UCHAR ucTimer) = nullptr;
FT_STATUS(WINAPI* FT_GetQueueStatus)(FT_HANDLE ftHandle, DWORD* dwRxBytes) = nullptr;
FT_STATUS(WINAPI* FT_SetEventNotification)(FT_HANDLE ftHandle, DWORD Mask, PVOID Param) = nullptr;
FT_STATUS(WINAPI* FT_SetUSBParameters)(FT_HANDLE ftHandle, DWORD dwInTransferSize, DWORD dwOutTransferSize) = nullptr;
FT_STATUS(WINAPI* FT_Read)(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned) = nullptr;
FT_STATUS(WINAPI* FT_Write)(FT_HANDLE ftHandle, LPVOID lpBuffer, DWORD dwBytesToWrite, LPDWORD lpBytesWritten) = nullptr;
};
@@ -278,34 +289,64 @@ namespace LibWinFtdi
return FT_Close(m_handle);
}
FT_STATUS Purge(ULONG Mask = FT_PURGE_RX | FT_PURGE_TX)
FT_STATUS ResetDevice()
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_Purge(m_handle, Mask);
return FT_ResetDevice(m_handle);
}
FT_STATUS SetTimeouts(ULONG ReadTimeout, ULONG WriteTimeout)
FT_STATUS ResetPort()
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_SetTimeouts(m_handle, ReadTimeout, WriteTimeout);
return FT_ResetPort(m_handle);
}
FT_STATUS SetBaudRate(ULONG BaudRate)
FT_STATUS CyclePort()
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_SetBaudRate(m_handle, BaudRate);
return FT_CyclePort(m_handle);
}
FT_STATUS Purge(DWORD dwMask = FT_PURGE_RX | FT_PURGE_TX)
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_Purge(m_handle, dwMask);
}
FT_STATUS SetTimeouts(DWORD dwReadTimeout, DWORD dwWriteTimeout)
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_SetTimeouts(m_handle, dwReadTimeout, dwWriteTimeout);
}
FT_STATUS SetBaudRate(DWORD dwBaudRate)
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_SetBaudRate(m_handle, dwBaudRate);
}
FT_STATUS SetBitMode(UCHAR ucMask, UCHAR ucEnable)
@@ -318,14 +359,14 @@ namespace LibWinFtdi
return FT_SetBitMode(m_handle, ucMask, ucEnable);
}
FT_STATUS SetLatencyTimer(UCHAR ucLatency)
FT_STATUS SetLatencyTimer(UCHAR ucTimer)
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_SetLatencyTimer(m_handle, ucLatency);
return FT_SetLatencyTimer(m_handle, ucTimer);
}
FT_STATUS GetQueueStatus(DWORD* dwRxBytes)
@@ -353,6 +394,16 @@ namespace LibWinFtdi
return FT_SetEventNotification(m_handle, Mask, m_event);
}
FT_STATUS SetUSBParameters(DWORD dwInTransferSize, DWORD dwOutTransferSize)
{
if (FAILED(Load()))
{
return FT_INVALID_HANDLE;
}
return FT_SetUSBParameters(m_handle, dwInTransferSize, dwOutTransferSize);
}
FT_STATUS Read(LPVOID lpBuffer, DWORD dwBytesToRead, LPDWORD lpBytesReturned)
{
if (FAILED(Load()))

View File

@@ -103,7 +103,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;LOG_APPNAME="avrdude";WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<AdditionalIncludeDirectories>include</AdditionalIncludeDirectories>
@@ -118,7 +118,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;LOG_APPNAME="avrdude";WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
@@ -134,7 +134,7 @@
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;LOG_APPNAME="avrdude";_DEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>
<AdditionalIncludeDirectories>include</AdditionalIncludeDirectories>
@@ -149,7 +149,7 @@
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<SDLCheck>true</SDLCheck>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<PreprocessorDefinitions>_CRT_SECURE_NO_WARNINGS;LOG_APPNAME="avrdude";NDEBUG;_LIB;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<ConformanceMode>true</ConformanceMode>
<RuntimeLibrary>MultiThreaded</RuntimeLibrary>
<DisableSpecificWarnings>4996</DisableSpecificWarnings>

View File

@@ -140,7 +140,6 @@ int usb_os_find_devices(struct usb_bus* bus, struct usb_device** devices)
if (FAILED(item->Open(driver)) ||
FAILED(driver->GetDescriptor(USB_DT_DEVICE, 0, 0, &dev->descriptor, sizeof(dev->descriptor), nullptr, 5000)))
{
USBERR0("couldn't read device descriptor\n");
free(dev);
continue;
}

4
main.c
View File

@@ -353,6 +353,10 @@ int main(int argc, char * argv [])
char * homedir;
#endif
#ifdef _MSC_VER
_set_printf_count_output(1);
#endif
/*
* Set line buffering for file descriptors so we see stdout and stderr
* properly interleaved.

View File

@@ -562,9 +562,12 @@ static void micronucleus_powerdown(PROGRAMMER* pgm)
pdata->write_last_page = false;
uint8_t* buffer = (unsigned char*)malloc(pdata->page_size);
memset(buffer, 0xFF, pdata->page_size);
micronucleus_write_page(pdata, pdata->bootloader_start - pdata->page_size, buffer, pdata->page_size);
free(buffer);
if (buffer != NULL)
{
memset(buffer, 0xFF, pdata->page_size);
micronucleus_write_page(pdata, pdata->bootloader_start - pdata->page_size, buffer, pdata->page_size);
free(buffer);
}
}
if (pdata->start_program)
@@ -644,6 +647,13 @@ static int micronucleus_open(PROGRAMMER* pgm, char* port)
}
}
if (port != NULL && dev_name == NULL)
{
avrdude_message(MSG_INFO, "%s: ERROR: Invalid -P value: '%s'\n", progname, port);
avrdude_message(MSG_INFO, "%sUse -P usb:bus:device\n", progbuf);
return -1;
}
// Determine VID/PID
int vid = pgm->usbvid ? pgm->usbvid : MICRONUCLEUS_VID;
int pid = MICRONUCLEUS_PID;
@@ -707,8 +717,7 @@ static int micronucleus_open(PROGRAMMER* pgm, char* port)
pdata->usb_handle = usb_open(device);
if (pdata->usb_handle == NULL)
{
avrdude_message(MSG_INFO, "%s: WARNING: cannot open USB device: %s\n", progname, usb_strerror());
continue;
avrdude_message(MSG_INFO, "%s: ERROR: Failed to open USB device: %s\n", progname, usb_strerror());
}
}
}
@@ -730,13 +739,6 @@ static int micronucleus_open(PROGRAMMER* pgm, char* port)
break;
}
if (port != NULL && dev_name == NULL)
{
avrdude_message(MSG_INFO, "%s: ERROR: Invalid -P value: '%s'\n", progname, port);
avrdude_message(MSG_INFO, "%sUse -P usb:bus:device\n", progbuf);
return -1;
}
if (!pdata->usb_handle)
{
avrdude_message(MSG_INFO, "%s: ERROR: Could not find device with Micronucleus bootloader (%04X:%04X)\n",
@@ -821,6 +823,11 @@ static int micronucleus_paged_write(PROGRAMMER* pgm, AVRPART* p, AVRMEM* mem,
}
uint8_t* page_buffer = (uint8_t*)malloc(pdata->page_size);
if (page_buffer == NULL)
{
avrdude_message(MSG_INFO, "%s: Failed to allocate memory\n", progname);
return -1;
}
// Note: Page size reported by the bootloader may be smaller than device page size as configured in avrdude.conf.
int result = 0;
@@ -866,7 +873,7 @@ static int micronucleus_parseextparams(PROGRAMMER* pgm, LISTID xparams)
}
else
{
avrdude_message(MSG_INFO, "%s: invalid extended parameter '%s'\n", progname, param);
avrdude_message(MSG_INFO, "%s: Invalid extended parameter '%s'\n", progname, param);
return -1;
}
}
@@ -904,7 +911,7 @@ void micronucleus_initpgm(PROGRAMMER* pgm)
// Give a proper error if we were not compiled with libusb
static int micronucleus_nousb_open(struct programmer_t* pgm, char* name)
{
avrdude_message(MSG_INFO, "%s: error: no usb support. Please compile again with libusb installed.\n", progname);
avrdude_message(MSG_INFO, "%s: error: No usb support. Please compile again with libusb installed.\n", progname);
return -1;
}

BIN
msvc/avrdude.rc Normal file

Binary file not shown.

View File

@@ -173,7 +173,7 @@
#define PACKAGE_NAME "avrdude"
/* Define to the full name and version of this package. */
#define PACKAGE_STRING "avrdude 6.3.1.0-windows"
#define PACKAGE_STRING "avrdude 6.3.1.1-windows"
/* Define to the one symbol short name of this package. */
#define PACKAGE_TARNAME "avrdude"
@@ -182,7 +182,7 @@
#define PACKAGE_URL ""
/* Define to the version of this package. */
#define PACKAGE_VERSION "6.3.1.0-windows"
#define PACKAGE_VERSION "6.3.1.1-windows"
/* Define to 1 if you have the ANSI C header files. */
#define STDC_HEADERS 1
@@ -191,7 +191,7 @@
#define TIME_WITH_SYS_TIME 1
/* Version number of package */
#define VERSION "6.3.1.0-windows"
#define VERSION "6.3.1.1-windows"
/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
`char[]'. */

16244
msvc/generated/avrdude.conf Normal file

File diff suppressed because it is too large Load Diff

16
msvc/res/resource.rc2 Normal file
View File

@@ -0,0 +1,16 @@
//
// resource.rc2
// Copyright (C) 2020 Marius Greuel. All rights reserved.
//
#ifdef APSTUDIO_INVOKED
#error this file is not editable by Microsoft Visual C++
#endif //APSTUDIO_INVOKED
#pragma code_page(1252)
//////////////////////////////////////////////////////////////////////////// Version
LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
#include "version.rc2"

102
msvc/res/version.rc2 Normal file
View File

@@ -0,0 +1,102 @@
//
// Version.rc2
// Copyright (C) 2020 Marius Greuel. All rights reserved.
//
/////////////////////////////////////////////////////////////////////////////
#include "..\version.h"
#define _STR(s) #s
#define _VER_STR(a, b, c, d) _STR(a) "." _STR(b) "." _STR(c) "." _STR(d)
#ifndef VER_FILEVERSION
#define VER_FILEVERSION VER_MAJOR,VER_MINOR,VER_BUILD,VER_REVISION
#endif
#ifndef VER_FILEVERSION_STR
#define VER_FILEVERSION_STR _VER_STR(VER_MAJOR, VER_MINOR, VER_BUILD, VER_REVISION)
#endif
#ifndef VER_PRODUCTVERSION
#define VER_PRODUCTVERSION VER_FILEVERSION
#endif
#ifndef VER_PRODUCTVERSION_STR
#define VER_PRODUCTVERSION_STR VER_FILEVERSION_STR
#endif
#ifndef VER_COMPANYNAME_STR
#define VER_COMPANYNAME_STR "Marius Greuel"
#endif
#ifndef VER_FILEDESCRIPTION_STR
#define VER_FILEDESCRIPTION_STR "AVRDUDE"
#endif
#ifndef VER_PRODUCTNAME_STR
#define VER_PRODUCTNAME_STR "AVRDUDE"
#endif
#ifndef VER_INTERNALNAME_STR
#define VER_INTERNALNAME_STR "avrdude.exe"
#endif
#ifndef VER_LEGALCOPYRIGHT_STR
#define VER_LEGALCOPYRIGHT_STR "\251 2020 The AVRDUDE authors."
#endif
#ifndef VER_ORIGINALFILENAME_STR
#define VER_ORIGINALFILENAME_STR VER_INTERNALNAME_STR
#endif
#ifndef VER_FILETYPE
#define VER_FILETYPE VFT_APP
#define VER_FILESUBTYPE 0
#endif
#ifdef RC_INVOKED
#ifdef DEBUG
#define VER_DEBUG VS_FF_DEBUG
#else
#define VER_DEBUG 0
#endif
#define VER_FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
#define VER_FILEOS VOS__WINDOWS32
#define VER_FILEFLAGS (VER_DEBUG)
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
PRODUCTVERSION VER_PRODUCTVERSION
FILEFLAGSMASK VER_FILEFLAGSMASK
FILEFLAGS VER_FILEFLAGS
FILEOS VER_FILEOS
FILETYPE VER_FILETYPE
FILESUBTYPE VER_FILESUBTYPE
BEGIN
BLOCK "StringFileInfo"
BEGIN
BLOCK "040904b0" // LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP
BEGIN
#ifdef VER_COMMENTS_STR
VALUE "Comments", VER_COMMENTS_STR
#endif
VALUE "CompanyName", VER_COMPANYNAME_STR
VALUE "FileDescription", VER_FILEDESCRIPTION_STR
VALUE "FileVersion", VER_FILEVERSION_STR
VALUE "InternalName", VER_INTERNALNAME_STR
VALUE "LegalCopyright", VER_LEGALCOPYRIGHT_STR
VALUE "OriginalFilename",VER_ORIGINALFILENAME_STR
VALUE "ProductName", VER_PRODUCTNAME_STR
VALUE "ProductVersion", VER_PRODUCTVERSION_STR
END
END
BLOCK "VarFileInfo"
BEGIN
VALUE "Translation", 0x0409, 1200 //LANG_ENGLISH/SUBLANG_ENGLISH_US, Unicode CP
END
END
#endif // RC_INVOKED

BIN
msvc/resource.h Normal file

Binary file not shown.

14
msvc/version.h Normal file
View File

@@ -0,0 +1,14 @@
//
// version.h
// Copyright (C) 2020 Marius Greuel. All rights reserved.
//
#define PRD_MAJOR 6
#define PRD_MINOR 3
#define PRD_BUILD 1
#define PRD_REVISION 0
#define VER_MAJOR PRD_MAJOR
#define VER_MINOR PRD_MINOR
#define VER_BUILD PRD_BUILD
#define VER_REVISION PRD_REVISION

View File

@@ -48,6 +48,7 @@
#include "stk500.h"
#include "stk500generic.h"
#include "stk500v2.h"
#include "teensy.h"
#include "usbasp.h"
#include "usbtiny.h"
#include "wiring.h"
@@ -94,6 +95,7 @@ const PROGRAMMER_TYPE programmers_types[] = {
{"stk600", stk600_initpgm, stk600_desc},
{"stk600hvsp", stk600hvsp_initpgm, stk600hvsp_desc},
{"stk600pp", stk600pp_initpgm, stk600pp_desc},
{"teensy", teensy_initpgm, teensy_desc},
{"usbasp", usbasp_initpgm, usbasp_desc},
{"usbtiny", usbtiny_initpgm, usbtiny_desc},
{"wiring", wiring_initpgm, wiring_desc},

View File

@@ -10,6 +10,7 @@ Noteable changes include:
- Support Atmel AVR programmers out of the box
- Support Micronucleus bootloader
- Support Teensy HalfKay bootloader
- Support COM port discovery via USB VID/PID
- Support Arduino Leonardo bootloader auto-reset
- Support WinUSB devices via custom libusb
@@ -18,6 +19,12 @@ Noteable changes include:
- Support Visual Studio
- Miscellaneous bug-fixes and patches
## Download
To get the latest version of **AVRDUDE for Windows**, go to the [releases folder](https://github.com/mariusgreuel/avrdude/releases):
<https://github.com/mariusgreuel/avrdude/releases>
## Feature Details
### Support Atmel AVR programmers out of the box
@@ -44,7 +51,27 @@ As it does not support reading, use the -V option to prevent AVRDUDE from verifi
#### Example: Flashing a Micronucleus bootloader device
```bash
AVRDUDE -c micronucleus -p t85 -x wait -V -U flash:w:main.hex:i
avrdude -c micronucleus -p t85 -x wait -V -U flash:w:main.hex:i
```
### Support Teensy HalfKay bootloader
This build adds support for the [Teensy HalfKay bootloader](https://www.pjrc.com/teensy/halfkay_protocol.html), so you do no longer need a the Teensy Loader tool when working with Teensy devices.
Since this bootloader is optimized for size, it implements writing to flash memory only.
As it does not support reading, use the -V option to prevent AVRDUDE from verifing the flash memory. To have AVRDUDE wait for the device to be connected, use the extended option '-x wait'.
Supported devices are:
- Teensy 1.0 (AT90USB162)
- Teensy 2.0 (ATmega32U4)
- Teensy++ 1.0 (AT90USB646)
- Teensy++ 2.0 (AT90USB1286)
#### Example: Flashing a Teensy 2.0 device
```bash
avrdude -c teensy -p m32u4 -x wait -V -U flash:w:main.hex:i
```
### Support COM port discovery via USB VID/PID
@@ -157,13 +184,17 @@ Note: The folder `msvc\generated` includes pre-built files from the AVRDUDE conf
### Building AVRDUDE for Linux
Note that the AVRDUDE for Linux version does not contain all extra Windows features. The features that have been added to the stock version of AVRDUDE include:
- Support Micronucleus bootloader
- Support Teensy HalfKay bootloader
#### Linux Prerequisites
In order to build AVRDUDE on Linux, you need the following packages:
In order to build AVRDUDE on Linux, you need to install the following packages:
```bash
sudo apt install make gcc automake libtool flex bison
sudo apt install libelf-dev libusb-dev libftdi1-dev libhidapi-dev
sudo apt install git make gcc automake libtool flex bison libelf-dev libusb-dev libftdi1-dev libhidapi-dev
```
#### Linux Build Instructions
@@ -178,6 +209,25 @@ cd avrdude
make
```
To install a local build of AVRDUDE on your system, run the following command:
```bash
sudo make install
```
#### Linux udev rules
If you intent to use either the Micronucleus or Teensy bootloader, you should edit the udev rules so that you can run AVRDUDE without root.
For instance, if you are on Ubuntu and you installed the avrdude package, you would edit `/lib/udev/rules.d/60-avrdude.rules` and add the following rules:
```bash
# Micronucleus Bootloader
SUBSYSTEM=="usb", ATTR{idVendor}=="16d0", ATTR{idProduct}=="0753", TAG+="uaccess"
# Teensy Bootloader
SUBSYSTEM=="usb", ATTR{idVendor}=="16c0", ATTR{idProduct}=="0478", TAG+="uaccess"
```
## Troubleshooting Tips & Tricks
### Atmel DFU Device driver broken

616
teensy.c Normal file
View File

@@ -0,0 +1,616 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2020 Marius Greuel
*
* 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 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
// Notes:
// This file adds support for the HalfKay bootloader,
// so you do no longer need the Teensy loader utility.
//
// This HalfKay bootloader is used on various PJRC Teensy boards,
// such as Teensy 2.0 (ATmega32U4), Teensy++ 2.0 (AT90USB1286),
// and the respective clones.
// By default, it bootloader uses the VID/PID 16C0:0478 (VOTI).
//
// As the Teensy bootloader is optimized for size, it implements
// writing to flash memory only. Since it does not support reading,
// use the -V option to prevent avrdude from verifing the flash memory.
// To have avrdude wait for the device to be connected, use the
// extended option '-x wait'.
//
// Example:
// avrdude -c teensy -p m32u4 -x wait -V -U flash:w:main.hex:i
#include "ac_cfg.h"
#include <stdint.h>
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <unistd.h>
#include "avrdude.h"
#include "teensy.h"
#include "usbdevs.h"
#if defined(HAVE_LIBHIDAPI)
#include <hidapi/hidapi.h>
//-----------------------------------------------------------------------------
#define TEENSY_CONNECT_WAIT 100
#define PDATA(pgm) ((pdata_t*)(pgm->cookie))
//-----------------------------------------------------------------------------
typedef struct pdata
{
hid_device* hid_handle;
uint16_t hid_usage;
// Extended parameters
bool wait_until_device_present;
// Bootloader info (from hid_usage)
const char* board;
uint32_t flash_size;
uint16_t page_size;
uint8_t sig_bytes[3];
// State
bool erase_flash;
bool reboot;
} pdata_t;
//-----------------------------------------------------------------------------
static void delay_ms(uint32_t duration)
{
usleep(duration * 1000);
}
static int teensy_get_bootloader_info(pdata_t* pdata, AVRPART* p)
{
switch (pdata->hid_usage)
{
case 0x19:
pdata->board = "Teensy 1.0 (AT90USB162)";
pdata->flash_size = 0x4000 - 0x200;
pdata->page_size = 128;
pdata->sig_bytes[0] = 0x1E;
pdata->sig_bytes[1] = 0x94;
pdata->sig_bytes[2] = 0x82;
break;
case 0x1A:
pdata->board = "Teensy++ 1.0 (AT90USB646)";
pdata->flash_size = 0x10000 - 0x400;
pdata->page_size = 256;
pdata->sig_bytes[0] = 0x1E;
pdata->sig_bytes[1] = 0x96;
pdata->sig_bytes[2] = 0x82;
break;
case 0x1B:
pdata->board = "Teensy 2.0 (ATmega32U4)";
pdata->flash_size = 0x8000 - 0x200;
pdata->page_size = 128;
pdata->sig_bytes[0] = 0x1E;
pdata->sig_bytes[1] = 0x95;
pdata->sig_bytes[2] = 0x87;
break;
case 0x1C:
pdata->board = "Teensy++ 2.0 (AT90USB1286)";
pdata->flash_size = 0x20000 - 0x400;
pdata->page_size = 256;
pdata->sig_bytes[0] = 0x1E;
pdata->sig_bytes[1] = 0x97;
pdata->sig_bytes[2] = 0x82;
break;
default:
if (pdata->hid_usage == 0)
{
// On Linux, libhidapi does not seem to return the HID usage from the report descriptor.
// We try to infer the board from the part information, until somebody fixes libhidapi.
// To use this workaround, the -F option is required.
avrdude_message(MSG_INFO, "%s: WARNING: Cannot detect board type (HID usage is 0)\n", progname);
AVRMEM* mem = avr_locate_mem(p, "flash");
if (mem == NULL)
{
avrdude_message(MSG_INFO, "No flash memory for part %s\n", p->desc);
return -1;
}
pdata->board = "Unknown Board";
pdata->flash_size = mem->size - (mem->size < 0x10000 ? 0x200 : 0x400);
pdata->page_size = mem->page_size;
// Pass an invalid signature to require -F option.
pdata->sig_bytes[0] = 0x1E;
pdata->sig_bytes[1] = 0x00;
pdata->sig_bytes[2] = 0x00;
}
else
{
avrdude_message(MSG_INFO, "%s: ERROR: Teensy board not supported (HID usage 0x%02X)\n",
progname, pdata->hid_usage);
return -1;
}
}
return 0;
}
static void teensy_dump_device_info(pdata_t* pdata)
{
avrdude_message(MSG_NOTICE, "%s: HID usage: 0x%02X\n", progname, pdata->hid_usage);
avrdude_message(MSG_NOTICE, "%s: Board: %s\n", progname, pdata->board);
avrdude_message(MSG_NOTICE, "%s: Available flash size: %u\n", progname, pdata->flash_size);
avrdude_message(MSG_NOTICE, "%s: Page size: %u\n", progname, pdata->page_size);
avrdude_message(MSG_NOTICE, "%s: Signature: 0x%02X%02X%02X\n", progname,
pdata->sig_bytes[0], pdata->sig_bytes[1], pdata->sig_bytes[2]);
}
static int teensy_write_page(pdata_t* pdata, uint32_t address, const uint8_t* buffer, uint32_t size)
{
avrdude_message(MSG_DEBUG, "%s: teensy_write_page(address=0x%06X, size=%d)\n", progname, address, size);
if (size > pdata->page_size)
{
avrdude_message(MSG_INFO, "%s: ERROR: Invalid page size: %u\n", progname, pdata->page_size);
return -1;
}
size_t report_size = 1 + 2 + (size_t)pdata->page_size;
uint8_t* report = (uint8_t*)malloc(report_size);
if (report == NULL)
{
avrdude_message(MSG_INFO, "%s: ERROR: Failed to allocate memory\n", progname);
return -1;
}
report[0] = 0; // report number
if (pdata->page_size <= 256 && pdata->flash_size < 0x10000)
{
report[1] = (uint8_t)(address >> 0);
report[2] = (uint8_t)(address >> 8);
}
else
{
report[1] = (uint8_t)(address >> 8);
report[2] = (uint8_t)(address >> 16);
}
if (size > 0)
{
memcpy(report + 1 + 2, buffer, size);
}
memset(report + 1 + 2 + size, 0xFF, report_size - (1 + 2 + size));
int result = hid_write(pdata->hid_handle, report, report_size);
free(report);
if (result < 0)
{
avrdude_message(MSG_INFO, "%s: WARNING: Failed to write page: %ls\n",
progname, hid_error(pdata->hid_handle));
return result;
}
return 0;
}
static int teensy_erase_flash(pdata_t* pdata)
{
avrdude_message(MSG_DEBUG, "%s: teensy_erase_flash()\n", progname);
// Write a dummy page at address 0 to explicitly erase the flash.
return teensy_write_page(pdata, 0, NULL, 0);
}
static int teensy_reboot(pdata_t* pdata)
{
avrdude_message(MSG_DEBUG, "%s: teensy_reboot()\n", progname);
// Write a dummy page at address -1 to reboot the Teensy.
return teensy_write_page(pdata, 0xFFFFFFFF, NULL, 0);
}
//-----------------------------------------------------------------------------
static void teensy_setup(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_setup()\n", progname);
if ((pgm->cookie = malloc(sizeof(pdata_t))) == NULL)
{
avrdude_message(MSG_INFO, "%s: ERROR: Failed to allocate memory\n", progname);
exit(1);
}
memset(pgm->cookie, 0, sizeof(pdata_t));
}
static void teensy_teardown(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_teardown()\n", progname);
free(pgm->cookie);
}
static int teensy_initialize(PROGRAMMER* pgm, AVRPART* p)
{
avrdude_message(MSG_DEBUG, "%s: teensy_initialize()\n", progname);
pdata_t* pdata = PDATA(pgm);
int result = teensy_get_bootloader_info(pdata, p);
if (result < 0)
return result;
teensy_dump_device_info(pdata);
return 0;
}
static void teensy_display(PROGRAMMER* pgm, const char* prefix)
{
avrdude_message(MSG_DEBUG, "%s: teensy_display()\n", progname);
}
static void teensy_powerup(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_powerup()\n", progname);
}
static void teensy_powerdown(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_powerdown()\n", progname);
pdata_t* pdata = PDATA(pgm);
if (pdata->erase_flash)
{
teensy_erase_flash(pdata);
pdata->erase_flash = false;
}
if (pdata->reboot)
{
teensy_reboot(pdata);
pdata->reboot = false;
}
}
static void teensy_enable(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_enable()\n", progname);
}
static void teensy_disable(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_disable()\n", progname);
}
static int teensy_program_enable(PROGRAMMER* pgm, AVRPART* p)
{
avrdude_message(MSG_DEBUG, "%s: teensy_program_enable()\n", progname);
return 0;
}
static int teensy_read_sig_bytes(PROGRAMMER* pgm, AVRPART* p, AVRMEM* mem)
{
avrdude_message(MSG_DEBUG, "%s: teensy_read_sig_bytes()\n", progname);
if (mem->size < 3)
{
avrdude_message(MSG_INFO, "%s: memory size too small for read_sig_bytes\n", progname);
return -1;
}
pdata_t* pdata = PDATA(pgm);
memcpy(mem->buf, pdata->sig_bytes, sizeof(pdata->sig_bytes));
return 0;
}
static int teensy_chip_erase(PROGRAMMER* pgm, AVRPART* p)
{
avrdude_message(MSG_DEBUG, "%s: teensy_chip_erase()\n", progname);
pdata_t* pdata = PDATA(pgm);
// Schedule a chip erase, either at first write or on powerdown.
pdata->erase_flash = true;
return 0;
}
static int teensy_open(PROGRAMMER* pgm, char* port)
{
avrdude_message(MSG_DEBUG, "%s: teensy_open(\"%s\")\n", progname, port);
pdata_t* pdata = PDATA(pgm);
char* bus_name = NULL;
char* dev_name = NULL;
// if no -P was given or '-P usb' was given
if (strcmp(port, "usb") == 0)
{
port = NULL;
}
else
{
// calculate bus and device names from -P option
if (strncmp(port, "usb", 3) == 0 && ':' == port[3])
{
bus_name = port + 4;
dev_name = strchr(bus_name, ':');
if (dev_name != NULL)
{
*dev_name = '\0';
dev_name++;
}
}
}
if (port != NULL && dev_name == NULL)
{
avrdude_message(MSG_INFO, "%s: ERROR: Invalid -P value: '%s'\n", progname, port);
avrdude_message(MSG_INFO, "%sUse -P usb:bus:device\n", progbuf);
return -1;
}
// Determine VID/PID
int vid = pgm->usbvid ? pgm->usbvid : TEENSY_VID;
int pid = TEENSY_PID;
LNODEID usbpid = lfirst(pgm->usbpid);
if (usbpid != NULL)
{
pid = *(int*)(ldata(usbpid));
if (lnext(usbpid))
{
avrdude_message(MSG_INFO, "%s: WARNING: using PID 0x%04x, ignoring remaining PIDs in list\n",
progname, pid);
}
}
bool show_retry_message = true;
for (;;)
{
// Search for device
struct hid_device_info* devices = hid_enumerate(vid, pid);
struct hid_device_info* device = devices;
while (device)
{
if (device->vendor_id == vid && device->product_id == pid)
{
pdata->hid_handle = hid_open_path(device->path);
if (pdata->hid_handle == NULL)
{
avrdude_message(MSG_INFO, "%s: ERROR: Found HID device, but hid_open_path() failed.\n", progname);
}
else
{
pdata->hid_usage = device->usage;
break;
}
}
device = device->next;
}
hid_free_enumeration(devices);
if (pdata->hid_handle == NULL && pdata->wait_until_device_present)
{
if (show_retry_message)
{
avrdude_message(MSG_INFO, "%s: No device found, waiting for device...\n", progname);
avrdude_message(MSG_INFO, "%s: Press CTRL-C to terminate.\n", progname);
show_retry_message = false;
}
delay_ms(TEENSY_CONNECT_WAIT);
continue;
}
break;
}
if (!pdata->hid_handle)
{
avrdude_message(MSG_INFO, "%s: ERROR: Could not find device with Teensy bootloader (%04X:%04X)\n",
progname, vid, pid);
return -1;
}
return 0;
}
static void teensy_close(PROGRAMMER* pgm)
{
avrdude_message(MSG_DEBUG, "%s: teensy_close()\n", progname);
pdata_t* pdata = PDATA(pgm);
if (pdata->hid_handle != NULL)
{
hid_close(pdata->hid_handle);
pdata->hid_handle = NULL;
}
}
static int teensy_read_byte(PROGRAMMER* pgm, AVRPART* p, AVRMEM* mem,
unsigned long addr, unsigned char* value)
{
avrdude_message(MSG_DEBUG, "%s: teensy_read_byte(desc=%s, addr=0x%0X)\n",
progname, mem->desc, addr);
if (strcmp(mem->desc, "lfuse") == 0 ||
strcmp(mem->desc, "hfuse") == 0 ||
strcmp(mem->desc, "efuse") == 0 ||
strcmp(mem->desc, "lock") == 0)
{
*value = 0xFF;
return 0;
}
else
{
avrdude_message(MSG_INFO, "%s: Unsupported memory type: %s\n", progname, mem->desc);
return -1;
}
}
static int teensy_write_byte(PROGRAMMER* pgm, AVRPART* p, AVRMEM* mem,
unsigned long addr, unsigned char value)
{
avrdude_message(MSG_DEBUG, "%s: teensy_write_byte(desc=%s, addr=0x%0X)\n",
progname, mem->desc, addr);
return -1;
}
static int teensy_paged_load(PROGRAMMER* pgm, AVRPART* p, AVRMEM* mem,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
avrdude_message(MSG_DEBUG, "%s: teensy_paged_load(page_size=0x%X, addr=0x%X, n_bytes=0x%X)\n",
progname, page_size, addr, n_bytes);
return -1;
}
static int teensy_paged_write(PROGRAMMER* pgm, AVRPART* p, AVRMEM* mem,
unsigned int page_size,
unsigned int addr, unsigned int n_bytes)
{
avrdude_message(MSG_DEBUG, "%s: teensy_paged_write(page_size=0x%X, addr=0x%X, n_bytes=0x%X)\n",
progname, page_size, addr, n_bytes);
if (strcmp(mem->desc, "flash") == 0)
{
pdata_t* pdata = PDATA(pgm);
if (n_bytes > page_size)
{
avrdude_message(MSG_INFO, "%s: Buffer size (%u) exceeds page size (%u)\n", progname, n_bytes, page_size);
return -1;
}
if (addr + n_bytes > pdata->flash_size)
{
avrdude_message(MSG_INFO, "%s: Program size (%u) exceeds flash size (%u)\n", progname, addr + n_bytes, pdata->flash_size);
return -1;
}
if (pdata->erase_flash)
{
// Writing page 0 will automatically erase the flash.
// If mem does not contain a page at address 0, write a dummy page at address 0.
if (addr != 0)
{
int result = teensy_erase_flash(pdata);
if (result < 0)
{
return result;
}
}
pdata->erase_flash = false;
}
int result = teensy_write_page(pdata, addr, mem->buf + addr, n_bytes);
if (result < 0)
{
return result;
}
// Schedule a reboot.
pdata->reboot = true;
return result;
}
else
{
avrdude_message(MSG_INFO, "%s: Unsupported memory type: %s\n", progname, mem->desc);
return -1;
}
}
static int teensy_parseextparams(PROGRAMMER* pgm, LISTID xparams)
{
avrdude_message(MSG_DEBUG, "%s: teensy_parseextparams()\n", progname);
pdata_t* pdata = PDATA(pgm);
for (LNODEID node = lfirst(xparams); node != NULL; node = lnext(node))
{
const char* param = ldata(node);
if (strcmp(param, "wait") == 0)
{
pdata->wait_until_device_present = true;
}
else
{
avrdude_message(MSG_INFO, "%s: Invalid extended parameter '%s'\n", progname, param);
return -1;
}
}
return 0;
}
void teensy_initpgm(PROGRAMMER* pgm)
{
strcpy(pgm->type, "teensy");
pgm->setup = teensy_setup;
pgm->teardown = teensy_teardown;
pgm->initialize = teensy_initialize;
pgm->display = teensy_display;
pgm->powerup = teensy_powerup;
pgm->powerdown = teensy_powerdown;
pgm->enable = teensy_enable;
pgm->disable = teensy_disable;
pgm->program_enable = teensy_program_enable;
pgm->read_sig_bytes = teensy_read_sig_bytes;
pgm->chip_erase = teensy_chip_erase;
pgm->cmd = NULL;
pgm->open = teensy_open;
pgm->close = teensy_close;
pgm->read_byte = teensy_read_byte;
pgm->write_byte = teensy_write_byte;
pgm->paged_load = teensy_paged_load;
pgm->paged_write = teensy_paged_write;
pgm->parseextparams = teensy_parseextparams;
}
#else /* !HAVE_LIBHIDAPI */
// Give a proper error if we were not compiled with libhidapi
static int teensy_nousb_open(struct programmer_t* pgm, char* name)
{
avrdude_message(MSG_INFO, "%s: error: No HID support. Please compile again with libhidapi installed.\n", progname);
return -1;
}
void teensy_initpgm(PROGRAMMER* pgm)
{
strcpy(pgm->type, "teensy");
pgm->open = teensy_nousb_open;
}
#endif /* HAVE_LIBHIDAPI */
const char teensy_desc[] = "Teensy Bootloader";

35
teensy.h Normal file
View File

@@ -0,0 +1,35 @@
/*
* avrdude - A Downloader/Uploader for AVR device programmers
* Copyright (C) 2020 Marius Greuel
*
* 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 of the License, 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. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef teensy_h
#define teensy_h
#include "libavrdude.h"
#ifdef __cplusplus
extern "C" {
#endif
extern const char teensy_desc[];
void teensy_initpgm(PROGRAMMER* pgm);
#ifdef __cplusplus
}
#endif
#endif /* teensy_h */

View File

@@ -57,6 +57,9 @@
#define MICRONUCLEUS_VID 0x16D0
#define MICRONUCLEUS_PID 0x0753
#define TEENSY_VID 0x16C0
#define TEENSY_PID 0x0478
/* JTAGICEmkII, AVRISPmkII */
#define USBDEV_BULK_EP_WRITE_MKII 0x02
#define USBDEV_BULK_EP_READ_MKII 0x82