Merge pull request #49 from diamondman/feature/J2534_windows_driver
Feature/j2534 windows drivermaster
|
@ -0,0 +1,306 @@
|
|||
## Ignore Visual Studio temporary files, build results, and
|
||||
## files generated by popular Visual Studio add-ons.
|
||||
##
|
||||
## Get latest from https://github.com/github/gitignore/blob/master/VisualStudio.gitignore
|
||||
|
||||
# User-specific files
|
||||
*.suo
|
||||
*.user
|
||||
*.userosscache
|
||||
*.sln.docstates
|
||||
|
||||
# User-specific files (MonoDevelop/Xamarin Studio)
|
||||
*.userprefs
|
||||
|
||||
# Build results
|
||||
Debug_x86/
|
||||
Debug_x64/
|
||||
Release_x86/
|
||||
Release_x64/
|
||||
[Dd]ebug/
|
||||
[Dd]ebugPublic/
|
||||
[Rr]elease/
|
||||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
[Bb]uild[Ll]og.*
|
||||
|
||||
# NUNIT
|
||||
*.VisualState.xml
|
||||
TestResult.xml
|
||||
|
||||
# Build Results of an ATL Project
|
||||
[Dd]ebugPS/
|
||||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# Benchmark Results
|
||||
BenchmarkDotNet.Artifacts/
|
||||
|
||||
# .NET Core
|
||||
project.lock.json
|
||||
project.fragment.lock.json
|
||||
artifacts/
|
||||
**/Properties/launchSettings.json
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
*.ilk
|
||||
*.meta
|
||||
*.obj
|
||||
*.pch
|
||||
*.pdb
|
||||
*.pgc
|
||||
*.pgd
|
||||
*.rsp
|
||||
*.sbr
|
||||
*.tlb
|
||||
*.tli
|
||||
*.tlh
|
||||
*.tmp
|
||||
*.tmp_proj
|
||||
*.log
|
||||
*.vspscc
|
||||
*.vssscc
|
||||
.builds
|
||||
*.pidb
|
||||
*.svclog
|
||||
*.scc
|
||||
|
||||
# Chutzpah Test files
|
||||
_Chutzpah*
|
||||
|
||||
# Visual C++ cache files
|
||||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
||||
# Guidance Automation Toolkit
|
||||
*.gpState
|
||||
|
||||
# ReSharper is a .NET coding add-in
|
||||
_ReSharper*/
|
||||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
_TeamCity*
|
||||
|
||||
# DotCover is a Code Coverage Tool
|
||||
*.dotCover
|
||||
|
||||
# AxoCover is a Code Coverage Tool
|
||||
.axoCover/*
|
||||
!.axoCover/settings.json
|
||||
|
||||
# Visual Studio code coverage results
|
||||
*.coverage
|
||||
*.coveragexml
|
||||
|
||||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
AutoTest.Net/
|
||||
|
||||
# Web workbench (sass)
|
||||
.sass-cache/
|
||||
|
||||
# Installshield output folder
|
||||
[Ee]xpress/
|
||||
|
||||
# DocProject is a documentation generator add-in
|
||||
DocProject/buildhelp/
|
||||
DocProject/Help/*.HxT
|
||||
DocProject/Help/*.HxC
|
||||
DocProject/Help/*.hhc
|
||||
DocProject/Help/*.hhk
|
||||
DocProject/Help/*.hhp
|
||||
DocProject/Help/Html2
|
||||
DocProject/Help/html
|
||||
|
||||
# Click-Once directory
|
||||
publish/
|
||||
|
||||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# Note: Comment the next line if you want to checkin your web deploy settings,
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
**/packages/*
|
||||
# except build/, which is used as an MSBuild target.
|
||||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignorable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
*.appx
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
ClientBin/
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
*.dbproj.schemaview
|
||||
*.jfm
|
||||
*.pfx
|
||||
*.publishsettings
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
||||
# Backup & report files from converting an old project file
|
||||
# to a newer Visual Studio version. Backup files are not needed,
|
||||
# because we have git ;-)
|
||||
_UpgradeReport_Files/
|
||||
Backup*/
|
||||
UpgradeLog*.XML
|
||||
UpgradeLog*.htm
|
||||
|
||||
# SQL Server files
|
||||
*.mdf
|
||||
*.ldf
|
||||
*.ndf
|
||||
|
||||
# Business Intelligence projects
|
||||
*.rdl.data
|
||||
*.bim.layout
|
||||
*.bim_*.settings
|
||||
|
||||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
node_modules/
|
||||
|
||||
# Typescript v1 declaration files
|
||||
typings/
|
||||
|
||||
# Visual Studio 6 build log
|
||||
*.plg
|
||||
|
||||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
|
||||
*.vbw
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
||||
# CodeRush
|
||||
.cr/
|
||||
|
||||
# Python Tools for Visual Studio (PTVS)
|
||||
__pycache__/
|
||||
*.pyc
|
||||
|
||||
# Cake - Uncomment if you are using it
|
||||
# tools/**
|
||||
# !tools/packages.config
|
||||
|
||||
# Tabs Studio
|
||||
*.tss
|
||||
|
||||
# Telerik's JustMock configuration file
|
||||
*.jmconfig
|
||||
|
||||
# BizTalk build output
|
||||
*.btp.cs
|
||||
*.btm.cs
|
||||
*.odx.cs
|
||||
*.xsd.cs
|
||||
|
||||
# installer
|
||||
*.exe
|
|
@ -0,0 +1,38 @@
|
|||
// ECUsim CLI.cpp : Defines the entry point for the console application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "ECUsim DLL\ECUsim.h"
|
||||
|
||||
std::unique_ptr<ECUsim> sim;
|
||||
|
||||
BOOL CtrlHandler(DWORD fdwCtrlType)
|
||||
{
|
||||
if (fdwCtrlType != CTRL_C_EVENT) return FALSE;
|
||||
|
||||
sim->stop();
|
||||
sim->join();
|
||||
|
||||
return(TRUE);
|
||||
}
|
||||
|
||||
int main(int argc, // Number of strings in array argv
|
||||
char *argv[], // Array of command-line argument strings
|
||||
char *envp[]) // Array of environment variable strings
|
||||
{
|
||||
|
||||
int count;
|
||||
|
||||
// Display each command-line argument.
|
||||
std::cout << "\nCommand-line arguments:\n";
|
||||
for (count = 0; count < argc; count++)
|
||||
std::cout << " argv[" << count << "] " << argv[count] << "\n";
|
||||
|
||||
SetConsoleCtrlHandler((PHANDLER_ROUTINE)CtrlHandler, TRUE);
|
||||
|
||||
sim.reset(new ECUsim("", 500000));
|
||||
sim->join();
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{D99E2FCD-21A4-4065-949A-31E34E0E69D1}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ECUsimCLI</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>Application</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)ecusim.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)ecusim.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)ecusim.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Console</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)ecusim.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\ECUsim DLL\ECUsim.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ECUsim CLI.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ECUsim DLL\ECUsim DLL.vcxproj">
|
||||
<Project>{96e0e646-ee76-444d-9a77-a0cd7f781deb}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\ECUsim DLL\ECUsim.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ECUsim CLI.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ECUsim CLI.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,15 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <tchar.h>
|
||||
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
|
@ -0,0 +1,197 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{96E0E646-EE76-444D-9A77-A0CD7F781DEB}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>ECUsimDLL</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>ecusim</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<TargetName>ecusim</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>ecusim</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<TargetName>ecusim</TargetName>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;ECUSIMDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;ECUSIMDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;ECUSIMDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;ECUSIMDLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\panda\panda.h" />
|
||||
<ClInclude Include="ECUsim.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ECUsim.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\panda\panda.vcxproj">
|
||||
<Project>{5528aefb-638d-49af-b9d4-965154e7d531}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,42 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="ECUsim.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\panda\panda.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ECUsim.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,261 @@
|
|||
#include "stdafx.h"
|
||||
#include "ECUsim.h"
|
||||
|
||||
ECUsim::ECUsim(std::string sn, unsigned long can_baud, bool ext_addr) :
|
||||
doloop(TRUE), verbose(TRUE), can11b_enabled(TRUE), can29b_enabled(TRUE), ext_addr(ext_addr){
|
||||
this->panda = panda::Panda::openPanda(sn);
|
||||
this->panda->set_can_speed_cbps(panda::PANDA_CAN1, can_baud / 100); //Don't pass in baud where baud%100 != 0
|
||||
this->panda->set_safety_mode(panda::SAFETY_ALLOUTPUT);
|
||||
this->panda->set_can_loopback(FALSE);
|
||||
this->panda->can_clear(panda::PANDA_CAN_RX);
|
||||
|
||||
DWORD threadid;
|
||||
this->thread_can = CreateThread(NULL, 0, _canthreadBootstrap, (LPVOID)this, 0, &threadid);
|
||||
}
|
||||
|
||||
ECUsim::~ECUsim() {
|
||||
this->stop();
|
||||
this->join();
|
||||
}
|
||||
|
||||
void ECUsim::stop() {
|
||||
this->doloop = FALSE;
|
||||
}
|
||||
|
||||
void ECUsim::join() {
|
||||
WaitForSingleObject(this->thread_can, INFINITE);
|
||||
}
|
||||
|
||||
DWORD WINAPI ECUsim::_canthreadBootstrap(LPVOID This) {
|
||||
return ((ECUsim*)This)->can_recv_thread_function();
|
||||
}
|
||||
|
||||
DWORD ECUsim::can_recv_thread_function() {
|
||||
while (this->doloop) {
|
||||
auto msgs = this->panda->can_recv();
|
||||
for (auto& msg : msgs) {
|
||||
if (msg.is_receipt) continue;
|
||||
if (msg.bus == 0 && !msg.is_receipt /*&& msg.len == 8*/ && msg.dat[0] >= 2) {
|
||||
if (this->verbose) {
|
||||
printf("Processing message (bus: %d; addr: %X; 29b: %d):\n ", msg.bus, msg.addr, msg.addr_29b);
|
||||
for (int i = 0; i < msg.len; i++) printf("%02X ", msg.dat[i]);
|
||||
printf("\n");
|
||||
}
|
||||
this->_CAN_process_msg(msg);
|
||||
} else {
|
||||
if (this->verbose) {
|
||||
printf("Rejecting message (bus: %d; addr: %X; 29b: %d):\n ", msg.bus, msg.addr, msg.addr_29b);
|
||||
for (int i = 0; i < msg.len; i++) printf("%02X ", msg.dat[i]);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
BOOL ECUsim::_can_addr_matches(panda::PANDA_CAN_MSG& msg) {
|
||||
if (this->can11b_enabled && !msg.addr_29b && (msg.addr == 0x7DF || (msg.addr & 0x7F8) == 0x7E0)) {
|
||||
if (!this->ext_addr) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return msg.len >= 1 && msg.dat[0] == 0x13;//13 is an arbitrary address picked to test ext addresses
|
||||
}
|
||||
}
|
||||
if (this->can29b_enabled && msg.addr_29b && ((msg.addr & 0x1FFF00FF) == 0x18DB00F1 || (msg.addr & 0x1FFF00FF) == 0x18da00f1)) {
|
||||
if (!this->ext_addr) {
|
||||
return TRUE;
|
||||
} else {
|
||||
return msg.len >= 1 && msg.dat[0] == 0x13;//13 is an arbitrary address picked to test ext addresses
|
||||
}
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void ECUsim::_CAN_process_msg(panda::PANDA_CAN_MSG& msg) {
|
||||
std::string outmsg;
|
||||
uint32_t outaddr;
|
||||
uint8_t formatted_msg_buff[8];
|
||||
bool doreply = FALSE;
|
||||
|
||||
if (this->_can_addr_matches(msg)) {// && msg.len == 8) {
|
||||
uint8_t *dat = (this->ext_addr) ? &msg.dat[1] : &msg.dat[0];
|
||||
if ((dat[0] & 0xF0) == 0x10) {
|
||||
printf("Got a multiframe write request\n");
|
||||
outaddr = (msg.addr_29b) ? 0x18DAF1EF : 0x7E8;
|
||||
this->panda->can_send(outaddr, msg.addr_29b, (const uint8_t*)"\x30\x00\x00", 3, panda::PANDA_CAN1);
|
||||
return;
|
||||
}
|
||||
|
||||
/////////// Check if Flow Control Msg
|
||||
if ((dat[0] & 0xF0) == 0x30 && msg.len >= 3 && this->can_multipart_data.size() > 0) {
|
||||
if (this->verbose) printf("More data requested\n");
|
||||
uint8_t block_size = dat[1], sep_time_min = dat[2];
|
||||
outaddr = (msg.addr == 0x7DF || msg.addr == 0x7E0) ? 0x7E8 : 0x18DAF1EF; //ext addr 5th byte is just always 0x13 for simplicity
|
||||
|
||||
unsigned int msgnum = 1;
|
||||
while (this->can_multipart_data.size()) {
|
||||
unsigned int datalen = this->ext_addr ?
|
||||
min(6, this->can_multipart_data.size()): //EXT ADDR VALUE
|
||||
min(7, this->can_multipart_data.size()); //NORMAL ADDR VALUE
|
||||
|
||||
unsigned int idx = 0;
|
||||
if (this->ext_addr)
|
||||
formatted_msg_buff[idx++] = 0x13; //EXT ADDR
|
||||
formatted_msg_buff[idx++] = 0x20 | msgnum;
|
||||
for (int i = 0; i < datalen; i++) {
|
||||
formatted_msg_buff[i + idx] = this->can_multipart_data.front();
|
||||
this->can_multipart_data.pop();
|
||||
}
|
||||
for (int i = datalen + idx; i < sizeof(formatted_msg_buff); i++)
|
||||
formatted_msg_buff[i] = 0;
|
||||
|
||||
if (this->verbose) {
|
||||
printf("Multipart reply to %X.\n ", outaddr);
|
||||
for (int i = 0; i < datalen + idx; i++) printf("%02X ", formatted_msg_buff[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
this->panda->can_send(outaddr, msg.addr_29b, formatted_msg_buff, datalen + idx, panda::PANDA_CAN1);
|
||||
msgnum = (msgnum + 1) % 0x10;
|
||||
Sleep(10);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/////////// Normal message in
|
||||
outmsg = this->process_obd_msg(dat[1], dat[2], doreply);
|
||||
if (doreply) {
|
||||
outaddr = (msg.addr_29b) ? 0x18DAF1EF : 0x7E8;
|
||||
|
||||
if (outmsg.size() <= (this->ext_addr ? 4 : 5)) {
|
||||
unsigned int idx = 0;
|
||||
if(this->ext_addr)
|
||||
formatted_msg_buff[idx++] = 0x13; //EXT ADDR
|
||||
formatted_msg_buff[idx++] = outmsg.size() + 2;
|
||||
formatted_msg_buff[idx++] = 0x40 | dat[1];
|
||||
formatted_msg_buff[idx++] = dat[2]; //PID
|
||||
memcpy_s(&formatted_msg_buff[idx], sizeof(formatted_msg_buff) - idx, outmsg.c_str(), outmsg.size());
|
||||
for (int i = idx + outmsg.size(); i < 8; i++)
|
||||
formatted_msg_buff[i] = 0;
|
||||
|
||||
if (this->verbose) {
|
||||
printf("Replying to %X.\n ", outaddr);
|
||||
for (int i = 0; i < 8; i++) printf("%02X ", formatted_msg_buff[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
this->panda->can_send(outaddr, msg.addr_29b, formatted_msg_buff, 8, panda::PANDA_CAN1); //outmsg.size() + 3
|
||||
} else {
|
||||
uint8_t first_msg_len = this->ext_addr ?
|
||||
min(2, outmsg.size() % 7) : //EXT ADDR VALUES
|
||||
min(3, outmsg.size() % 7); //NORMAL ADDR VALUES
|
||||
uint8_t payload_len = outmsg.size() + 3;
|
||||
|
||||
unsigned int idx = 0;
|
||||
if (this->ext_addr)
|
||||
formatted_msg_buff[idx++] = 0x13; //EXT ADDR
|
||||
formatted_msg_buff[idx++] = 0x10 | ((payload_len >> 8) & 0xF);
|
||||
formatted_msg_buff[idx++] = payload_len & 0xFF;
|
||||
formatted_msg_buff[idx++] = 0x40 | dat[1];
|
||||
formatted_msg_buff[idx++] = dat[2]; //PID
|
||||
formatted_msg_buff[idx++] = 1;
|
||||
memcpy_s(&formatted_msg_buff[idx], sizeof(formatted_msg_buff) - idx, outmsg.c_str(), first_msg_len);
|
||||
|
||||
if (this->verbose) {
|
||||
printf("Replying FIRST FRAME to %X.\n ", outaddr);
|
||||
for (int i = 0; i < 8; i++) printf("%02X ", formatted_msg_buff[i]);
|
||||
printf("\n");
|
||||
}
|
||||
|
||||
this->panda->can_send(outaddr, msg.addr_29b, formatted_msg_buff, 8, panda::PANDA_CAN1);
|
||||
for (int i = first_msg_len; i < outmsg.size(); i++)
|
||||
this->can_multipart_data.push(outmsg[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::string ECUsim::process_obd_msg(UCHAR mode, UCHAR pid, bool& return_data) {
|
||||
std::string tmp;
|
||||
return_data = TRUE;
|
||||
|
||||
switch (mode) {
|
||||
case 0x01: // Mode : Show current data
|
||||
switch (pid) {
|
||||
case 0x00: //List supported things
|
||||
return "\xff\xff\xff\xfe"; //b"\xBE\x1F\xB8\x10" #Bitfield, random features
|
||||
case 0x01: // Monitor Status since DTC cleared
|
||||
return std::string("\x00\x00\x00\x00", 4); //Bitfield, random features
|
||||
case 0x04: // Calculated engine load
|
||||
return "\x2f";
|
||||
case 0x05: // Engine coolant temperature
|
||||
return "\x3c";
|
||||
case 0x0B: // Intake manifold absolute pressure
|
||||
return "\x90";
|
||||
case 0x0C: // Engine RPM
|
||||
return "\x1A\xF8";
|
||||
case 0x0D: // Vehicle Speed
|
||||
return "\x53";
|
||||
case 0x10: // MAF air flow rate
|
||||
return "\x01\xA0";
|
||||
case 0x11: // Throttle Position
|
||||
return "\x90";
|
||||
case 0x33: // Absolute Barometric Pressure
|
||||
return "\x90";
|
||||
default:
|
||||
return_data = FALSE;
|
||||
return "";
|
||||
}
|
||||
case 0x09: // Mode : Request vehicle information
|
||||
switch (pid) {
|
||||
case 0x02: // Show VIN
|
||||
return "1D4GP00R55B123456";
|
||||
case 0xFC: // test long multi message.Ligned up for LIN responses
|
||||
for (int i = 0; i < 80; i++) {
|
||||
tmp += "\xAA\xAA";
|
||||
}
|
||||
return tmp;//">BBH", 0xAA, 0xAA, num + 1)
|
||||
case 0xFD: // test long multi message
|
||||
for (int i = 0; i < 80; i++) {
|
||||
tmp += "\xAA\xAA\xAA";
|
||||
tmp.push_back(i >> 24);
|
||||
tmp.push_back((i >> 16) & 0xFF);
|
||||
tmp.push_back((i >> 8) & 0xFF);
|
||||
tmp.push_back(i & 0xFF);
|
||||
}
|
||||
return "\xAA\xAA\xAA" + tmp;
|
||||
case 0xFE: // test very long multi message
|
||||
tmp = "\xAA\xAA\xAA";
|
||||
for (int i = 0; i < 584; i++) {
|
||||
tmp += "\xAA\xAA\xAA";
|
||||
tmp.push_back(i >> 24);
|
||||
tmp.push_back((i >> 16) & 0xFF);
|
||||
tmp.push_back((i >> 8) & 0xFF);
|
||||
tmp.push_back(i & 0xFF);
|
||||
}
|
||||
return tmp + "\xAA";
|
||||
case 0xFF:
|
||||
for (int i = 0; i < 584; i++) {
|
||||
tmp += "\xAA\xAA\xAA\xAA\xAA";
|
||||
tmp.push_back(((i + 1) >> 8) & 0xFF);
|
||||
tmp.push_back((i + 1) & 0xFF);
|
||||
}
|
||||
return std::string("\xAA\x00\x00", 3) + tmp;
|
||||
default:
|
||||
return_data = FALSE;
|
||||
return "";
|
||||
}
|
||||
case 0x3E:
|
||||
if (pid == 0) {
|
||||
return_data = TRUE;
|
||||
return "";
|
||||
}
|
||||
return_data = FALSE;
|
||||
return "";
|
||||
default:
|
||||
return_data = FALSE;
|
||||
return "";
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "panda\panda.h"
|
||||
#include <queue>
|
||||
|
||||
// The following ifdef block is the standard way of creating macros which make exporting
|
||||
// from a DLL simpler. All files within this DLL are compiled with the ECUSIMDLL_EXPORTS
|
||||
// symbol defined on the command line. This symbol should not be defined on any project
|
||||
// that uses this DLL. This way any other project whose source files include this file see
|
||||
// ECUSIMDLL_API functions as being imported from a DLL, whereas this DLL sees symbols
|
||||
// defined with this macro as being exported.
|
||||
#ifdef ECUSIMDLL_EXPORTS
|
||||
#define ECUSIMDLL_API __declspec(dllexport)
|
||||
#else
|
||||
#define ECUSIMDLL_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
// This class is exported from the ECUsim DLL.dll
|
||||
class ECUSIMDLL_API ECUsim {
|
||||
public:
|
||||
ECUsim(std::string sn, unsigned long can_baud, bool ext_addr = FALSE);
|
||||
ECUsim(panda::Panda && p, unsigned long can_baud, bool ext_addr = FALSE);
|
||||
~ECUsim();
|
||||
|
||||
void stop();
|
||||
void join();
|
||||
|
||||
// Flag determines if verbose output is enabled
|
||||
volatile bool verbose;
|
||||
BOOL ext_addr;
|
||||
private:
|
||||
std::unique_ptr<panda::Panda> panda;
|
||||
|
||||
static DWORD WINAPI _canthreadBootstrap(LPVOID This);
|
||||
DWORD can_recv_thread_function();
|
||||
|
||||
BOOL _can_addr_matches(panda::PANDA_CAN_MSG & msg);
|
||||
|
||||
void _CAN_process_msg(panda::PANDA_CAN_MSG & msg);
|
||||
|
||||
std::string process_obd_msg(UCHAR mode, UCHAR pid, bool& return_data);
|
||||
|
||||
HANDLE thread_can;
|
||||
volatile bool doloop;
|
||||
std::queue<uint8_t> can_multipart_data;
|
||||
|
||||
BOOL can11b_enabled;
|
||||
BOOL can29b_enabled;
|
||||
};
|
|
@ -0,0 +1,19 @@
|
|||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "stdafx.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// ECUsim DLL.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,16 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
|
||||
|
||||
|
||||
// TODO: reference additional headers your program requires here
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
|
@ -0,0 +1,177 @@
|
|||
```
|
||||
;" ^; ;' ",
|
||||
______/\\\\\\\\\\\____/\\\\\\\\\_______/\\\\\\\\\\\\\\\______/\\\\\\\\\\_____________/\\\____ ; s$$$$$$$s ;
|
||||
_____\/////\\\///___/\\\///////\\\____\/\\\///////////_____/\\\///////\\\__________/\\\\\____ , ss$$$$$$$$$$s ,'
|
||||
_________\/\\\_____\///______\//\\\___\/\\\_______________\///______/\\\_________/\\\/\\\____ ;s$$$$$$$$$$$$$$$
|
||||
_________\/\\\_______________/\\\/____\/\\\\\\\\\\\\_____________/\\\//________/\\\/\/\\\____ $$$$$$$$$$$$$$$$$$
|
||||
_________\/\\\____________/\\\//______\////////////\\\__________\////\\\_____/\\\/__\/\\\____ $$$$P""Y$$$Y""W$$$$$
|
||||
_________\/\\\_________/\\\//____________________\//\\\____________\//\\\__/\\\\\\\\\\\\\\\\_ $$$$ p"$$$"q $$$$$
|
||||
__/\\\___\/\\\_______/\\\/____________/\\\________\/\\\___/\\\______/\\\__\///////////\\\//__ $$$$ .$$$$$. $$$$
|
||||
_\//\\\\\\\\\_______/\\\\\\\\\\\\\\\_\//\\\\\\\\\\\\\/___\///\\\\\\\\\/_____________\/\\\____ _ $$$$$$$$$$$$$$$$
|
||||
__\/////////_______\///////////////___\/////////////_______\/////////_______________\///_____| | "Y$$$"*"$$$Y"
|
||||
_ __ __ _ _ __ __| | __ _"$b.$$"
|
||||
| '_ \ / _` | '_ \ / _` |/ _` |
|
||||
| |_) | (_| | | | | (_| | (_| |
|
||||
| .__/ \__,_|_| |_|\__,_|\__,_|
|
||||
| | A comma.ai product.
|
||||
|_| (Code by Jessy Diamond Exum)
|
||||
```
|
||||
|
||||
|
||||
# What is J2534?
|
||||
|
||||
J2534 is an API that tries to provide a consistent way to send/receive
|
||||
messages over the many different protocols supported by the OBD II
|
||||
port. The place this is perhaps most obvious, is sending data over
|
||||
different protocols (each using unique packetizing methods) using the
|
||||
same data format.
|
||||
|
||||
For each PassThru Device that should be used with J2534 (in this case,
|
||||
the panda), a 'driver' has to be written that can be loaded by a
|
||||
client application wanting to send/receive data.
|
||||
|
||||
A lot of J2534 has good ideas behind it, but the standard has some odd choices:
|
||||
|
||||
* Platform Locked: Requires using the Windows Registry to find installed J2534 libraries/drivers. Drivers have to be DLLs.
|
||||
* Architecture Locked: So far there is only support for x86.
|
||||
* No device autodetect, and poor support for selecting from multiple devices.
|
||||
* Constant vague language about important behavior (small differences between vendors).
|
||||
* Most common differences become standard in later revisions.
|
||||
|
||||
# Why use J2534 with the panda?
|
||||
|
||||
J2534 is the only interface supported by most professional grade
|
||||
vehicle diagnostics systems (such as HDS). These tools are useful for
|
||||
diagnosing vehicles, as well as reverse engineering some lesser known
|
||||
features.
|
||||
|
||||
# What parts are supported with panda?
|
||||
|
||||
- [ ] **J1850VPW** *(Outdated, and not physically supported by the panda)*
|
||||
- [ ] **J1850PWM** *(Outdated, and not physically supported by the panda)*
|
||||
- [X] **CAN**
|
||||
- [X] **ISO15765**
|
||||
- [ ] **ISO9141** *(This protocol could be implemented if 5 BAUD init support is added to the panda.)*
|
||||
- [ ] **ISO14230/KWP2000** *(Could be supported with FAST init, 5baud init if panda adds support for 5bps serial)*
|
||||
|
||||
# Building the Project:
|
||||
|
||||
This project was developed with Visual Studio 2015, the Windows SDK,
|
||||
and the Windows Driver Kit (WDK). At the time of writing, there is not
|
||||
a stable WDK for Visual Studio 2017, but this project should build
|
||||
with the new WDK and Visual Studio when it is available.
|
||||
|
||||
The WDK is only required for creating the signed WinUSB inf file. The
|
||||
WDK may also provide the headers for WinUSB.
|
||||
|
||||
To build all the projects required for the installer, in Visual
|
||||
Studio, select **Build->Batch Build.** In the project list select:
|
||||
|
||||
- **"panda"** *Release|x86*
|
||||
- **"panda"** *Release|x64*
|
||||
- **"panda Driver Package"** Debug|x86 (Note this inf file works with x86/amd64).
|
||||
- **"pandaJ2534DLL"** *Release|x86*
|
||||
|
||||
The installer is generated with [NullSoft NSIS](http://nsis.sourceforge.net/Main_Page).
|
||||
Use NSIS to run panda_install.nsi after building all the required projects.
|
||||
|
||||
Before generating the installer, you must go to copy vscruntimeinfo.nsh.sample to
|
||||
vscruntimeinfo.nsh and follow the instructions to bundle in the Visual Studio C
|
||||
Runtime required by your version of Visual Studio. Without this runtime, the panda
|
||||
code will not work, so without this file, the installer will refuse to build.
|
||||
|
||||
# Installing:
|
||||
|
||||
Either build the software yourself by following the steps in the
|
||||
'Developing' section, or get the panda_installer.exe file and run
|
||||
it. The wizard should correctly set up the drivers.
|
||||
|
||||
Since this driver is still in development, there are some issues
|
||||
that may occur. If after you install the driver and then plug in your
|
||||
panda (unplug it first if it was already plugged in), Windows says
|
||||
the driver is missing, refer to the section below 'Dealing with self
|
||||
signed drivers.'
|
||||
|
||||
# Using J2534:
|
||||
|
||||
After installing the J2534 drivers for the panda, you can do... nothing.
|
||||
You first need to get a J2534 client that can load the drivers and talk to
|
||||
the panda for you.
|
||||
|
||||
A simple tool for testing J2534 drivers is DrewTech's 'J2534-1 Bus Analysis
|
||||
Tool' available in the 'Other Support Applications' section of their
|
||||
[Download Page](http://www.drewtech.com/downloads/).
|
||||
|
||||
# Dealing with self signed drivers:
|
||||
|
||||
Installation would be straightforward were it not for the USB Driver
|
||||
that needs to be setup. The driver itself is only a WinUSB inf file
|
||||
(no actual driver), but it still needs to be signed.
|
||||
|
||||
Driver signing is a requirement of Windows starting in 8 (64 bit
|
||||
versions only for some reason). If your Windows refuses to install
|
||||
the driver, there are three choices:
|
||||
|
||||
- Self Sign the Driver.
|
||||
- Disable Driver Signature Verification
|
||||
- Purchase a certificate signed by a trusted authority.
|
||||
|
||||
Since self signed certificates have no chain of trust to a known
|
||||
certificate authority, if you self sign, you will have to add your
|
||||
cert to the root certificate store of your Windows' installation. This
|
||||
is dangerous because it means anything signed with your cert will be
|
||||
trusted. If you make your own cert, add a password so someone can't
|
||||
copy it and screw with your computer's trust.
|
||||
|
||||
Disabling Signature Verification allows you to temporarily install
|
||||
drivers without a trusted signature. Once you reboot, new drivers will
|
||||
need to be verified again, but any installed drivers will stay where
|
||||
they are. This option is irritating if you are installing and
|
||||
uninstalling the inf driver multiple times, but overall, is safer than
|
||||
the custom root certificate described above.
|
||||
|
||||
Purchasing a signed certificate is the best long term option, but it
|
||||
is not useful for open source contributors, since the certificate will
|
||||
be kept safe by the comma.ai team. Developers should use one of the
|
||||
other two options.
|
||||
|
||||
**Note that certificate issues apply no matter if you are building
|
||||
from source or running an insaller .exe file.**
|
||||
|
||||
Some people have reported that the driver installs without needing to
|
||||
disable driver signing, or that visual studio correctly sets up a
|
||||
temporary signing key for them. I call witchcraft because I have not
|
||||
had that happen to me. The signed certificate is still the correct
|
||||
thing to do in the end.
|
||||
|
||||
Windows 7 will not force driver signing. This software is not tested
|
||||
on anything before 7.
|
||||
|
||||
# Developing:
|
||||
|
||||
- Edit and merge pandaJ2534DLL\J2534register_x64.reg to register your development J2534 DLL.
|
||||
- Add your output directory (panda\drivers\windows\Debug_x86) to your system PATH to avoid insanity.
|
||||
|
||||
# ToDo Items:
|
||||
|
||||
- Get official signing key for WinUSB driver inf file.
|
||||
- Implement TxClear and RxClear. (Requires reading vague specifications).
|
||||
- Apply a style-guide and consistent naming convention for Classes/Functions/Variables.
|
||||
- Send multiple messages (each with a different address) from a given connection at the same time.
|
||||
- Implement ISO14230/KWP2000 FAST (LIN communication is already supported with the raw panda USB driver).
|
||||
- Find more documentation about SW_CAN_PS (Single Wire CAN, aka GMLAN).
|
||||
- Find example of client using a _PS version of a protocol (PS is pin select, and may support using different CAN buses).
|
||||
|
||||
|
||||
# Known Issues:
|
||||
|
||||
- ISO15765 Multi-frame TX: Hardware delays make transmission overshoot
|
||||
STMIN by several milliseconds. This does not violate the requirements
|
||||
of STMIN, it just means it is a little slower than it could be.
|
||||
|
||||
- All Tx messages from a single Connection are serialized. This can be
|
||||
relaxed to allow serialization of messages based on their address
|
||||
(making multiple queues, effectively one queue per address).
|
||||
|
||||
# Other:
|
||||
Panda head ASCII art by dcau
|
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 348 KiB |
After Width: | Height: | Size: 112 KiB |
After Width: | Height: | Size: 107 KiB |
After Width: | Height: | Size: 56 KiB |
After Width: | Height: | Size: 44 KiB |
After Width: | Height: | Size: 93 KiB |
After Width: | Height: | Size: 109 KiB |
|
@ -0,0 +1,347 @@
|
|||
When using the ISO 15765-4 protocol, only SingleFrame messages can be transmitted without a matching
|
||||
flow control filter. Also, PCI bytes are transparently added by the API. See PassThruStartMsgFilter
|
||||
and Appendix A for a discussion of flow control filters.
|
||||
|
||||
|
||||
|
||||
PassThruReadMsgs
|
||||
This function reads messages and indications from the receive buffer. All messages and indications shall
|
||||
be read in the order that they occurred on the bus. If a transmit message generated a loopback message
|
||||
and TxDone indication, the TxDone indication shall always be queued first. Except for loopback messages
|
||||
and indications, no messages shall be queued for reception without matching a PASS_FILTER
|
||||
(for non-ISO 15765) or FLOW_CONTROL filter (for ISO 15765). On ISO 15765, PCI bytes are transparently
|
||||
removed by the API. If the function is successful, a value of STATUS_NOERROR is returned.
|
||||
|
||||
|
||||
PassThruWriteMsgs
|
||||
Write timeout (in milliseconds). When a value of 0 is specified, the function queues as
|
||||
many of the specified messages as possible and returns immediately. When a value
|
||||
greater than 0 is specified, the function will block until the Timeout has expired, an error
|
||||
has occurred, or the desired number of messages have been transmitted on the vehicle
|
||||
network. Even if the device can buffer only one packet at a time, this function shall be
|
||||
able to send an arbitrary number of packets if a Timeout value is supplied. Since the
|
||||
function returns early if all the messages have been sent, there is normally no penalty for
|
||||
having a large timeout (several seconds). If the number of messages requested have
|
||||
been written, the function shall not return ERR_TIMEOUT, even if the timeout value is
|
||||
zero.
|
||||
|
||||
When an ERR_TIMEOUT is returned, only the number of messages that were sent on
|
||||
the vehicle network is known. The number of messages queued is unknown. Application
|
||||
writers should avoid this ambiguity by using a Timeout value large enough to work on
|
||||
slow devices and networks with arbitration delays.
|
||||
|
||||
|
||||
|
||||
PassThruStartPeriodicMsg
|
||||
This function will immediately queue the specified message for transmission, and repeat at the specified
|
||||
interval. Periodic messages are limited in length to a single frame message of 12 bytes or less, including
|
||||
header or CAN ID. Periodic messages shall have priority over messages queued with
|
||||
PassThruWriteMsgs, but periodic messages must not violate bus idle timing parameters (e.g. P3_MIN).
|
||||
Periodic messages shall generate TxDone indications (ISO 15765) and loopback messages (on any
|
||||
protocol, if enabled). On ISO 15765, periodic messages can be sent during a multi-frame transmission or
|
||||
reception. If the function is successful, a value of STATUS_NOERROR is returned. The Pass-Thru
|
||||
device must support a minimum of ten periodic messages.
|
||||
|
||||
PassThruDisconnect shall delete all periodic messages on that channel. PassThruClose shall delete all
|
||||
periodic messages on all channels for the device. All periodic messages will be stopped on a
|
||||
PassThruDisconnect for the associated protocol or a PassThruClose for the device.
|
||||
|
||||
|
||||
|
||||
PASSTHRUSTARTMSGFILTER
|
||||
This function starts filtering of incoming messages. If the function is successful, a value of
|
||||
STATUS_NOERROR is returned. A minimum of ten message filters shall be supported by the interface
|
||||
for each supported protocol. PassThruDisconnect shall delete all message filters on that channel.
|
||||
|
||||
PassThruClose shall delete all filters on all channels for the device. Pattern and Mask messages shall
|
||||
follow the protocol formats specified in Section 8. However, only the first twelve (12) bytes, including
|
||||
header or CAN ID, are used by the filter. ERR_INVALID_MSG shall be returned if the filter length
|
||||
exceeds 12. Note that this function does not clear any messages that may have been received and
|
||||
queued before the filter was set. Users are cautioned to consider performing a CLEAR_RX_BUFFER
|
||||
after starting a message filter to be sure that unwanted frames are purged from any receive buffers.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
FILTER RELATED STUFF
|
||||
For all protocols except ISO 15765:
|
||||
• PASS_FILTERs and BLOCK_FILTERs will be applied to all received messages. They shall not be
|
||||
applied to indications or loopback messages
|
||||
|
||||
• FLOW_CONTROL_FILTERs must not be used and shall cause the interface to return
|
||||
ERR_INVALID_FILTER_ID
|
||||
|
||||
• Both pMaskMsg and pPatternMsg must have the same DataSize and TxFlags. Otherwise, the
|
||||
interface shall return ERR_INVALID_MSG
|
||||
|
||||
• The default filter behavior after PassThruConnect is to block all messages, which means no messages
|
||||
will be placed in the receive queue until a PASS_FILTER has been set. Messages that match a
|
||||
PASS_FILTER can still be blocked by a BLOCK_FILTER
|
||||
|
||||
• Figure 16 and Figure 17 show how the message filtering mechanism operates
|
||||
|
||||
For ISO 15765:
|
||||
• PASS_FILTERs and BLOCK_FILTERs must not be used and shall cause the interface to return
|
||||
ERR_INVALID_FILTER_ID
|
||||
|
||||
• Filters shall not be applied to indications or loopback messages. When loopback is on, the original
|
||||
message shall be copied to the receive queue upon the last segment being transmitted on the bus.
|
||||
|
||||
• Non-segmented messages do not need to match a FLOW_CONTROL_FILTER.
|
||||
|
||||
• No segmented messages can be transmitted without matching an appropriate FLOW_CONTROL_FILTER.
|
||||
An appropriate filter is one in which the pFlowControlMsg CAN ID matches the messages to be
|
||||
transmitted. Also, the ISO 15765_ADDR_TYPE (reference TxFlags in Section 8.7.3) bits must match.
|
||||
If that bit is set, the first byte after the CAN IDs (the extended address)
|
||||
must match too.
|
||||
|
||||
• No message (segmented or unsegmented) shall be received without matching an appropriate
|
||||
FLOW_CONTROL_FILTER. An appropriate filter is one in which the pPatternMsg CAN ID matches
|
||||
the incoming message ID. If the ISO 15765_ADDR_TYPE (reference TxFlags in Section 8.7.3) bit is
|
||||
set in the filter, the first byte after the CAN IDs (the extended address) must match too.
|
||||
|
||||
• All 3 message pointers must have the same DataSize and TxFlags. Otherwise, the interface shall
|
||||
return ERR_INVALID_MSG.
|
||||
|
||||
• Both the pFlowControlMsg ID and the pPatternMsg ID must be unique (not match any IDs in any other
|
||||
filters). The only exception is that pPatternMsg can equal pFlowControlMsg to allow for receiving
|
||||
functionally addressed messages. In this case, only non-segmented messages can be received.
|
||||
|
||||
• See Appendix A for a detailed description of flow control filter usage.
|
||||
|
||||
|
||||
|
||||
|
||||
8.4 Format Checks for Messages Passed to the API
|
||||
The vendor DLL shall validate all PASSTHRU_MSG structures, and return an ERR_INVALID_MSG in the following cases:
|
||||
• DataSize violates Min Tx or Max Tx columns in Figure 42
|
||||
|
||||
• Source address (Data[3]) is different from the Node ID (Ioctl SET_CONFIG, Parameter NODE_ADDRESS) on J1850PWM
|
||||
|
||||
• The header length field is incorrect for the number of bytes in the message on ISO14230
|
||||
|
||||
• The CAN_29_BIT flag of the message does not match the CAN_29_BIT flag passed to
|
||||
PassThruConnect, unless the CAN_ID_BOTH bit was set on connect
|
||||
|
||||
The vendor DLL shall return ERR_MSG_PROTOCOL_ID when the ProtocolID field in the message does
|
||||
not match the Protocol ID specified when opening the channel.
|
||||
|
||||
|
||||
|
||||
8.5 Conventions for Returning Messages from the API
|
||||
When returning a message in PassThruReadMsg:
|
||||
– DataSize shall tell the application how many bytes in the Data array are valid. ExtraDataIndex will be
|
||||
the (non-zero) index of the last byte of the message. If ExtraDataIndex is not equal to DataSize there
|
||||
are extra data bytes after the message. If loopback is on, RxStatus must be consulted to tell if the
|
||||
message came via loopback.
|
||||
|
||||
– DataSize will be in the range shown in the Min Rx and Max Rx columns of Figure 42. If the device
|
||||
receives a message from the vehicle bus that is too long or too short, the message shall be discarded
|
||||
with no error.
|
||||
|
||||
– For received messages, ExtraDataIndex shall be equal to DataSize, except when the interface is
|
||||
returning SAE J1850 PWM IFR bytes. In no case shall ExtraDataIndex be larger than DataSize.
|
||||
|
||||
– When receiving a message on an SAE J1850 PWM channel, the message shall have any IFR bytes
|
||||
appended. In this case, ExtraDataIndex shall be the index of the first IFR byte, and DataSize shall be
|
||||
the total length of the original message plus all IFR bytes. For example, if there are two IFR bytes,
|
||||
DataSize will be incremented by two, and ExtraDataIndex will be DataSize - 2. When loopback is on,
|
||||
the loopback message shall contain any IFR bytes.
|
||||
|
||||
|
||||
|
||||
8.6 Conventions for Retuning Indications from the API
|
||||
When returning an indication in PassThruReadMsg:
|
||||
– ExtraDataIndex must be zero
|
||||
|
||||
– DataSize shall tell the application how many bytes in the Data array are valid
|
||||
|
||||
– RxStatus must be consulted to determine the indication type (See Section 8.4).
|
||||
|
||||
– A TxDone indication (ISO 15765 only) is generated by the DLL after a SingleFrame message is sent,
|
||||
or the last frame of a multi-segment transmission is sent. DataSize shall be 4 (or 5 when the message
|
||||
was using Extended Addressing). Data shall contain the CAN ID (and possible Extended Address) of
|
||||
the message just sent. If loopback is on, the TxDone indication shall precede the loopback message in
|
||||
the receive queue.
|
||||
|
||||
– An RxBreak indication (SAE J2610/SCI and SAE J1850VPW only) is generated by the DLL if a break
|
||||
is received.
|
||||
|
||||
– An RxStart indication is generated by the DLL when starting to receive a message on ISO9141 or
|
||||
ISO14230, or when receiving the FirstFrame signal of a multi-segment ISO 15765 message.
|
||||
|
||||
|
||||
|
||||
9.1 Naming of Files
|
||||
Each vendor will provide a different name implementation of the API DLL and a number of these
|
||||
implementations could simultaneously reside on the same PC. No vendor shall name its implementation
|
||||
“J2534.DLL”. All implementations shall have the string “32” suffixed to end of the name of the API DLL to
|
||||
indicate 32-bit. For example, if the company name is “Vendor X” the name could be VENDRX32.DLL.
|
||||
|
||||
For simplicity, an API DLL shall be named in accordance with the file allocation table (FAT) file system
|
||||
naming convention (which allows up to eight characters for the file name and three characters for the
|
||||
extension with no spaces anywhere). Note that, given this criteria, the major name of an API DLL can be
|
||||
no greater than six characters. The OEM application can determine the name of the appropriate vendor’s
|
||||
DLL using the Win32 Registry mechanism described in this section.
|
||||
|
||||
|
||||
|
||||
|
||||
A.1 Flow Control Overview
|
||||
ISO 15765-2 was designed to send blocks of up to 4095 bytes on top of the limited 8-byte payload of raw
|
||||
CAN frames. If the data is small enough, it can fit in a single frame and be transmitted like a raw CAN
|
||||
message with additional headers. Otherwise, the block is broken up into segments and becomes a
|
||||
segmented transmission, generating CAN frames in both directions. For flexibility, the receiver of the
|
||||
segments can control the rate at which the segments are sent.
|
||||
|
||||
Each transmission is actually part of a conversation between two nodes. There is no discovery
|
||||
mechanism for conversation partners. Therefore, each desired conversation must be pre-defined on each
|
||||
side before the conversation can start. Conversations are symmetric, meaning that either side can send a
|
||||
block of data to the other. A conversation can only have one transfer (in one direction) in progress at a
|
||||
time. One transfer must complete before the next transfer (in the same or in a different direction) can
|
||||
start. The device must support multiple transfers at once, as long as each one is part of a different
|
||||
conversation. Raw CAN frames are not allowed when using ISO15765-2.
|
||||
|
||||
A key feature of a conversation is that each side has a unique CAN ID, and each side uses their unique
|
||||
CAN ID for all transmissions during the conversation. No other CAN IDs are part of the conversation.
|
||||
Even though the useful data is only flowing in one direction, both sides are transmitting. One side is
|
||||
sending the flow control message to pace the segments of data coming from the other side.
|
||||
|
||||
For example, during OBD communication, a pass-thru device and an ECU might have a conversation.
|
||||
The pass-thru device will use the "Tester1" physical CAN ID ($241), and the first ECU will use the
|
||||
"ECU1" physical CAN ID ($641). During a multi-segment transfer, both sides will be transmitting using
|
||||
only their respective IDs. It does not matter if the data is being sent by the ECU or by the Tester, the IDs
|
||||
remain the same.
|
||||
|
||||
It is important to understand the difference between OBD Requests/Responses and ISO 15765-2
|
||||
transfers. The OBD Request is transmitted from the Tester to the ECU using functional addressing.
|
||||
Because segmented transfer is not possible on functional addresses, the message must fit in a single
|
||||
frame. The OBD Response is a message from the ECU to the Tester using physical addressing. Unlike
|
||||
other protocols, the responses are not sequential. In fact, the responses can overlap, as if each ECU
|
||||
were having a private conversation with the Tester. Some of the responses may fit in a single frame,
|
||||
while others will require a segmented transfer from the ECU to the tester.
|
||||
|
||||
|
||||
A.2 Transmitting a Segmented Message
|
||||
When PassThruWrite is called, the API will search the list of flow control filters, looking for a
|
||||
pFlowControlMsg that matches the CAN ID (and possible extended address) of the message being sent.
|
||||
Upon matching a filter, the pass-thru device will:
|
||||
|
||||
• Start the ISO 15765 transfer by sending a FirstFrame on the bus. The CAN ID of this segment was
|
||||
specified in both the message and the matching pFlowControlMsg. In our example, this is $241.
|
||||
|
||||
• Wait for a FlowControl frame from the conversation partner. The CAN ID to look for is specified in the
|
||||
corresponding pPatternMsg. In our example, this is $641.
|
||||
|
||||
• Transmit the message data in ConsecutiveFrames according to the FlowControl frame’s instructions
|
||||
for BS (BlockSize) and STmin (SeparationTime minimum). Again, the pass-thru device transmits using
|
||||
CAN ID specified in pFlowControlMsg. In our example, this is $241.
|
||||
|
||||
• Repeat the previous two steps as required.
|
||||
|
||||
• When finished, the pass-thru device will place a TxDone indication in the API receive queue. The data
|
||||
will contain the CAN ID specified in pFlowControlMsg. In our example, this is $241.
|
||||
|
||||
• If loopback is on, the entire message sent will appear in the API receive queue with the
|
||||
TX_MSG_TYPE bit set to 1 in RxStatus. The loopback shall not precede the TxDone indication.
|
||||
|
||||
Before any multi-segment transfer can take place, the conversation must be set up on both sides. It’s
|
||||
assumed that the ECU is already setup. The application is responsible for setting up the pass-thru device.
|
||||
This setup must be done once (and only once) per conversation. The setup involves a single call to
|
||||
PassThruStartMsgFilter, with the following parameters:
|
||||
|
||||
A.2.2 Data Transmission
|
||||
Once the conversation is set up, any number of messages (to the conversation partner) can be
|
||||
transmitted using PassThruWriteMsg. The interface shall handle all aspects of the transfer, including
|
||||
pacing (slowing) the transmission to the requirements of the receiver.
|
||||
|
||||
When there are multiple conversations setup, the pass-thru device will search all of the flow control filters
|
||||
for a matching pFlowControlMsg. If there is no match, the message cannot be sent because the pass-
|
||||
thru device doesn’t know which partner will be pacing the conversation.
|
||||
|
||||
When doing blocking writes, it is important to pick a timeout long enough to cover entire transfer, even if
|
||||
the ECU is pacing things slowly. Otherwise PassThruWriteMsg will return with a timeout, even though the
|
||||
transmission is proceeding normally.
|
||||
|
||||
|
||||
A.3 Transmitting an Unsegmented Message
|
||||
As a special case, transfers that fit in a single frame can be transmitted without setting up a conversation.
|
||||
This is useful during an OBD Request, which is a functionally addressed message that is broadcast to all
|
||||
ECUs. This message must be small enough to fit into a single frame (including headers) because it is not
|
||||
possible to do one segmented transfer to multiple ECUs.
|
||||
|
||||
When using functional addressing for an OBD Request, it is important to remember that there can be no
|
||||
direct reply. Instead, each ECU will send their OBD Response using physical addressing to their
|
||||
conversation partner (e.g. ECU1 to Tester1, ECU2 to Tester2) as defined by ISO 15765-4. The OBD
|
||||
Response may be a segmented transfer, or it may be a single frame.
|
||||
|
||||
In this case, no conversation setup is necessary. The call to PassThruWriteMsg is the same as above,
|
||||
except that the DataSize must be 7 bytes or less (6 bytes or less if extended addressing is turned on).
|
||||
The pass-thru device will automatically insert a PCI byte before transmission.
|
||||
|
||||
|
||||
A.4 Receiving a Segmented Message
|
||||
Message reception is asynchronous to the application. When a FirstFrame is seen on the bus, the pass-
|
||||
thru device will search the list of flow control filters, looking for a pPatternMsg message with the same
|
||||
CAN ID (and possible extended address) as the FirstFrame. Upon matching a filter, the pass-thru device will:
|
||||
|
||||
• Place an RxStart indication in the API receive queue. This indication has the START_OF_MESSAGE
|
||||
bit set in RxFlags. The message data will contain the CAN ID of the sender. In our example, this is
|
||||
$641. DataSize will be 4 bytes (5 with extended addressing), and ExtraDataIndex will be zero.
|
||||
|
||||
• Send a FlowControl frame to the conversation partner. The FlowStatus field shall be set to
|
||||
ontinueToSend. The CAN ID of this segment comes from the filter’s corresponding
|
||||
pFlowControlMsg. In our example, this CAN ID is $241. The BS (BlockSize) and STmin
|
||||
(SeparationTime minimum) parameters default to zero, but can be changed with the SET_CONFIGIoctl.
|
||||
|
||||
• Wait for the conversation partner to send C
|
||||
onsecutiveFrames containing the actual data. The
|
||||
partner’s CAN ID is specified in pPatternMsg. In our example, this CAN ID is $641.
|
||||
|
||||
• Repeat as necessary until the entire block has been received. When finished, the pass-thru device will
|
||||
put the assembled message into the API receive queue. The CAN ID of the assembled message will
|
||||
be the CAN ID of the sender. In our example, this CAN ID is $641.
|
||||
|
||||
If the FirstFrame does not match any flow control filters, then the message must be ignored by the
|
||||
device.
|
||||
|
||||
Segmented messages cause the API to generate an RxStart indication. This lets the application know
|
||||
that the device has started message reception. It may take a while before message reception is
|
||||
complete, especially if the application has increased BS and STmin.
|
||||
|
||||
Once the transfer is complete, the entire message can be read like on any other protocol. Usually,
|
||||
applications will call PassThruReadMsg again immediately after getting an RxStart indication. Application
|
||||
writers should not assume that the complete message will always follow the RxStart indication. If multiple
|
||||
conversations are setup, indications and messages from other conversations can be received in between
|
||||
the RxStart indication and the actual message. The parameters for PassThruReadMsg are exactly the
|
||||
same as in the previous section. The only difference is that the DataSize will be larger and
|
||||
ExtraDataIndex will be non-zero.
|
||||
|
||||
|
||||
|
||||
A.5 Receiving an Unsegmented Message
|
||||
No messages can be received until a conversation is setup. Each conversation setup will receive
|
||||
messages from exactly one CAN ID (and extended address if present). Because setup is bi-directional,
|
||||
the same PassThruStartMsgFilter call used for transmission will allow for message reception.
|
||||
|
||||
When a SingleFrame is seen on the bus, the pass-thru device will search the list of flow control filters,
|
||||
looking for a pPatternMsg message with the same C
|
||||
AN ID (and possible extended address) as the
|
||||
SingleFrame. Upon matching a filter, the pass-thru device will strip the PCI byte and queue the packet for
|
||||
reception. If the SingleFrame does not match a flow control filter, it must be discarded.
|
||||
|
||||
The only difference between the previous cases is that single-frame messages do not generate an
|
||||
RxStart indication.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
After Width: | Height: | Size: 67 KiB |
|
@ -0,0 +1,2 @@
|
|||
#32 bit: HKEY_LOCAL_MACHINE\SOFTWARE\PassThruSupport
|
||||
#64 bit: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\PassThruSupport
|
After Width: | Height: | Size: 70 KiB |
After Width: | Height: | Size: 69 KiB |
After Width: | Height: | Size: 45 KiB |
After Width: | Height: | Size: 45 KiB |
|
@ -0,0 +1,42 @@
|
|||
From focum information on NI hardware: https://forums.ni.com/t5/Automotive-and-Embedded-Networks/15765-2-with-NI-products/td-p/1454256
|
||||
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
Timeout Diag Command is the timeout in milliseconds the master
|
||||
waits for the response to a diagnostic request message. The default is
|
||||
1000 ms.
|
||||
|
||||
Timeout FC (Bs) is the timeout in milliseconds the master waits
|
||||
for a Flow Control frame after sending a First Frame or the last
|
||||
Consecutive Frame of a block. The default is 250 ms.
|
||||
|
||||
Timeout CF (Cr) is the timeout in milliseconds the master waits
|
||||
for a Consecutive Frame in a multiframe response. The default is
|
||||
250 ms.
|
||||
|
||||
Receive Block Size (BS) is the number of Consecutive Frames the
|
||||
slave sends in one block before waiting for the next Flow Control
|
||||
frame. A value of 0 (default) means all Consecutive Frames are sent
|
||||
in one run without interruption.
|
||||
|
||||
Wait Time CF (STmin) defines the minimum time for the slave to
|
||||
wait between sending two Consecutive Frames of a block. Values
|
||||
from 0 to 127 are wait times in milliseconds. Values 241 to 249
|
||||
(Hex F1 to F9) mean wait times of 100 μs to 900 μs, respectively.
|
||||
All other values are reserved. The default is 5 ms.
|
||||
|
||||
Max Wait Frames (N_WFTmax) is the maximum number of WAIT
|
||||
frames the master accepts before terminating the connection. The
|
||||
default is 10.
|
||||
|
||||
|
||||
There are no defined lower limits for these values; you can specify any
|
||||
value down to 0. However, as you correctly pointed out, the timing is
|
||||
done by Windows, and will be subject to the jitter introduced by the OS
|
||||
which can easily be in the order of 10s of milliseconds. It is however
|
||||
hard to give more accurate numbers as the actual jitter is dependent on
|
||||
the workload of the computer
|
||||
/////////////////////////////////////////////////////////////////////
|
||||
|
||||
J2534 04.04 does not appear to have default adjustable parameters for
|
||||
the timeout related fields. For now, these default values shall be used
|
||||
in the Panda J2534 implementation.
|
|
@ -0,0 +1,99 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{BD34DB24-F5DC-4992-A74F-05FAF731ABED}</ProjectGuid>
|
||||
<TemplateGuid>{a1357fe7-03e0-4d61-85f4-09c7ed38c0c1}</TemplateGuid>
|
||||
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
|
||||
<MinimumVisualStudioVersion>12.0</MinimumVisualStudioVersion>
|
||||
<Configuration>$driverCurrentWindowsConfigurationName$ Debug</Configuration>
|
||||
<Platform Condition="'$(Platform)' == ''">Win32</Platform>
|
||||
<RootNamespace>panda_Driver_Package</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>$(LatestTargetPlatformVersion)</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<TargetVersion>Windows10</TargetVersion>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||
<ConfigurationType>Utility</ConfigurationType>
|
||||
<DriverType>Package</DriverType>
|
||||
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<TargetVersion>Windows10</TargetVersion>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>WindowsKernelModeDriver10.0</PlatformToolset>
|
||||
<ConfigurationType>Utility</ConfigurationType>
|
||||
<DriverType>Package</DriverType>
|
||||
<DisableFastUpToDateCheck>true</DisableFastUpToDateCheck>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<!-- Debug the associated application, not the WinUSB driver -->
|
||||
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
|
||||
<HardwareIdString />
|
||||
<CommandLine />
|
||||
<DeployFiles />
|
||||
<EnableVerifier>False</EnableVerifier>
|
||||
<AllDrivers>False</AllDrivers>
|
||||
<VerifyProjectOutput>True</VerifyProjectOutput>
|
||||
<VerifyDrivers />
|
||||
<VerifyFlags>133563</VerifyFlags>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<!-- Debug the associated application, not the WinUSB driver -->
|
||||
<DebuggerFlavor>DbgengRemoteDebugger</DebuggerFlavor>
|
||||
<HardwareIdString />
|
||||
<CommandLine />
|
||||
<DeployFiles />
|
||||
<EnableVerifier>False</EnableVerifier>
|
||||
<AllDrivers>False</AllDrivers>
|
||||
<VerifyProjectOutput>True</VerifyProjectOutput>
|
||||
<VerifyDrivers />
|
||||
<VerifyFlags>133563</VerifyFlags>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Inf Include="panda.inf" />
|
||||
<!-- Explicitly set all FilesToPackage since there is no dependency on a driver -->
|
||||
<FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''" />
|
||||
<FilesToPackage Condition="$(KMDF_VERSION_MAJOR) == 1 and $(KMDF_VERSION_MINOR) < 13" Include="$(WDKContentRoot)redist\wdf\$(DDKPlatform)\WdfCoinstaller$(KMDF_VERSION_MAJOR_STRING)$(KMDF_VERSION_MINOR_STRING).dll" />
|
||||
</ItemGroup>
|
||||
<!-- INF handling depends on order. Some of the above ImportGroup nodes set up INF handling. -->
|
||||
<!-- Modify INF handling here. -->
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Inf>
|
||||
<!-- The WinUSB driver requires KMDF, so we must provide a KMDF version number in the INF. -->
|
||||
<!-- Use the user's KMDF setting (defaults to latest) -->
|
||||
<KmdfVersionNumber>$(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)</KmdfVersionNumber>
|
||||
</Inf>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Inf>
|
||||
<!-- The WinUSB driver requires KMDF, so we must provide a KMDF version number in the INF. -->
|
||||
<!-- Use the user's KMDF setting (defaults to latest) -->
|
||||
<KmdfVersionNumber>$(KMDF_VERSION_MAJOR).$(KMDF_VERSION_MINOR)</KmdfVersionNumber>
|
||||
</Inf>
|
||||
</ItemDefinitionGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,14 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Driver Files">
|
||||
<UniqueIdentifier>{8E41214B-6785-4CFE-B992-037D68949A14}</UniqueIdentifier>
|
||||
<Extensions>inf;inv;inx;mof;mc;</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Inf Include="panda.inf">
|
||||
<Filter>Driver Files</Filter>
|
||||
</Inf>
|
||||
</ItemGroup>
|
||||
</Project>
|
After Width: | Height: | Size: 95 KiB |
|
@ -0,0 +1,90 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "pandaJ2534DLL", "pandaJ2534DLL\pandaJ2534DLL.vcxproj", "{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531} = {5528AEFB-638D-49AF-B9D4-965154E7D531}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "panda", "panda\panda.vcxproj", "{5528AEFB-638D-49AF-B9D4-965154E7D531}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "panda_playground", "panda_playground\panda_playground.vcxproj", "{691DB635-C272-4B98-897E-0505B970DCA9}"
|
||||
ProjectSection(ProjectDependencies) = postProject
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531} = {5528AEFB-638D-49AF-B9D4-965154E7D531}
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "panda Driver Package", "panda Driver Package\panda Driver Package.vcxproj", "{BD34DB24-F5DC-4992-A74F-05FAF731ABED}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "Tests", "pandaJ2534DLL Test\pandaJ2534DLL Test.vcxproj", "{7912F978-B48C-4C5D-8BFD-5D1E22158E47}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ECUsim DLL", "ECUsim DLL\ECUsim DLL.vcxproj", "{96E0E646-EE76-444D-9A77-A0CD7F781DEB}"
|
||||
EndProject
|
||||
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ECUsim CLI", "ECUsim CLI\ECUsim CLI.vcxproj", "{D99E2FCD-21A4-4065-949A-31E34E0E69D1}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|x64 = Debug|x64
|
||||
Debug|x86 = Debug|x86
|
||||
Release|x64 = Release|x64
|
||||
Release|x86 = Release|x86
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}.Debug|x86.Build.0 = Debug|Win32
|
||||
{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}.Release|x64.ActiveCfg = Release|Win32
|
||||
{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}.Release|x86.ActiveCfg = Release|Win32
|
||||
{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}.Release|x86.Build.0 = Release|Win32
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Debug|x64.Build.0 = Debug|x64
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Debug|x86.Build.0 = Debug|Win32
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Release|x64.ActiveCfg = Release|x64
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Release|x64.Build.0 = Release|x64
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Release|x86.ActiveCfg = Release|Win32
|
||||
{5528AEFB-638D-49AF-B9D4-965154E7D531}.Release|x86.Build.0 = Release|Win32
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Debug|x64.Build.0 = Debug|x64
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Debug|x86.Build.0 = Debug|Win32
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Release|x64.ActiveCfg = Release|x64
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Release|x64.Build.0 = Release|x64
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Release|x86.ActiveCfg = Release|Win32
|
||||
{691DB635-C272-4B98-897E-0505B970DCA9}.Release|x86.Build.0 = Release|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Debug|x86.Build.0 = Debug|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Debug|x86.Deploy.0 = Debug|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Release|x64.ActiveCfg = Release|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Release|x86.ActiveCfg = Release|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Release|x86.Build.0 = Release|Win32
|
||||
{BD34DB24-F5DC-4992-A74F-05FAF731ABED}.Release|x86.Deploy.0 = Release|Win32
|
||||
{7912F978-B48C-4C5D-8BFD-5D1E22158E47}.Debug|x64.ActiveCfg = Debug|Win32
|
||||
{7912F978-B48C-4C5D-8BFD-5D1E22158E47}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{7912F978-B48C-4C5D-8BFD-5D1E22158E47}.Debug|x86.Build.0 = Debug|Win32
|
||||
{7912F978-B48C-4C5D-8BFD-5D1E22158E47}.Release|x64.ActiveCfg = Release|Win32
|
||||
{7912F978-B48C-4C5D-8BFD-5D1E22158E47}.Release|x86.ActiveCfg = Release|Win32
|
||||
{7912F978-B48C-4C5D-8BFD-5D1E22158E47}.Release|x86.Build.0 = Release|Win32
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Debug|x64.Build.0 = Debug|x64
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Debug|x86.Build.0 = Debug|Win32
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Release|x64.ActiveCfg = Release|x64
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Release|x64.Build.0 = Release|x64
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Release|x86.ActiveCfg = Release|Win32
|
||||
{96E0E646-EE76-444D-9A77-A0CD7F781DEB}.Release|x86.Build.0 = Release|Win32
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Debug|x64.ActiveCfg = Debug|x64
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Debug|x64.Build.0 = Debug|x64
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Debug|x86.ActiveCfg = Debug|Win32
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Debug|x86.Build.0 = Debug|Win32
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Release|x64.ActiveCfg = Release|x64
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Release|x64.Build.0 = Release|x64
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Release|x86.ActiveCfg = Release|Win32
|
||||
{D99E2FCD-21A4-4065-949A-31E34E0E69D1}.Release|x86.Build.0 = Release|Win32
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,166 @@
|
|||
#include "stdafx.h"
|
||||
#include <SetupAPI.h>
|
||||
#include <Devpkey.h>
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
|
||||
#include "device.h"
|
||||
|
||||
using namespace panda;
|
||||
|
||||
//Returns the last Win32 error, in string format. Returns an empty string if there is no error.
|
||||
tstring GetLastErrorAsString(){
|
||||
//Get the error message, if any.
|
||||
DWORD errorMessageID = ::GetLastError();
|
||||
if (errorMessageID == 0)
|
||||
return tstring(); //No error message has been recorded
|
||||
|
||||
_TCHAR *messageBuffer = nullptr;
|
||||
size_t size = FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL, errorMessageID, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (_TCHAR*)&messageBuffer, 0, NULL);
|
||||
|
||||
tstring message(messageBuffer, size);
|
||||
|
||||
//Free the buffer.
|
||||
LocalFree(messageBuffer);
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
std::unordered_map<std::string, tstring> panda::detect_pandas() {
|
||||
HDEVINFO deviceInfo;
|
||||
HRESULT hr;
|
||||
SP_DEVINFO_DATA deviceInfoData;
|
||||
SP_DEVICE_INTERFACE_DATA interfaceData;
|
||||
unsigned int deviceIndex;
|
||||
|
||||
std::unordered_map<std::string, tstring> map_sn_to_devpath;
|
||||
|
||||
deviceInfo = SetupDiGetClassDevs(&GUID_DEVINTERFACE_panda,
|
||||
NULL, NULL, DIGCF_PRESENT | DIGCF_DEVICEINTERFACE); //DIGCF_ALLCLASSES
|
||||
|
||||
if (deviceInfo == INVALID_HANDLE_VALUE) {
|
||||
hr = HRESULT_FROM_WIN32(GetLastError());
|
||||
_tprintf(_T("Failed to get dev handle. HR: %d\n"), hr);
|
||||
return map_sn_to_devpath;
|
||||
}
|
||||
|
||||
ZeroMemory(&deviceInfoData, sizeof(SP_DEVINFO_DATA));
|
||||
deviceInfoData.cbSize = sizeof(SP_DEVINFO_DATA);
|
||||
deviceIndex = 0;
|
||||
|
||||
while (SetupDiEnumDeviceInfo(deviceInfo, deviceIndex, &deviceInfoData)) {
|
||||
deviceIndex++;
|
||||
_tprintf(_T("Device info index %d\n"), deviceIndex);
|
||||
|
||||
interfaceData.cbSize = sizeof(SP_DEVICE_INTERFACE_DATA);
|
||||
if (SetupDiEnumDeviceInterfaces(deviceInfo, &deviceInfoData,
|
||||
&GUID_DEVINTERFACE_panda, 0, &interfaceData) == FALSE) {
|
||||
_tprintf(_T(" Got unexpected error while accessing interface %d\n"), GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
DWORD requiredLength;
|
||||
if (SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, NULL, 0, &requiredLength, NULL) == FALSE
|
||||
&& ERROR_INSUFFICIENT_BUFFER != GetLastError()) {
|
||||
_tprintf(_T(" Got unexpected error while reading interface details %d\n"), GetLastError());
|
||||
continue;
|
||||
}
|
||||
|
||||
PSP_DEVICE_INTERFACE_DETAIL_DATA detailData = (PSP_DEVICE_INTERFACE_DETAIL_DATA)LocalAlloc(LMEM_FIXED, requiredLength);
|
||||
if (NULL == detailData) {
|
||||
_tprintf(_T(" Failed to allocate %d bytes for interface data\n"), requiredLength);
|
||||
continue;
|
||||
}
|
||||
detailData->cbSize = sizeof(SP_DEVICE_INTERFACE_DETAIL_DATA);
|
||||
|
||||
DWORD length = requiredLength;
|
||||
if (SetupDiGetDeviceInterfaceDetail(deviceInfo, &interfaceData, detailData, length, &requiredLength, NULL) == FALSE) {
|
||||
_tprintf(_T(" Got unexpected error while reading interface details (2nd time) %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
LocalFree(detailData);
|
||||
continue;
|
||||
}
|
||||
|
||||
//_tprintf(_T(" Path: '%s'\n"), detailData->DevicePath);
|
||||
HANDLE deviceHandle = CreateFile(detailData->DevicePath,
|
||||
GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == deviceHandle) {
|
||||
_tprintf(_T(" Error opening Device Handle %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
LocalFree(detailData);
|
||||
continue;
|
||||
}
|
||||
|
||||
WINUSB_INTERFACE_HANDLE winusbHandle;
|
||||
if (WinUsb_Initialize(deviceHandle, &winusbHandle) == FALSE) {
|
||||
_tprintf(_T(" Error initializing WinUSB %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
CloseHandle(deviceHandle);
|
||||
LocalFree(detailData);
|
||||
continue;
|
||||
}
|
||||
|
||||
USB_DEVICE_DESCRIPTOR deviceDesc;
|
||||
unsigned long lengthReceived;
|
||||
if (WinUsb_GetDescriptor(winusbHandle, USB_DEVICE_DESCRIPTOR_TYPE, 0, 0,
|
||||
(PBYTE)&deviceDesc, sizeof(deviceDesc), &lengthReceived) == FALSE
|
||||
|| lengthReceived != sizeof(deviceDesc)) {
|
||||
_tprintf(_T(" Error getting device descriptor %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
WinUsb_Free(winusbHandle);
|
||||
CloseHandle(deviceHandle);
|
||||
LocalFree(detailData);
|
||||
continue;
|
||||
}
|
||||
|
||||
#define SNDESCLEN 64
|
||||
PUSB_STRING_DESCRIPTOR psnDesc = (PUSB_STRING_DESCRIPTOR)LocalAlloc(LMEM_FIXED, SNDESCLEN);
|
||||
if (NULL == psnDesc) {
|
||||
_tprintf(_T(" Failed to allocate %d bytes for sn data\n"), SNDESCLEN);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (WinUsb_GetDescriptor(winusbHandle, USB_STRING_DESCRIPTOR_TYPE, deviceDesc.iSerialNumber,
|
||||
0x0409 /*Eng*/, (PBYTE)psnDesc, SNDESCLEN, &lengthReceived) == FALSE || lengthReceived == 0) {
|
||||
_tprintf(_T(" Error getting serial number %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
LocalFree(psnDesc);
|
||||
WinUsb_Free(winusbHandle);
|
||||
CloseHandle(deviceHandle);
|
||||
LocalFree(detailData);
|
||||
continue;
|
||||
}
|
||||
//The minus 2 is for the two numbers, not the null term.
|
||||
psnDesc->bString[(psnDesc->bLength - 2) / sizeof(_TCHAR)] = 0;
|
||||
|
||||
char w_to_m_buff[256];
|
||||
size_t mbuff_len;
|
||||
if (wcstombs_s(&mbuff_len, w_to_m_buff, sizeof(w_to_m_buff), psnDesc->bString, 24) != 0) {
|
||||
_tprintf(_T(" Error generating mb SN string %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
LocalFree(psnDesc);
|
||||
WinUsb_Free(winusbHandle);
|
||||
CloseHandle(deviceHandle);
|
||||
LocalFree(detailData);
|
||||
continue;
|
||||
}
|
||||
std::string serialnum(w_to_m_buff, mbuff_len-1);
|
||||
printf(" Device found: seriallen: %d; serial: %s\n", lengthReceived, serialnum.c_str());
|
||||
|
||||
map_sn_to_devpath[serialnum] = tstring(detailData->DevicePath);
|
||||
|
||||
LocalFree(psnDesc);
|
||||
WinUsb_Free(winusbHandle);
|
||||
CloseHandle(deviceHandle);
|
||||
LocalFree(detailData);
|
||||
}
|
||||
|
||||
if(deviceInfo)
|
||||
SetupDiDestroyDeviceInfoList(deviceInfo);
|
||||
|
||||
return map_sn_to_devpath;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#ifndef __PANDA_DEVICE
|
||||
#define __PANDA_DEVICE
|
||||
|
||||
//
|
||||
// Define below GUIDs
|
||||
//
|
||||
#include "stdafx.h"
|
||||
#include <initguid.h>
|
||||
#include <unordered_map>
|
||||
|
||||
#if defined(UNICODE)
|
||||
#define _tcout std::wcout
|
||||
#define tstring std::wstring
|
||||
#else
|
||||
#define _tcout std::cout
|
||||
#define tstring std::string
|
||||
#endif
|
||||
|
||||
//
|
||||
// Device Interface GUID.
|
||||
// Used by all WinUsb devices that this application talks to.
|
||||
// Must match "DeviceInterfaceGUIDs" registry value specified in the INF file.
|
||||
// cce5291c-a69f-4995-a4c2-2ae57a51ade9
|
||||
//
|
||||
DEFINE_GUID(GUID_DEVINTERFACE_panda,
|
||||
0xcce5291c,0xa69f,0x4995,0xa4,0xc2,0x2a,0xe5,0x7a,0x51,0xad,0xe9);
|
||||
|
||||
tstring GetLastErrorAsString();
|
||||
|
||||
namespace panda {
|
||||
std::unordered_map<std::string, tstring> __declspec(dllexport) detect_pandas();
|
||||
}
|
||||
#endif
|
|
@ -0,0 +1,19 @@
|
|||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "stdafx.h"
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
|
@ -0,0 +1,79 @@
|
|||
#include "stdafx.h"
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
LONG __cdecl
|
||||
_tmain(
|
||||
LONG Argc,
|
||||
LPTSTR * Argv
|
||||
)
|
||||
/*++
|
||||
|
||||
Routine description:
|
||||
|
||||
Sample program that communicates with a USB device using WinUSB
|
||||
|
||||
--*/
|
||||
{
|
||||
DEVICE_DATA deviceData;
|
||||
HRESULT hr;
|
||||
USB_DEVICE_DESCRIPTOR deviceDesc;
|
||||
BOOL bResult;
|
||||
BOOL noDevice;
|
||||
ULONG lengthReceived;
|
||||
|
||||
UNREFERENCED_PARAMETER(Argc);
|
||||
UNREFERENCED_PARAMETER(Argv);
|
||||
|
||||
//
|
||||
// Find a device connected to the system that has WinUSB installed using our
|
||||
// INF
|
||||
//
|
||||
hr = OpenDevice(&deviceData, &noDevice);
|
||||
|
||||
if (FAILED(hr)) {
|
||||
|
||||
if (noDevice) {
|
||||
|
||||
printf(_T("Device not connected or driver not installed\n"));
|
||||
|
||||
} else {
|
||||
|
||||
printf(_T("Failed looking for device, HRESULT 0x%x\n"), hr);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Get device descriptor
|
||||
//
|
||||
bResult = WinUsb_GetDescriptor(deviceData.WinusbHandle,
|
||||
USB_DEVICE_DESCRIPTOR_TYPE,
|
||||
0,
|
||||
0,
|
||||
(PBYTE) &deviceDesc,
|
||||
sizeof(deviceDesc),
|
||||
&lengthReceived);
|
||||
|
||||
if (FALSE == bResult || lengthReceived != sizeof(deviceDesc)) {
|
||||
|
||||
printf(_T("Error among LastError %d or lengthReceived %d\n"),
|
||||
FALSE == bResult ? GetLastError() : 0,
|
||||
lengthReceived);
|
||||
CloseDevice(&deviceData);
|
||||
return 0;
|
||||
}
|
||||
|
||||
//
|
||||
// Print a few parts of the device descriptor
|
||||
//
|
||||
printf(_T("Device found: VID_%04X&PID_%04X; bcdUsb %04X; path: %s\n"),
|
||||
deviceDesc.idVendor,
|
||||
deviceDesc.idProduct,
|
||||
deviceDesc.bcdUSB,
|
||||
deviceData.DevicePath);
|
||||
|
||||
CloseDevice(&deviceData);
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,479 @@
|
|||
// panda.cpp : Defines the exported functions for the DLL application.
|
||||
//
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "device.h"
|
||||
#include "panda.h"
|
||||
|
||||
#define REQUEST_IN 0xC0
|
||||
#define REQUEST_OUT 0x40
|
||||
|
||||
#define CAN_TRANSMIT 1
|
||||
#define CAN_EXTENDED 4
|
||||
|
||||
using namespace panda;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct _PANDA_CAN_MSG_INTERNAL {
|
||||
uint32_t rir;
|
||||
uint32_t f2;
|
||||
uint8_t dat[8];
|
||||
} PANDA_CAN_MSG_INTERNAL;
|
||||
|
||||
Panda::Panda(
|
||||
WINUSB_INTERFACE_HANDLE WinusbHandle,
|
||||
HANDLE DeviceHandle,
|
||||
tstring devPath_,
|
||||
std::string sn_
|
||||
) : usbh(WinusbHandle), devh(DeviceHandle), devPath(devPath_), sn(sn_) {
|
||||
printf("CREATED A PANDA %s\n", this->sn.c_str());
|
||||
this->set_can_loopback(FALSE);
|
||||
this->set_alt_setting(0);
|
||||
}
|
||||
|
||||
Panda::~Panda() {
|
||||
WinUsb_Free(this->usbh);
|
||||
CloseHandle(this->devh);
|
||||
printf("Cleanup Panda %s\n", this->sn.c_str());
|
||||
}
|
||||
|
||||
std::vector<std::string> Panda::listAvailablePandas() {
|
||||
std::vector<std::string> ret;
|
||||
auto map_sn_to_devpath = detect_pandas();
|
||||
|
||||
for (auto kv : map_sn_to_devpath) {
|
||||
ret.push_back(std::string(kv.first));
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::unique_ptr<Panda> Panda::openPanda(std::string sn)
|
||||
{
|
||||
auto map_sn_to_devpath = detect_pandas();
|
||||
|
||||
if (map_sn_to_devpath.empty()) return nullptr;
|
||||
if (map_sn_to_devpath.find(sn) == map_sn_to_devpath.end() && sn != "") return nullptr;
|
||||
|
||||
tstring devpath;
|
||||
if (sn.empty()) {
|
||||
sn = map_sn_to_devpath.begin()->first;
|
||||
devpath = map_sn_to_devpath.begin()->second;
|
||||
} else {
|
||||
devpath = map_sn_to_devpath[sn];
|
||||
}
|
||||
|
||||
HANDLE deviceHandle = CreateFile(devpath.c_str(),
|
||||
GENERIC_WRITE | GENERIC_READ, FILE_SHARE_WRITE | FILE_SHARE_READ,
|
||||
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED, NULL);
|
||||
|
||||
if (INVALID_HANDLE_VALUE == deviceHandle) {
|
||||
_tprintf(_T(" Error opening Device Handle %d.\n"),// Msg: '%s'\n"),
|
||||
GetLastError());// , GetLastErrorAsString().c_str());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
WINUSB_INTERFACE_HANDLE winusbHandle;
|
||||
if (WinUsb_Initialize(deviceHandle, &winusbHandle) == FALSE) {
|
||||
_tprintf(_T(" Error initializing WinUSB %d.\n"),// Msg: '%s'\n"),
|
||||
GetLastError());// , GetLastErrorAsString().c_str());
|
||||
CloseHandle(deviceHandle);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return std::unique_ptr<Panda>(new Panda(winusbHandle, deviceHandle, map_sn_to_devpath[sn], sn));
|
||||
}
|
||||
|
||||
std::string Panda::get_usb_sn() {
|
||||
return std::string(this->sn);
|
||||
}
|
||||
|
||||
int Panda::control_transfer(
|
||||
uint8_t bmRequestType,
|
||||
uint8_t bRequest,
|
||||
uint16_t wValue,
|
||||
uint16_t wIndex,
|
||||
void * data,
|
||||
uint16_t wLength,
|
||||
unsigned int timeout
|
||||
) {
|
||||
UNREFERENCED_PARAMETER(timeout);
|
||||
|
||||
WINUSB_SETUP_PACKET SetupPacket;
|
||||
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
|
||||
ULONG cbSent = 0;
|
||||
|
||||
//Create the setup packet
|
||||
SetupPacket.RequestType = bmRequestType;
|
||||
SetupPacket.Request = bRequest;
|
||||
SetupPacket.Value = wValue;
|
||||
SetupPacket.Index = wIndex;
|
||||
SetupPacket.Length = wLength;
|
||||
|
||||
//ULONG timeout = 10; // ms
|
||||
//WinUsb_SetPipePolicy(interfaceHandle, pipeID, PIPE_TRANSFER_TIMEOUT, sizeof(ULONG), &timeout);
|
||||
|
||||
if (WinUsb_ControlTransfer(this->usbh, SetupPacket, (PUCHAR)data, wLength, &cbSent, 0) == FALSE) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return cbSent;
|
||||
}
|
||||
|
||||
int Panda::bulk_write(UCHAR endpoint, const void * buff, ULONG length, PULONG transferred, ULONG timeout) {
|
||||
if (this->usbh == INVALID_HANDLE_VALUE || !buff || !length || !transferred) return FALSE;
|
||||
|
||||
if (WinUsb_WritePipe(this->usbh, endpoint, (PUCHAR)buff, length, transferred, NULL) == FALSE) {
|
||||
_tprintf(_T(" Got error during bulk xfer: %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
int Panda::bulk_read(UCHAR endpoint, void * buff, ULONG buff_size, PULONG transferred, ULONG timeout) {
|
||||
if (this->usbh == INVALID_HANDLE_VALUE || !buff || !buff_size || !transferred) return FALSE;
|
||||
|
||||
if (WinUsb_ReadPipe(this->usbh, endpoint, (PUCHAR)buff, buff_size, transferred, NULL) == FALSE) {
|
||||
_tprintf(_T(" Got error during bulk xfer: %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool Panda::set_alt_setting(UCHAR alt_setting) {
|
||||
if (WinUsb_AbortPipe(this->usbh, 0x81) == FALSE) {
|
||||
_tprintf(_T(" Error abobrting pipe before setting altsetting. continue. %d, Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
}
|
||||
if (WinUsb_SetCurrentAlternateSetting(this->usbh, alt_setting) == FALSE) {
|
||||
_tprintf(_T(" Error setting usb altsetting %d, Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// Either the panda or the windows usb stack can drop messages
|
||||
// if an odd number of messages are sent before an interrupt IN
|
||||
// message is canceled. There are some other odd behaviors, but
|
||||
// the best solution so far has been to send a few messages
|
||||
// before using the device to clear out the pipe. No, the windows
|
||||
// functions for clearing/resetting/etc the pipe did not work.
|
||||
// This took way too to figure out a workaround.
|
||||
// New info. The most repeatable behavior is losing the first
|
||||
// message sent after setting alt setting to 1 (even without
|
||||
// receiving). Something like this happened on linux sometimes.
|
||||
bool loopback_backup = this->loopback;
|
||||
this->set_can_loopback(TRUE);
|
||||
Sleep(20); // Give time for any sent messages to appear in the RX buffer.
|
||||
this->can_clear(PANDA_CAN_RX);
|
||||
for (int i = 0; i < 2; i++) {
|
||||
printf("Sending PAD %d\n", i);
|
||||
if (this->can_send(0x7FF, FALSE, {}, 0, PANDA_CAN1) == FALSE) {
|
||||
auto err = GetLastError();
|
||||
printf("Got err on first send: %d\n", err);
|
||||
}
|
||||
}
|
||||
Sleep(10);
|
||||
//this->can_clear(PANDA_CAN_RX);
|
||||
|
||||
std::vector<PANDA_CAN_MSG> msg_recv;
|
||||
if (alt_setting == 1) {
|
||||
//Read the messages so they do not contaimnate the real message stream.
|
||||
auto err = this->can_recv_async(NULL, msg_recv, 1000);
|
||||
}
|
||||
else {
|
||||
msg_recv = this->can_recv();
|
||||
}
|
||||
|
||||
//this->set_can_loopback(FALSE);
|
||||
this->set_can_loopback(loopback_backup);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
UCHAR Panda::get_current_alt_setting() {
|
||||
UCHAR alt_setting;
|
||||
if (WinUsb_GetCurrentAlternateSetting(this->usbh, &alt_setting) == FALSE) {
|
||||
_tprintf(_T(" Error getting usb altsetting %d, Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return alt_setting;
|
||||
}
|
||||
|
||||
PANDA_HEALTH Panda::get_health()
|
||||
{
|
||||
WINUSB_SETUP_PACKET SetupPacket;
|
||||
ZeroMemory(&SetupPacket, sizeof(WINUSB_SETUP_PACKET));
|
||||
ULONG cbSent = 0;
|
||||
|
||||
//Create the setup packet
|
||||
SetupPacket.RequestType = REQUEST_IN;
|
||||
SetupPacket.Request = 0xD2;
|
||||
SetupPacket.Value = 0;
|
||||
SetupPacket.Index = 0;
|
||||
SetupPacket.Length = sizeof(UCHAR);
|
||||
|
||||
//uint8_t health[13];
|
||||
PANDA_HEALTH health;
|
||||
|
||||
if (WinUsb_ControlTransfer(this->usbh, SetupPacket, (PUCHAR)&health, sizeof(health), &cbSent, 0) == FALSE) {
|
||||
_tprintf(_T(" Got unexpected error while reading panda health (2nd time) %d. Msg: '%s'\n"),
|
||||
GetLastError(), GetLastErrorAsString().c_str());
|
||||
}
|
||||
|
||||
return health;
|
||||
}
|
||||
|
||||
bool Panda::enter_bootloader() {
|
||||
return this->control_transfer(REQUEST_OUT, 0xd1, 0, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
std::string Panda::get_version() {
|
||||
char buff[0x40];
|
||||
ZeroMemory(&buff, sizeof(buff));
|
||||
|
||||
int xferCount = this->control_transfer(REQUEST_IN, 0xd6, 0, 0, buff, 0x40, 0);
|
||||
if (xferCount == -1) return std::string();
|
||||
return std::string(buff);
|
||||
}
|
||||
|
||||
//TODO: Do hash stuff for calculating the serial.
|
||||
std::string Panda::get_serial() {
|
||||
char buff[0x20];
|
||||
ZeroMemory(&buff, sizeof(buff));
|
||||
|
||||
int xferCount = this->control_transfer(REQUEST_IN, 0xD0, 0, 0, buff, 0x20, 0);
|
||||
if (xferCount == -1) return std::string();
|
||||
return std::string(buff);
|
||||
|
||||
//dat = self._handle.controlRead(REQUEST_IN, 0xd0, 0, 0, 0x20);
|
||||
//hashsig, calc_hash = dat[0x1c:], hashlib.sha1(dat[0:0x1c]).digest()[0:4]
|
||||
// assert(hashsig == calc_hash)
|
||||
// return[dat[0:0x10], dat[0x10:0x10 + 10]]
|
||||
}
|
||||
|
||||
//Secret appears to by raw bytes, not a string. TODO: Change returned type.
|
||||
std::string Panda::get_secret() {
|
||||
char buff[0x10];
|
||||
ZeroMemory(&buff, sizeof(buff));
|
||||
|
||||
int xferCount = this->control_transfer(REQUEST_IN, 0xd0, 1, 0, buff, 0x10, 0);
|
||||
if (xferCount == -1) return std::string();
|
||||
return std::string(buff);
|
||||
}
|
||||
|
||||
bool Panda::set_usb_power(bool on) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xe6, (int)on, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::set_esp_power(bool on) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xd9, (int)on, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::esp_reset(uint16_t bootmode = 0) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xda, bootmode, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::set_safety_mode(PANDA_SAFETY_MODE mode = SAFETY_NOOUTPUT) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xdc, mode, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::set_can_forwarding(PANDA_CAN_PORT from_bus, PANDA_CAN_PORT to_bus) {
|
||||
if (from_bus == PANDA_CAN_UNK) return FALSE;
|
||||
return this->control_transfer(REQUEST_OUT, 0xdd, from_bus, to_bus, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::set_gmlan(PANDA_GMLAN_HOST_PORT bus = PANDA_GMLAN_CAN3) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xdb, 1, (bus == PANDA_GMLAN_CLEAR) ? 0 : bus, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::set_can_loopback(bool enable) {
|
||||
this->loopback = enable;
|
||||
return this->control_transfer(REQUEST_OUT, 0xe5, enable, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
//Can not use the full range of 16 bit speed.
|
||||
//cbps means centa bits per second (tento of kbps)
|
||||
bool Panda::set_can_speed_cbps(PANDA_CAN_PORT bus, uint16_t speed) {
|
||||
if (bus == PANDA_CAN_UNK) return FALSE;
|
||||
return this->control_transfer(REQUEST_OUT, 0xde, bus, speed, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
//Can not use the full range of 16 bit speed.
|
||||
bool Panda::set_can_speed_kbps(PANDA_CAN_PORT bus, uint16_t speed) {
|
||||
return set_can_speed_cbps(bus, speed * 10);
|
||||
}
|
||||
|
||||
//Can not use full 32 bit range of rate
|
||||
bool Panda::set_uart_baud(PANDA_SERIAL_PORT uart, uint32_t rate) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xe4, uart, rate / 300, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::set_uart_parity(PANDA_SERIAL_PORT uart, PANDA_SERIAL_PORT_PARITY parity) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xe2, uart, parity, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
bool Panda::can_send_many(const std::vector<PANDA_CAN_MSG>& can_msgs) {
|
||||
std::vector<PANDA_CAN_MSG_INTERNAL> formatted_msgs;
|
||||
formatted_msgs.reserve(can_msgs.size());
|
||||
|
||||
for (auto msg : can_msgs) {
|
||||
if (msg.bus == PANDA_CAN_UNK) continue;
|
||||
if (msg.len > 8) continue;
|
||||
PANDA_CAN_MSG_INTERNAL tmpmsg = {};
|
||||
tmpmsg.rir = (msg.addr_29b) ?
|
||||
((msg.addr << 3) | CAN_TRANSMIT | CAN_EXTENDED) :
|
||||
(((msg.addr & 0x7FF) << 21) | CAN_TRANSMIT);
|
||||
tmpmsg.f2 = msg.len | (msg.bus << 4);
|
||||
memcpy(tmpmsg.dat, msg.dat, msg.len);
|
||||
formatted_msgs.push_back(tmpmsg);
|
||||
}
|
||||
|
||||
if (formatted_msgs.size() == 0) return FALSE;
|
||||
|
||||
unsigned int retcount;
|
||||
return this->bulk_write(3, formatted_msgs.data(),
|
||||
sizeof(PANDA_CAN_MSG_INTERNAL)*formatted_msgs.size(), (PULONG)&retcount, 0);
|
||||
}
|
||||
|
||||
bool Panda::can_send(uint32_t addr, bool addr_29b, const uint8_t *dat, uint8_t len, PANDA_CAN_PORT bus) {
|
||||
if (bus == PANDA_CAN_UNK) return FALSE;
|
||||
if (len > 8) return FALSE;
|
||||
PANDA_CAN_MSG msg;
|
||||
msg.addr_29b = addr_29b;
|
||||
msg.addr = addr;
|
||||
msg.len = len;
|
||||
memcpy(msg.dat, dat, msg.len);
|
||||
msg.bus = bus;
|
||||
return this->can_send_many(std::vector<PANDA_CAN_MSG>{msg});
|
||||
}
|
||||
|
||||
void Panda::parse_can_recv(std::vector<PANDA_CAN_MSG>& msg_recv, char *buff, int retcount) {
|
||||
for (int i = 0; i < retcount; i += sizeof(PANDA_CAN_MSG_INTERNAL)) {
|
||||
PANDA_CAN_MSG_INTERNAL *in_msg_raw = (PANDA_CAN_MSG_INTERNAL *)(buff + i);
|
||||
PANDA_CAN_MSG in_msg;
|
||||
|
||||
in_msg.addr_29b = (bool)(in_msg_raw->rir & CAN_EXTENDED);
|
||||
in_msg.addr = (in_msg.addr_29b) ? (in_msg_raw->rir >> 3) : (in_msg_raw->rir >> 21);
|
||||
in_msg.recv_time = this->runningTime.getTimePassedUS();
|
||||
in_msg.recv_time_point = std::chrono::steady_clock::now();
|
||||
//The timestamp from the device is (in_msg_raw->f2 >> 16),
|
||||
//but this 16 bit value is a little hard to use. Using a
|
||||
//timer since the initialization of this device.
|
||||
in_msg.len = in_msg_raw->f2 & 0xF;
|
||||
memcpy(in_msg.dat, in_msg_raw->dat, 8);
|
||||
|
||||
in_msg.is_receipt = ((in_msg_raw->f2 >> 4) & 0x80) == 0x80;
|
||||
switch ((in_msg_raw->f2 >> 4) & 0x7F) {
|
||||
case PANDA_CAN1:
|
||||
in_msg.bus = PANDA_CAN1;
|
||||
break;
|
||||
case PANDA_CAN2:
|
||||
in_msg.bus = PANDA_CAN2;
|
||||
break;
|
||||
case PANDA_CAN3:
|
||||
in_msg.bus = PANDA_CAN3;
|
||||
break;
|
||||
default:
|
||||
in_msg.bus = PANDA_CAN_UNK;
|
||||
}
|
||||
msg_recv.push_back(in_msg);
|
||||
}
|
||||
}
|
||||
|
||||
bool Panda::can_recv_async(HANDLE kill_event, std::vector<PANDA_CAN_MSG>& msg_buff, DWORD timeoutms) {
|
||||
int retcount;
|
||||
char buff[sizeof(PANDA_CAN_MSG_INTERNAL) * 4];
|
||||
|
||||
// Overlapped structure required for async read.
|
||||
HANDLE m_hReadFinishedEvent = CreateEvent(NULL, TRUE, TRUE, NULL);
|
||||
OVERLAPPED m_overlappedData;
|
||||
memset(&m_overlappedData, sizeof(OVERLAPPED), 0);
|
||||
m_overlappedData.hEvent = m_hReadFinishedEvent;
|
||||
|
||||
HANDLE phSignals[2] = { m_hReadFinishedEvent, kill_event };
|
||||
|
||||
if (!WinUsb_ReadPipe(this->usbh, 0x81, (PUCHAR)buff, sizeof(buff), (PULONG)&retcount, &m_overlappedData)) {
|
||||
// An overlapped read will return true if done, or false with an
|
||||
// error of ERROR_IO_PENDING if the transfer is still in process.
|
||||
DWORD dwError = GetLastError();
|
||||
if (dwError == ERROR_IO_PENDING) {
|
||||
dwError = WaitForMultipleObjects(kill_event ? 2 : 1, phSignals, FALSE, timeoutms);
|
||||
|
||||
// Check if packet, timeout (nope), or break
|
||||
if (dwError == WAIT_OBJECT_0) {
|
||||
// Signal came from our usb object. Read the returned data.
|
||||
if (!GetOverlappedResult(this->usbh, &m_overlappedData, (PULONG)&retcount, FALSE)) {
|
||||
// TODO: handle other error cases better.
|
||||
dwError = GetLastError();
|
||||
printf("Got overlap error %d\n", dwError);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
} else {
|
||||
WinUsb_AbortPipe(this->usbh, 0x81);
|
||||
|
||||
// Return FALSE to show that the optional signal
|
||||
// was set instead of the wait breaking from a
|
||||
// message or recoverable error.
|
||||
if (dwError == (WAIT_OBJECT_0 + 1)) {
|
||||
return FALSE;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
} else { // ERROR_BAD_COMMAND happens when device is unplugged.
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
parse_can_recv(msg_buff, buff, retcount);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
std::vector<PANDA_CAN_MSG> Panda::can_recv() {
|
||||
std::vector<PANDA_CAN_MSG> msg_recv;
|
||||
int retcount;
|
||||
char buff[sizeof(PANDA_CAN_MSG_INTERNAL) * 4];
|
||||
|
||||
if (this->bulk_read(0x81, buff, sizeof(buff), (PULONG)&retcount, 0) == FALSE)
|
||||
return msg_recv;
|
||||
|
||||
parse_can_recv(msg_recv, buff, retcount);
|
||||
|
||||
return msg_recv;
|
||||
}
|
||||
|
||||
bool Panda::can_clear(PANDA_CAN_PORT_CLEAR bus) {
|
||||
/*Clears all messages from the specified internal CAN ringbuffer as though it were drained.
|
||||
bus(int) : can bus number to clear a tx queue, or 0xFFFF to clear the global can rx queue.*/
|
||||
return this->control_transfer(REQUEST_OUT, 0xf1, bus, 0, NULL, 0, 0) != -1;
|
||||
}
|
||||
|
||||
std::string Panda::serial_read(PANDA_SERIAL_PORT port_number) {
|
||||
std::string result;
|
||||
char buff[0x40];
|
||||
while (TRUE) {
|
||||
int retlen = this->control_transfer(REQUEST_IN, 0xe0, port_number, 0, &buff, 0x40, 0);
|
||||
if (retlen <= 0)
|
||||
break;
|
||||
result += std::string(buff, retlen);
|
||||
if (retlen < 0x40) break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
int Panda::serial_write(PANDA_SERIAL_PORT port_number, const void* buff, uint16_t len) {
|
||||
std::string dat;
|
||||
dat += port_number;
|
||||
dat += std::string((char*)buff, len);
|
||||
int retcount;
|
||||
if (this->bulk_write(2, dat.c_str(), len+1, (PULONG)&retcount, 0) == FALSE) return -1;
|
||||
return retcount;
|
||||
}
|
||||
|
||||
bool Panda::serial_clear(PANDA_SERIAL_PORT port_number) {
|
||||
return this->control_transfer(REQUEST_OUT, 0xf2, port_number, 0, NULL, 0, 0) != -1;
|
||||
}
|
|
@ -0,0 +1,214 @@
|
|||
#pragma once
|
||||
|
||||
// The following ifdef block is the standard way of creating macros which make exporting
|
||||
// from a DLL simpler. All files within this DLL are compiled with the PANDA_EXPORTS
|
||||
// symbol defined on the command line. This symbol should not be defined on any project
|
||||
// that uses this DLL. This way any other project whose source files include this file see
|
||||
// PANDA_API functions as being imported from a DLL, whereas this DLL sees symbols
|
||||
// defined with this macro as being exported.
|
||||
#ifdef PANDA_EXPORTS
|
||||
#define PANDA_API __declspec(dllexport)
|
||||
#else
|
||||
#define PANDA_API __declspec(dllimport)
|
||||
#endif
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
#include <chrono>
|
||||
|
||||
#include <windows.h>
|
||||
#include <winusb.h>
|
||||
|
||||
#if defined(UNICODE)
|
||||
#define _tcout std::wcout
|
||||
#define tstring std::wstring
|
||||
#else
|
||||
#define _tcout std::cout
|
||||
#define tstring std::string
|
||||
#endif
|
||||
|
||||
#define LIN_MSG_MAX_LEN 10
|
||||
|
||||
//template class __declspec(dllexport) std::basic_string<char>;
|
||||
|
||||
namespace panda {
|
||||
typedef enum _PANDA_SAFETY_MODE : uint16_t {
|
||||
SAFETY_NOOUTPUT = 0,
|
||||
SAFETY_HONDA = 1,
|
||||
SAFETY_ALLOUTPUT = 0x1337,
|
||||
} PANDA_SAFETY_MODE;
|
||||
|
||||
typedef enum _PANDA_SERIAL_PORT : uint8_t {
|
||||
SERIAL_DEBUG = 0,
|
||||
SERIAL_ESP = 1,
|
||||
SERIAL_LIN1 = 2,
|
||||
SERIAL_LIN2 = 3,
|
||||
} PANDA_SERIAL_PORT;
|
||||
|
||||
typedef enum _PANDA_SERIAL_PORT_PARITY : uint8_t {
|
||||
PANDA_PARITY_OFF = 0,
|
||||
PANDA_PARITY_EVEN = 1,
|
||||
PANDA_PARITY_ODD = 2,
|
||||
} PANDA_SERIAL_PORT_PARITY;
|
||||
|
||||
typedef enum _PANDA_CAN_PORT : uint8_t {
|
||||
PANDA_CAN1 = 0,
|
||||
PANDA_CAN2 = 1,
|
||||
PANDA_CAN3 = 2,
|
||||
PANDA_CAN_UNK = 0xFF,
|
||||
} PANDA_CAN_PORT;
|
||||
|
||||
typedef enum _PANDA_CAN_PORT_CLEAR : uint16_t {
|
||||
PANDA_CAN1_TX = 0,
|
||||
PANDA_CAN2_TX = 1,
|
||||
PANDA_CAN3_TX = 2,
|
||||
PANDA_CAN_RX = 0xFFFF,
|
||||
} PANDA_CAN_PORT_CLEAR;
|
||||
|
||||
typedef enum _PANDA_GMLAN_HOST_PORT : uint8_t {
|
||||
PANDA_GMLAN_CLEAR = 0,
|
||||
PANDA_GMLAN_CAN2 = 1,
|
||||
PANDA_GMLAN_CAN3 = 2,
|
||||
} PANDA_GMLAN_HOST_PORT;
|
||||
|
||||
#pragma pack(1)
|
||||
typedef struct _PANDA_HEALTH {
|
||||
uint32_t voltage;
|
||||
uint32_t current;
|
||||
uint8_t started;
|
||||
uint8_t controls_allowed;
|
||||
uint8_t gas_interceptor_detected;
|
||||
uint8_t started_signal_detected;
|
||||
uint8_t started_alt;
|
||||
} PANDA_HEALTH, *PPANDA_HEALTH;
|
||||
|
||||
typedef struct _PANDA_CAN_MSG {
|
||||
uint32_t addr;
|
||||
unsigned long long recv_time; //In microseconds since device initialization
|
||||
std::chrono::time_point<std::chrono::steady_clock> recv_time_point;
|
||||
uint8_t dat[8];
|
||||
uint8_t len;
|
||||
PANDA_CAN_PORT bus;
|
||||
bool is_receipt;
|
||||
bool addr_29b;
|
||||
} PANDA_CAN_MSG;
|
||||
|
||||
//Copied from https://stackoverflow.com/a/31488113
|
||||
class Timer
|
||||
{
|
||||
using clock = std::chrono::steady_clock;
|
||||
using time_point_type = std::chrono::time_point < clock, std::chrono::microseconds >;
|
||||
public:
|
||||
Timer() {
|
||||
start = std::chrono::time_point_cast<std::chrono::microseconds>(clock::now());
|
||||
}
|
||||
|
||||
// gets the time elapsed from construction.
|
||||
unsigned long long /*microseconds*/ Timer::getTimePassedUS() {
|
||||
// get the new time
|
||||
auto end = std::chrono::time_point_cast<std::chrono::microseconds>(clock::now());
|
||||
|
||||
// return the difference of the times
|
||||
return (end - start).count();
|
||||
}
|
||||
|
||||
// gets the time elapsed from construction.
|
||||
unsigned long long /*milliseconds*/ Timer::getTimePassedMS() {
|
||||
// get the new time
|
||||
auto end = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
|
||||
|
||||
// return the difference of the times
|
||||
auto startms = std::chrono::time_point_cast<std::chrono::milliseconds>(start);
|
||||
return (end - startms).count();
|
||||
}
|
||||
private:
|
||||
time_point_type start;
|
||||
};
|
||||
|
||||
// This class is exported from the panda.dll
|
||||
class PANDA_API Panda {
|
||||
public:
|
||||
static std::vector<std::string> listAvailablePandas();
|
||||
static std::unique_ptr<Panda> openPanda(std::string sn);
|
||||
|
||||
~Panda();
|
||||
|
||||
std::string get_usb_sn();
|
||||
bool set_alt_setting(UCHAR alt_setting);
|
||||
UCHAR get_current_alt_setting();
|
||||
|
||||
PANDA_HEALTH get_health();
|
||||
bool enter_bootloader();
|
||||
std::string get_version();
|
||||
std::string get_serial();
|
||||
std::string get_secret();
|
||||
|
||||
bool set_usb_power(bool on);
|
||||
bool set_esp_power(bool on);
|
||||
bool esp_reset(uint16_t bootmode);
|
||||
bool set_safety_mode(PANDA_SAFETY_MODE mode);
|
||||
bool set_can_forwarding(PANDA_CAN_PORT from_bus, PANDA_CAN_PORT to_bus);
|
||||
bool set_gmlan(PANDA_GMLAN_HOST_PORT bus);
|
||||
bool set_can_loopback(bool enable);
|
||||
bool set_can_speed_cbps(PANDA_CAN_PORT bus, uint16_t speed);
|
||||
bool set_can_speed_kbps(PANDA_CAN_PORT bus, uint16_t speed);
|
||||
bool set_uart_baud(PANDA_SERIAL_PORT uart, uint32_t rate);
|
||||
bool set_uart_parity(PANDA_SERIAL_PORT uart, PANDA_SERIAL_PORT_PARITY parity);
|
||||
|
||||
bool can_send_many(const std::vector<PANDA_CAN_MSG>& can_msgs);
|
||||
bool can_send(uint32_t addr, bool addr_29b, const uint8_t *dat, uint8_t len, PANDA_CAN_PORT bus);
|
||||
void parse_can_recv(std::vector<PANDA_CAN_MSG>& msg_recv, char *buff, int retcount);
|
||||
bool can_recv_async(HANDLE kill_event, std::vector<PANDA_CAN_MSG>& msg_buff, DWORD timeoutms = INFINITE);
|
||||
std::vector<PANDA_CAN_MSG> can_recv();
|
||||
bool can_clear(PANDA_CAN_PORT_CLEAR bus);
|
||||
|
||||
std::string serial_read(PANDA_SERIAL_PORT port_number);
|
||||
int serial_write(PANDA_SERIAL_PORT port_number, const void* buff, uint16_t len);
|
||||
bool serial_clear(PANDA_SERIAL_PORT port_number);
|
||||
private:
|
||||
Panda(
|
||||
WINUSB_INTERFACE_HANDLE WinusbHandle,
|
||||
HANDLE DeviceHandle,
|
||||
tstring devPath_,
|
||||
std::string sn_
|
||||
);
|
||||
|
||||
int control_transfer(
|
||||
uint8_t bmRequestType,
|
||||
uint8_t bRequest,
|
||||
uint16_t wValue,
|
||||
uint16_t wIndex,
|
||||
void * data,
|
||||
uint16_t wLength,
|
||||
unsigned int timeout
|
||||
);
|
||||
|
||||
int bulk_write(
|
||||
UCHAR endpoint,
|
||||
const void * buff,
|
||||
ULONG length,
|
||||
PULONG transferred,
|
||||
ULONG timeout
|
||||
);
|
||||
|
||||
int Panda::bulk_read(
|
||||
UCHAR endpoint,
|
||||
void * buff,
|
||||
ULONG buff_size,
|
||||
PULONG transferred,
|
||||
ULONG timeout
|
||||
);
|
||||
|
||||
WINUSB_INTERFACE_HANDLE usbh;
|
||||
HANDLE devh;
|
||||
tstring devPath;
|
||||
std::string sn;
|
||||
bool loopback;
|
||||
|
||||
Timer runningTime;
|
||||
};
|
||||
|
||||
}
|
After Width: | Height: | Size: 95 KiB |
|
@ -0,0 +1,193 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Debug|x64">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|x64">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>x64</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{5528AEFB-638D-49AF-B9D4-965154E7D531}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>panda</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PANDA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<TreatWarningAsError>false</TreatWarningAsError>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);winusb.lib;setupapi.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>_DEBUG;_WINDOWS;_USRDLL;PANDA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);winusb.lib;setupapi.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PANDA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);winusb.lib;setupapi.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>NDEBUG;_WINDOWS;_USRDLL;PANDA_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);winusb.lib;setupapi.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="device.h" />
|
||||
<ClInclude Include="panda.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="device.cpp" />
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|x64'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="panda.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|x64'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="panda.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="panda.ico" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,58 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="panda.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="device.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="panda.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="device.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="panda.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="panda.ico">
|
||||
<Filter>Resource Files</Filter>
|
||||
</Image>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// panda.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,19 @@
|
|||
// stdafx.h : include file for standard system include files,
|
||||
// or project specific include files that are used frequently, but
|
||||
// are changed infrequently
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#ifndef WIN32_LEAN_AND_MEAN
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
#endif
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
|
||||
#include <tchar.h>
|
||||
#include <strsafe.h>
|
||||
#include <winusb.h>
|
||||
#include <usb.h>
|
|
@ -0,0 +1,13 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <WinSDKVer.h>
|
||||
|
||||
#define WINVER _WIN32_WINNT_WIN7
|
||||
#define _WIN32_WINNT _WIN32_WINNT_WIN7
|
||||
|
||||
#include <SDKDDKVer.h>
|
|
@ -0,0 +1,87 @@
|
|||
#include "stdafx.h"
|
||||
#include "Loader4.h"
|
||||
#include "pandaJ2534DLL/J2534_v0404.h"
|
||||
#include "panda/panda.h"
|
||||
#include "Timer.h"
|
||||
#include "ECUsim DLL\ECUsim.h"
|
||||
#include "TestHelpers.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
namespace pandaWCUsimTest
|
||||
{
|
||||
|
||||
TEST_CLASS(ECUsimTests)
|
||||
{
|
||||
public:
|
||||
|
||||
TEST_METHOD(ECUsim_ISO15765_SingleFrameTx_29bStandardAddrPad500k)
|
||||
{
|
||||
ECUsim sim("", 500000);
|
||||
auto p = getPanda(500);
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x02\x01\x00", 3, panda::PANDA_CAN1);
|
||||
auto msg_recv = panda_recv_loop(p, 2);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x02\x01\x00", 3), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x06\x41\x00\xff\xff\xff\xfe\x00", 8), LINE_INFO());
|
||||
}
|
||||
|
||||
TEST_METHOD(ECUsim_ISO15765_SingleFrameTx_29bStandardAddrPad250k)
|
||||
{
|
||||
ECUsim sim("", 250000);
|
||||
auto p = getPanda(250);
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x02\x01\x00", 3, panda::PANDA_CAN1);
|
||||
auto msg_recv = panda_recv_loop(p, 2);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x02\x01\x00", 3), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x06""\x41\x00""\xff\xff\xff\xfe""\x00", 8), LINE_INFO());
|
||||
}
|
||||
|
||||
TEST_METHOD(ECUsim_ISO15765_SingleFrameTx_29bExtAddrPad500k)
|
||||
{
|
||||
ECUsim sim("", 500000, TRUE);
|
||||
auto p = getPanda(500);
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x13""\x02\x01\x00", 4, panda::PANDA_CAN1);
|
||||
auto msg_recv = panda_recv_loop(p, 2);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x13""\x02\x01\x00", 4), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x06""\x41\x00""\xff\xff\xff\xfe", 8), LINE_INFO());
|
||||
}
|
||||
|
||||
TEST_METHOD(ECUsim_ISO15765_MultiFrameTx_29bStandardAddrPad500k)
|
||||
{
|
||||
ECUsim sim("", 500000);
|
||||
auto p = getPanda(500);
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x02\x09\x02", 3, panda::PANDA_CAN1);
|
||||
auto msg_recv = panda_recv_loop(p, 2);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x02\x09\x02", 3), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x10\x14""\x49\x02\x01""1D4", 8), LINE_INFO());
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x30\x00\x00", 3, panda::PANDA_CAN1);
|
||||
msg_recv = panda_recv_loop(p, 3);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x30\x0\x0", 3), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x21""GP00R55", 8), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[2], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x22""B123456", 8), LINE_INFO());
|
||||
}
|
||||
|
||||
TEST_METHOD(ECUsim_ISO15765_MultiFrameTx_29bExtAddrPad500k)
|
||||
{
|
||||
ECUsim sim("", 500000, TRUE);
|
||||
auto p = getPanda(500);
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x13""\x02\x09\x02", 4, panda::PANDA_CAN1);
|
||||
auto msg_recv = panda_recv_loop(p, 2);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x13""\x02\x09\x02", 4), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x10\x14""\x49\x02\x01""1D", 8), LINE_INFO());
|
||||
|
||||
p->can_send(0x18daeff1, TRUE, (const uint8_t*)"\x13""\x30\x00\x00", 4, panda::PANDA_CAN1);
|
||||
msg_recv = panda_recv_loop(p, 4);
|
||||
check_panda_can_msg(msg_recv[0], 0, 0x18daeff1, TRUE, TRUE, std::string("\x13""\x30\x0\x0", 4), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[1], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x21""4GP00R", 8), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[2], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x22""55B123", 8), LINE_INFO());
|
||||
check_panda_can_msg(msg_recv[3], 0, 0x18daf1ef, TRUE, FALSE, std::string("\x13""\x23""456", 5), LINE_INFO());
|
||||
}
|
||||
};
|
||||
|
||||
}
|
|
@ -0,0 +1,240 @@
|
|||
// Loader4.cpp
|
||||
// (c) 2005 National Control Systems, Inc.
|
||||
// Portions (c) 2004 Drew Technologies, Inc.
|
||||
// Dynamic J2534 v04.04 dll loader for VB
|
||||
|
||||
// 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 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, write to:
|
||||
// the Free Software Foundation, Inc.
|
||||
// 51 Franklin Street, Fifth Floor
|
||||
// Boston, MA 02110-1301, USA
|
||||
|
||||
// National Control Systems, Inc.
|
||||
// 10737 Hamburg Rd
|
||||
// Hamburg, MI 48139
|
||||
// 810-231-2901
|
||||
|
||||
// Drew Technologies, Inc.
|
||||
// 7012 E.M -36, Suite 3B
|
||||
// Whitmore Lake, MI 48189
|
||||
// 810-231-3171
|
||||
|
||||
#define STRICT
|
||||
#include "stdafx.h"
|
||||
#include <windows.h>
|
||||
#include "Loader4.h"
|
||||
|
||||
PTOPEN LocalOpen;
|
||||
PTCLOSE LocalClose;
|
||||
PTCONNECT LocalConnect;
|
||||
PTDISCONNECT LocalDisconnect;
|
||||
PTREADMSGS LocalReadMsgs;
|
||||
PTWRITEMSGS LocalWriteMsgs;
|
||||
PTSTARTPERIODICMSG LocalStartPeriodicMsg;
|
||||
PTSTOPPERIODICMSG LocalStopPeriodicMsg;
|
||||
PTSTARTMSGFILTER LocalStartMsgFilter;
|
||||
PTSTOPMSGFILTER LocalStopMsgFilter;
|
||||
PTSETPROGRAMMINGVOLTAGE LocalSetProgrammingVoltage;
|
||||
PTREADVERSION LocalReadVersion;
|
||||
PTGETLASTERROR LocalGetLastError;
|
||||
PTIOCTL LocalIoctl;
|
||||
|
||||
HINSTANCE hDLL = NULL;
|
||||
//BOOL bIsCorrectVersion = FALSE;
|
||||
|
||||
BOOL WINAPI DllMain(HINSTANCE hInstA, DWORD dwReason, LPVOID lpvReserved)
|
||||
{
|
||||
switch (dwReason) {
|
||||
case DLL_PROCESS_ATTACH:
|
||||
// The DLL is being mapped into the process's address space
|
||||
|
||||
case DLL_THREAD_ATTACH:
|
||||
// A thread is being created
|
||||
break;
|
||||
|
||||
case DLL_THREAD_DETACH:
|
||||
// A thread is exiting cleanly
|
||||
break;
|
||||
|
||||
case DLL_PROCESS_DETACH:
|
||||
// The DLL is being unmapped from the process's address space
|
||||
break;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
|
||||
long WINAPI LoadJ2534Dll(char *sLib)
|
||||
{
|
||||
long lFuncList = 0;
|
||||
|
||||
if (hDLL != NULL) UnloadJ2534Dll();
|
||||
hDLL = LoadLibraryA (sLib);
|
||||
if (hDLL == NULL) return ERR_NO_DLL;
|
||||
|
||||
LocalOpen = (PTOPEN)(GetProcAddress(hDLL, "PassThruOpen"));
|
||||
if (LocalOpen == NULL) lFuncList = lFuncList | ERR_NO_PTOPEN;
|
||||
|
||||
LocalClose = (PTCLOSE)(GetProcAddress(hDLL, "PassThruClose"));
|
||||
if (LocalClose == NULL) lFuncList = lFuncList | ERR_NO_PTCLOSE;
|
||||
|
||||
LocalConnect = (PTCONNECT)(GetProcAddress(hDLL,"PassThruConnect"));
|
||||
if (LocalConnect == NULL) lFuncList = lFuncList | ERR_NO_PTCONNECT;
|
||||
|
||||
LocalDisconnect = (PTDISCONNECT)(GetProcAddress(hDLL,"PassThruDisconnect"));
|
||||
if (LocalDisconnect == NULL) lFuncList = lFuncList | ERR_NO_PTDISCONNECT;
|
||||
|
||||
LocalReadMsgs = (PTREADMSGS)(GetProcAddress(hDLL,"PassThruReadMsgs"));
|
||||
if (LocalReadMsgs == NULL) lFuncList = lFuncList | ERR_NO_PTREADMSGS;
|
||||
|
||||
LocalWriteMsgs = (PTWRITEMSGS)(GetProcAddress(hDLL,"PassThruWriteMsgs"));
|
||||
if (LocalWriteMsgs == NULL) lFuncList = lFuncList | ERR_NO_PTWRITEMSGS;
|
||||
|
||||
LocalStartPeriodicMsg = (PTSTARTPERIODICMSG)(GetProcAddress(hDLL,"PassThruStartPeriodicMsg"));
|
||||
if (LocalStartPeriodicMsg == NULL) lFuncList = lFuncList | ERR_NO_PTSTARTPERIODICMSG;
|
||||
|
||||
LocalStopPeriodicMsg = (PTSTOPPERIODICMSG)(GetProcAddress(hDLL,"PassThruStopPeriodicMsg"));
|
||||
if (LocalStopPeriodicMsg == NULL) lFuncList = lFuncList | ERR_NO_PTSTOPPERIODICMSG;
|
||||
|
||||
LocalStartMsgFilter = (PTSTARTMSGFILTER)(GetProcAddress(hDLL,"PassThruStartMsgFilter"));
|
||||
if (LocalStartPeriodicMsg == NULL) lFuncList = lFuncList | ERR_NO_PTSTARTMSGFILTER;
|
||||
|
||||
LocalStopMsgFilter = (PTSTOPMSGFILTER)(GetProcAddress(hDLL,"PassThruStopMsgFilter"));
|
||||
if (LocalStopMsgFilter == NULL) lFuncList = lFuncList | ERR_NO_PTSTOPMSGFILTER;
|
||||
|
||||
LocalSetProgrammingVoltage = (PTSETPROGRAMMINGVOLTAGE)(GetProcAddress(hDLL,"PassThruSetProgrammingVoltage"));
|
||||
if (LocalSetProgrammingVoltage == NULL) lFuncList = lFuncList | ERR_NO_PTSETPROGRAMMINGVOLTAGE;
|
||||
|
||||
LocalReadVersion = (PTREADVERSION)(GetProcAddress(hDLL,"PassThruReadVersion"));
|
||||
if (LocalReadVersion == NULL) lFuncList = lFuncList | ERR_NO_PTREADVERSION;
|
||||
|
||||
LocalGetLastError = (PTGETLASTERROR)(GetProcAddress(hDLL,"PassThruGetLastError"));
|
||||
if (LocalGetLastError == NULL) lFuncList = lFuncList | ERR_NO_PTGETLASTERROR;
|
||||
|
||||
LocalIoctl = (PTIOCTL)(GetProcAddress(hDLL,"PassThruIoctl"));
|
||||
if (LocalIoctl == NULL) lFuncList = lFuncList | ERR_NO_PTIOCTL;
|
||||
|
||||
if (lFuncList == ERR_NO_FUNCTIONS) return ERR_WRONG_DLL_VER;
|
||||
|
||||
return lFuncList;
|
||||
}
|
||||
|
||||
long WINAPI UnloadJ2534Dll()
|
||||
{
|
||||
if (FreeLibrary(hDLL))
|
||||
{
|
||||
hDLL = NULL;
|
||||
LocalOpen = NULL;
|
||||
LocalClose = NULL;
|
||||
LocalConnect = NULL;
|
||||
LocalDisconnect = NULL;
|
||||
LocalReadMsgs = NULL;
|
||||
LocalWriteMsgs = NULL;
|
||||
LocalStartPeriodicMsg = NULL;
|
||||
LocalStopPeriodicMsg = NULL;
|
||||
LocalStartMsgFilter = NULL;
|
||||
LocalStopMsgFilter = NULL;
|
||||
LocalSetProgrammingVoltage = NULL;
|
||||
LocalReadVersion = NULL;
|
||||
LocalGetLastError = NULL;
|
||||
LocalIoctl = NULL;
|
||||
return 0;
|
||||
}
|
||||
return ERR_NO_DLL;
|
||||
}
|
||||
|
||||
long WINAPI PassThruOpen(void *pName, unsigned long *pDeviceID)
|
||||
{
|
||||
if (LocalOpen == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalOpen(pName, pDeviceID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruClose(unsigned long DeviceID)
|
||||
{
|
||||
if (LocalOpen == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalClose(DeviceID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long Baudrate, unsigned long *pChannelID)
|
||||
{
|
||||
if (LocalConnect == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalConnect(DeviceID, ProtocolID, Flags, Baudrate, pChannelID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruDisconnect(unsigned long ChannelID)
|
||||
{
|
||||
if (LocalDisconnect == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalDisconnect(ChannelID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruReadMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout)
|
||||
{
|
||||
if (LocalReadMsgs == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalReadMsgs(ChannelID, pMsg, pNumMsgs, Timeout);
|
||||
}
|
||||
|
||||
long WINAPI PassThruWriteMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout)
|
||||
{
|
||||
if (LocalWriteMsgs == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalWriteMsgs(ChannelID, pMsg, pNumMsgs, Timeout);
|
||||
}
|
||||
|
||||
long WINAPI PassThruStartPeriodicMsg(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval)
|
||||
{
|
||||
if (LocalStartPeriodicMsg == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalStartPeriodicMsg(ChannelID, pMsg, pMsgID, TimeInterval);
|
||||
}
|
||||
|
||||
long WINAPI PassThruStopPeriodicMsg(unsigned long ChannelID, unsigned long MsgID)
|
||||
{
|
||||
if (LocalStopPeriodicMsg == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalStopPeriodicMsg(ChannelID, MsgID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruStartMsgFilter(unsigned long ChannelID, unsigned long FilterType,
|
||||
PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg, PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID)
|
||||
{
|
||||
if (LocalStartMsgFilter == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalStartMsgFilter(ChannelID, FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg, pFilterID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruStopMsgFilter(unsigned long ChannelID, unsigned long FilterID)
|
||||
{
|
||||
if (LocalStopMsgFilter == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalStopMsgFilter(ChannelID, FilterID);
|
||||
}
|
||||
|
||||
long WINAPI PassThruSetProgrammingVoltage(unsigned long DeviceID, unsigned long PinNumber, unsigned long Voltage)
|
||||
{
|
||||
if (LocalSetProgrammingVoltage == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalSetProgrammingVoltage(DeviceID, PinNumber, Voltage);
|
||||
}
|
||||
|
||||
long WINAPI PassThruReadVersion(unsigned long DeviceID, char *pFirmwareVersion, char *pDllVersion, char *pApiVersion)
|
||||
{
|
||||
if (LocalReadVersion == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalReadVersion(DeviceID, pFirmwareVersion, pDllVersion, pApiVersion);
|
||||
}
|
||||
|
||||
long WINAPI PassThruGetLastError(char *pErrorDescription)
|
||||
{
|
||||
if (LocalGetLastError == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalGetLastError(pErrorDescription);
|
||||
}
|
||||
|
||||
long WINAPI PassThruIoctl(unsigned long ChannelID, unsigned long IoctlID, void *pInput, void *pOutput)
|
||||
{
|
||||
if (LocalIoctl == NULL) return ERR_FUNC_MISSING;
|
||||
return LocalIoctl(ChannelID, IoctlID, pInput, pOutput);
|
||||
}
|
|
@ -0,0 +1,55 @@
|
|||
// Loader4.h
|
||||
// (c) 2005 National Control Systems, Inc.
|
||||
// Portions (c) 2004 Drew Technologies, Inc.
|
||||
|
||||
// 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 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, write to:
|
||||
// the Free Software Foundation, Inc.
|
||||
// 51 Franklin Street, Fifth Floor
|
||||
// Boston, MA 02110-1301, USA
|
||||
|
||||
// National Control Systems, Inc.
|
||||
// 10737 Hamburg Rd
|
||||
// Hamburg, MI 48139
|
||||
// 810-231-2901
|
||||
|
||||
// Drew Technologies, Inc.
|
||||
// 7012 E.M -36, Suite 3B
|
||||
// Whitmore Lake, MI 48189
|
||||
// 810-231-3171
|
||||
|
||||
#include "pandaJ2534DLL/J2534_v0404.h"
|
||||
|
||||
//Other Functions
|
||||
long WINAPI LoadJ2534Dll(char *);
|
||||
long WINAPI UnloadJ2534Dll();
|
||||
|
||||
// NCS Returns of any functions not found
|
||||
#define ERR_NO_PTOPEN 0x0001
|
||||
#define ERR_NO_PTCLOSE 0x0002
|
||||
#define ERR_NO_PTCONNECT 0x0004
|
||||
#define ERR_NO_PTDISCONNECT 0x0008
|
||||
#define ERR_NO_PTREADMSGS 0x0010
|
||||
#define ERR_NO_PTWRITEMSGS 0x0020
|
||||
#define ERR_NO_PTSTARTPERIODICMSG 0x0040
|
||||
#define ERR_NO_PTSTOPPERIODICMSG 0x0080
|
||||
#define ERR_NO_PTSTARTMSGFILTER 0x0100
|
||||
#define ERR_NO_PTSTOPMSGFILTER 0x0200
|
||||
#define ERR_NO_PTSETPROGRAMMINGVOLTAGE 0x0400
|
||||
#define ERR_NO_PTREADVERSION 0x0800
|
||||
#define ERR_NO_PTGETLASTERROR 0x1000
|
||||
#define ERR_NO_PTIOCTL 0x2000
|
||||
#define ERR_NO_FUNCTIONS 0x3fff
|
||||
#define ERR_NO_DLL -1
|
||||
#define ERR_WRONG_DLL_VER -2
|
||||
#define ERR_FUNC_MISSING -3
|
|
@ -0,0 +1,254 @@
|
|||
#include "stdafx.h"
|
||||
#include "TestHelpers.h"
|
||||
#include "Loader4.h"
|
||||
#include "pandaJ2534DLL/J2534_v0404.h"
|
||||
#include "panda/panda.h"
|
||||
#include "Timer.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
void write_ioctl(unsigned int chanid, unsigned int param, unsigned int val, const __LineInfo* pLineInfo) {
|
||||
SCONFIG config = { param, val };
|
||||
SCONFIG_LIST inconfig = { 1, &config };
|
||||
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, PassThruIoctl(chanid, SET_CONFIG, &inconfig, NULL), _T("Failed to set IOCTL."), pLineInfo);
|
||||
}
|
||||
|
||||
std::vector<panda::PANDA_CAN_MSG> panda_recv_loop_loose(std::unique_ptr<panda::Panda>& p, unsigned int min_num, unsigned long timeout_ms) {
|
||||
std::vector<panda::PANDA_CAN_MSG> ret_messages;
|
||||
Timer t = Timer();
|
||||
|
||||
while (t.getTimePassed() < timeout_ms) {
|
||||
Sleep(10);
|
||||
std::vector<panda::PANDA_CAN_MSG>msg_recv = p->can_recv();
|
||||
if (msg_recv.size() > 0) {
|
||||
ret_messages.insert(std::end(ret_messages), std::begin(msg_recv), std::end(msg_recv));
|
||||
}
|
||||
}
|
||||
|
||||
Assert::IsTrue(min_num <= ret_messages.size(), _T("Received too few messages."));
|
||||
return ret_messages;
|
||||
}
|
||||
|
||||
std::vector<panda::PANDA_CAN_MSG> panda_recv_loop(std::unique_ptr<panda::Panda>& p, unsigned int num_expected, unsigned long timeout_ms) {
|
||||
std::vector<panda::PANDA_CAN_MSG> ret_messages;
|
||||
Timer t = Timer();
|
||||
|
||||
while (t.getTimePassed() < timeout_ms) {
|
||||
Sleep(10);
|
||||
std::vector<panda::PANDA_CAN_MSG>msg_recv = p->can_recv();
|
||||
if (msg_recv.size() > 0) {
|
||||
ret_messages.insert(std::end(ret_messages), std::begin(msg_recv), std::end(msg_recv));
|
||||
}
|
||||
if (ret_messages.size() >= num_expected) break;
|
||||
}
|
||||
|
||||
std::ostringstream stringStream;
|
||||
|
||||
stringStream << "j2534_recv_loop Broke at " << t.getTimePassed() << " ms size is " << ret_messages.size() << std::endl;
|
||||
|
||||
if (num_expected != ret_messages.size()) {
|
||||
stringStream << "Incorrect number of messages received. Displaying the messages:" << std::endl;
|
||||
for (auto msg : ret_messages) {
|
||||
stringStream << " TS: " << msg.recv_time << "; Dat: ";
|
||||
for (int i = 0; i < msg.len; i++) stringStream << std::hex << std::setw(2) << std::setfill('0') << int(msg.dat[i] & 0xFF) << " ";
|
||||
stringStream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Logger::WriteMessage(stringStream.str().c_str());
|
||||
|
||||
Assert::AreEqual<unsigned long>(num_expected, ret_messages.size(), _T("Received wrong number of messages."));
|
||||
return ret_messages;
|
||||
}
|
||||
|
||||
void check_panda_can_msg(panda::PANDA_CAN_MSG& msgin, uint8_t bus, unsigned long addr, bool addr_29b,
|
||||
bool is_receipt, std::string dat, const __LineInfo* pLineInfo) {
|
||||
Assert::AreEqual<uint8_t>(bus, msgin.bus, _T("Wrong msg bus"), pLineInfo);
|
||||
Assert::AreEqual<unsigned long>(addr, msgin.addr, _T("Wrong msg addr"), pLineInfo);
|
||||
Assert::AreEqual<bool>(addr_29b, msgin.addr_29b, _T("Wrong msg 29b flag"), pLineInfo);
|
||||
Assert::AreEqual<bool>(is_receipt, msgin.is_receipt, _T("Wrong msg receipt flag"), pLineInfo);
|
||||
|
||||
std::ostringstream logmsg;
|
||||
logmsg << "Expected Hex (";
|
||||
for (int i = 0; i < dat.size(); i++) logmsg << std::hex << std::setw(2) << std::setfill('0') << int(dat[i] & 0xFF) << " ";
|
||||
logmsg << "); Actual Hex (";
|
||||
for (int i = 0; i < msgin.len; i++) logmsg << std::hex << std::setw(2) << std::setfill('0') << int(((char*)msgin.dat)[i] & 0xFF) << " ";
|
||||
logmsg << ")";
|
||||
Logger::WriteMessage(logmsg.str().c_str());
|
||||
|
||||
Assert::AreEqual<size_t>(dat.size(), msgin.len, _T("Wrong msg len"), pLineInfo);
|
||||
Assert::AreEqual<std::string>(dat, std::string((char*)msgin.dat, msgin.len), _T("Wrong msg payload"), pLineInfo);
|
||||
}
|
||||
|
||||
unsigned long J2534_start_periodic_msg_checked(unsigned long chanid, unsigned long ProtocolID, unsigned long TxFlags, unsigned long DataSize,
|
||||
unsigned long ExtraDataIndex, const char * Data, unsigned long TimeInterval, const __LineInfo * pLineInfo) {
|
||||
PASSTHRU_MSG msg = { ProtocolID, 0, TxFlags, 0, DataSize, ExtraDataIndex };
|
||||
memcpy_s(msg.Data, 4128, Data, DataSize);
|
||||
unsigned long msgID;
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, J2534_start_periodic_msg(chanid, ProtocolID, TxFlags, DataSize,
|
||||
ExtraDataIndex, Data, TimeInterval, &msgID, pLineInfo), _T("Failed to start Periodic Message."), pLineInfo);
|
||||
return msgID;
|
||||
}
|
||||
|
||||
unsigned long J2534_start_periodic_msg(unsigned long chanid, unsigned long ProtocolID, unsigned long TxFlags, unsigned long DataSize,
|
||||
unsigned long ExtraDataIndex, const char * Data, unsigned long TimeInterval, unsigned long* msgID, const __LineInfo * pLineInfo) {
|
||||
PASSTHRU_MSG msg = { ProtocolID, 0, TxFlags, 0, DataSize, ExtraDataIndex };
|
||||
memcpy_s(msg.Data, 4128, Data, DataSize);
|
||||
return PassThruStartPeriodicMsg(chanid, &msg, msgID, TimeInterval);
|
||||
}
|
||||
|
||||
void J2534_send_msg_checked(unsigned long chanid, unsigned long ProtocolID, unsigned long RxStatus, unsigned long TxFlags,
|
||||
unsigned long Timestamp, unsigned long DataSize, unsigned long ExtraDataIndex, const char* Data, const __LineInfo* pLineInfo) {
|
||||
|
||||
PASSTHRU_MSG msg = { ProtocolID, RxStatus, TxFlags, Timestamp, DataSize, ExtraDataIndex };
|
||||
memcpy_s(msg.Data, 4128, Data, DataSize);
|
||||
unsigned long msgcount = 1;
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, PassThruWriteMsgs(chanid, &msg, &msgcount, 0), _T("Failed to write message."), pLineInfo);
|
||||
Assert::AreEqual<unsigned long>(1, msgcount, _T("Wrong message count after tx."), pLineInfo);
|
||||
}
|
||||
|
||||
long J2534_send_msg(unsigned long chanid, unsigned long ProtocolID, unsigned long RxStatus, unsigned long TxFlags,
|
||||
unsigned long Timestamp, unsigned long DataSize, unsigned long ExtraDataIndex, const char* Data) {
|
||||
|
||||
PASSTHRU_MSG msg = { ProtocolID, RxStatus, TxFlags, Timestamp, DataSize, ExtraDataIndex };
|
||||
memcpy_s(msg.Data, 4128, Data, DataSize);
|
||||
unsigned long msgcount = 1;
|
||||
return PassThruWriteMsgs(chanid, &msg, &msgcount, 0);
|
||||
}
|
||||
|
||||
//Allow more messages to come in than the min.
|
||||
std::vector<PASSTHRU_MSG> j2534_recv_loop_loose(unsigned int chanid, unsigned int min_num, unsigned long timeout_ms) {
|
||||
std::vector<PASSTHRU_MSG> ret_messages;
|
||||
PASSTHRU_MSG recvbuff[4] = {};
|
||||
Timer t = Timer();
|
||||
|
||||
while (t.getTimePassed() < timeout_ms) {
|
||||
unsigned long msgcount = 4;
|
||||
unsigned int res = PassThruReadMsgs(chanid, recvbuff, &msgcount, 0);
|
||||
if (res == ERR_BUFFER_EMPTY) continue;
|
||||
Assert::IsFalse(msgcount > 4, _T("PassThruReadMsgs returned more data than the buffer could hold."));
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, res, _T("Failed to read message."));
|
||||
if (msgcount > 0) {
|
||||
for (unsigned int i = 0; i < msgcount; i++) {
|
||||
ret_messages.push_back(recvbuff[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Assert::IsTrue(min_num <= ret_messages.size(), _T("Received too few messages."));
|
||||
return ret_messages;
|
||||
}
|
||||
|
||||
std::vector<PASSTHRU_MSG> j2534_recv_loop(unsigned int chanid, unsigned int num_expected, unsigned long timeout_ms) {
|
||||
std::vector<PASSTHRU_MSG> ret_messages;
|
||||
PASSTHRU_MSG recvbuff[4] = {};
|
||||
Timer t = Timer();
|
||||
|
||||
while (t.getTimePassed() < timeout_ms) {
|
||||
unsigned long msgcount = 4;
|
||||
unsigned int res = PassThruReadMsgs(chanid, recvbuff, &msgcount, 0);
|
||||
if (res == ERR_BUFFER_EMPTY) continue;
|
||||
Assert::IsFalse(msgcount > 4, _T("PassThruReadMsgs returned more data than the buffer could hold."));
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, res, _T("Failed to read message."));
|
||||
if (msgcount > 0) {
|
||||
for (unsigned int i = 0; i < msgcount; i++) {
|
||||
ret_messages.push_back(recvbuff[i]);
|
||||
}
|
||||
}
|
||||
if (ret_messages.size() >= num_expected) break;
|
||||
}
|
||||
|
||||
std::ostringstream stringStream;
|
||||
stringStream << "j2534_recv_loop Broke at " << t.getTimePassed() << " ms size is " << ret_messages.size() << std::endl;
|
||||
|
||||
if (num_expected != ret_messages.size()) {
|
||||
stringStream << "Incorrect number of messages received. Displaying the messages:" << std::endl;
|
||||
for (auto msg : ret_messages) {
|
||||
stringStream << " TS: " << msg.Timestamp << "; Dat: ";
|
||||
for (int i = 0; i < msg.DataSize; i++) stringStream << std::hex << std::setw(2) << std::setfill('0') << int(msg.Data[i] & 0xFF) << " ";
|
||||
stringStream << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
Logger::WriteMessage(stringStream.str().c_str());
|
||||
|
||||
Assert::AreEqual<unsigned long>(num_expected, ret_messages.size(), _T("Received wrong number of messages."));
|
||||
return ret_messages;
|
||||
}
|
||||
|
||||
void check_J2534_can_msg(PASSTHRU_MSG& msgin, unsigned long ProtocolID, unsigned long RxStatus, unsigned long TxFlags,
|
||||
unsigned long DataSize, unsigned long ExtraDataIndex, const char* Data, const __LineInfo* pLineInfo) {
|
||||
Assert::AreEqual<size_t>(DataSize, msgin.DataSize, _T("Wrong msg len"), pLineInfo);
|
||||
|
||||
std::ostringstream logmsg;
|
||||
logmsg << "Expected Hex (";
|
||||
for (int i = 0; i < DataSize; i++) logmsg << std::hex << std::setw(2) << std::setfill('0') << int(Data[i] & 0xFF) << " ";
|
||||
logmsg << "); Actual Hex (";
|
||||
for (int i = 0; i < msgin.DataSize; i++) logmsg << std::hex << std::setw(2) << std::setfill('0') << int(((char*)msgin.Data)[i] & 0xFF) << " ";
|
||||
logmsg << ")";
|
||||
Logger::WriteMessage(logmsg.str().c_str());
|
||||
Assert::AreEqual<std::string>(std::string(Data, DataSize), std::string((char*)msgin.Data, msgin.DataSize), _T("Wrong msg payload"), pLineInfo);
|
||||
|
||||
Assert::AreEqual<unsigned long>(ProtocolID, msgin.ProtocolID, _T("Wrong msg protocol"), pLineInfo);
|
||||
Assert::AreEqual<unsigned long>(RxStatus, msgin.RxStatus, _T("Wrong msg receipt rxstatus"), pLineInfo);
|
||||
Assert::AreEqual<unsigned long>(TxFlags, msgin.TxFlags, _T("Wrong msg receipt txflag"), pLineInfo);
|
||||
Assert::AreEqual<unsigned long>(ExtraDataIndex, msgin.ExtraDataIndex, _T("Wrong msg ExtraDataIndex"), pLineInfo);
|
||||
}
|
||||
|
||||
unsigned long J2534_set_PASS_filter(unsigned long chanid, unsigned long ProtocolID, unsigned long tx,
|
||||
unsigned long len, char* mask, char* pattern, const __LineInfo* pLineInfo) {
|
||||
unsigned long filterid;
|
||||
PASSTHRU_MSG mask_msg = { ProtocolID, 0, tx, 0, len, 0, 0 };
|
||||
PASSTHRU_MSG pattern_msg = { ProtocolID, 0, tx, 0, len, 0, 0 };
|
||||
memcpy(mask_msg.Data, mask, len);
|
||||
memcpy(pattern_msg.Data, pattern, len);
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, PassThruStartMsgFilter(chanid, PASS_FILTER, &mask_msg, &pattern_msg, NULL, &filterid),
|
||||
_T("Failed to create filter."), pLineInfo);
|
||||
return filterid;
|
||||
}
|
||||
|
||||
unsigned long J2534_set_BLOCK_filter(unsigned long chanid, unsigned long ProtocolID, unsigned long tx,
|
||||
unsigned long len, char* mask, char* pattern, const __LineInfo* pLineInfo) {
|
||||
unsigned long filterid;
|
||||
PASSTHRU_MSG mask_msg = { ProtocolID, 0, tx, 0, len, 0, 0 };
|
||||
PASSTHRU_MSG pattern_msg = { ProtocolID, 0, tx, 0, len, 0, 0 };
|
||||
memcpy(mask_msg.Data, mask, len);
|
||||
memcpy(pattern_msg.Data, pattern, len);
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, PassThruStartMsgFilter(chanid, BLOCK_FILTER, &mask_msg, &pattern_msg, NULL, &filterid),
|
||||
_T("Failed to create filter."), pLineInfo);
|
||||
return filterid;
|
||||
}
|
||||
|
||||
unsigned long J2534_set_flowctrl_filter(unsigned long chanid, unsigned long tx,
|
||||
unsigned long len, char* mask, char* pattern, char* flow, const __LineInfo* pLineInfo) {
|
||||
unsigned long filterid;
|
||||
PASSTHRU_MSG mask_msg = { ISO15765, 0, tx, 0, len, 0, 0 };
|
||||
PASSTHRU_MSG pattern_msg = { ISO15765, 0, tx, 0, len, 0, 0 };
|
||||
PASSTHRU_MSG flow_msg = { ISO15765, 0, tx, 0, len, 0, 0 };
|
||||
memcpy(mask_msg.Data, mask, len);
|
||||
memcpy(pattern_msg.Data, pattern, len);
|
||||
memcpy(flow_msg.Data, flow, len);
|
||||
Assert::AreEqual<long>(STATUS_NOERROR, PassThruStartMsgFilter(chanid, FLOW_CONTROL_FILTER, &mask_msg, &pattern_msg, &flow_msg, &filterid),
|
||||
_T("Failed to create filter."), pLineInfo);
|
||||
return filterid;
|
||||
}
|
||||
|
||||
std::unique_ptr<panda::Panda> getPanda(unsigned long kbaud, BOOL loopback) {
|
||||
auto p = panda::Panda::openPanda("");
|
||||
Assert::IsTrue(p != nullptr, _T("Could not open raw panda device to test communication."));
|
||||
p->set_can_speed_kbps(panda::PANDA_CAN1, kbaud);
|
||||
p->set_safety_mode(panda::SAFETY_ALLOUTPUT);
|
||||
p->set_can_loopback(loopback);
|
||||
p->can_clear(panda::PANDA_CAN_RX);
|
||||
return p;
|
||||
}
|
||||
|
||||
std::vector<panda::PANDA_CAN_MSG> checked_panda_send(std::unique_ptr<panda::Panda>& p, uint32_t addr, bool is_29b,
|
||||
char* msg, uint8_t len, unsigned int num_expected, const __LineInfo* pLineInfo, unsigned long timeout_ms) {
|
||||
Assert::IsTrue(p->can_send(addr, is_29b, (const uint8_t*)msg, len, panda::PANDA_CAN1), _T("Panda send says it failed."), pLineInfo);
|
||||
auto panda_msg_recv = panda_recv_loop(p, 1 + num_expected, timeout_ms);
|
||||
check_panda_can_msg(panda_msg_recv[0], 0, addr, is_29b, TRUE, std::string(msg, len), pLineInfo);
|
||||
panda_msg_recv.erase(panda_msg_recv.begin());
|
||||
return panda_msg_recv;
|
||||
}
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
#include "pandaJ2534DLL/J2534_v0404.h"
|
||||
#include "panda/panda.h"
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
|
||||
extern void write_ioctl(unsigned int chanid, unsigned int param, unsigned int val, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern std::vector<panda::PANDA_CAN_MSG> panda_recv_loop_loose(std::unique_ptr<panda::Panda>& p, unsigned int min_num, unsigned long timeout_ms = 100);
|
||||
|
||||
extern std::vector<panda::PANDA_CAN_MSG> panda_recv_loop(std::unique_ptr<panda::Panda>& p, unsigned int num_expected, unsigned long timeout_ms = 100);
|
||||
|
||||
extern void check_panda_can_msg(panda::PANDA_CAN_MSG& msgin, uint8_t bus, unsigned long addr, bool addr_29b,
|
||||
bool is_receipt, std::string dat, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern unsigned long J2534_start_periodic_msg_checked(unsigned long chanid, unsigned long ProtocolID, unsigned long TxFlags, unsigned long DataSize,
|
||||
unsigned long ExtraDataIndex, const char * Data, unsigned long TimeInterval, const __LineInfo * pLineInfo);
|
||||
|
||||
extern unsigned long J2534_start_periodic_msg(unsigned long chanid, unsigned long ProtocolID, unsigned long TxFlags, unsigned long DataSize,
|
||||
unsigned long ExtraDataIndex, const char* Data, unsigned long TimeInterval, unsigned long* msgID, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern void J2534_send_msg_checked(unsigned long chanid, unsigned long ProtocolID, unsigned long RxStatus, unsigned long TxFlags,
|
||||
unsigned long Timestamp, unsigned long DataSize, unsigned long ExtraDataIndex, const char* Data, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern long J2534_send_msg(unsigned long chanid, unsigned long ProtocolID, unsigned long RxStatus, unsigned long TxFlags,
|
||||
unsigned long Timestamp, unsigned long DataSize, unsigned long ExtraDataIndex, const char* Data);
|
||||
|
||||
extern std::vector<PASSTHRU_MSG> j2534_recv_loop_loose(unsigned int chanid, unsigned int min_num, unsigned long timeout_ms = 100);
|
||||
|
||||
extern std::vector<PASSTHRU_MSG> j2534_recv_loop(unsigned int chanid, unsigned int num_expected, unsigned long timeout_ms = 100);
|
||||
|
||||
extern void check_J2534_can_msg(PASSTHRU_MSG& msgin, unsigned long ProtocolID, unsigned long RxStatus, unsigned long TxFlags,
|
||||
unsigned long DataSize, unsigned long ExtraDataIndex, const char* Data, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern unsigned long J2534_set_PASS_filter(unsigned long chanid, unsigned long ProtocolID, unsigned long tx,
|
||||
unsigned long len, char* mask, char* pattern, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern unsigned long J2534_set_BLOCK_filter(unsigned long chanid, unsigned long ProtocolID, unsigned long tx,
|
||||
unsigned long len, char* mask, char* pattern, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern unsigned long J2534_set_flowctrl_filter(unsigned long chanid, unsigned long tx,
|
||||
unsigned long len, char* mask, char* pattern, char* flow, const __LineInfo* pLineInfo = NULL);
|
||||
|
||||
extern std::unique_ptr<panda::Panda> getPanda(unsigned long kbaud = 500, BOOL loopback = FALSE);
|
||||
|
||||
extern std::vector<panda::PANDA_CAN_MSG> checked_panda_send(std::unique_ptr<panda::Panda>& p, uint32_t addr, bool is_29b,
|
||||
char* msg, uint8_t len, unsigned int num_expected=0, const __LineInfo* pLineInfo = NULL, unsigned long timeout_ms = 100);
|
|
@ -0,0 +1,21 @@
|
|||
#include "stdafx.h"
|
||||
#include "Timer.h"
|
||||
|
||||
|
||||
Timer::Timer()
|
||||
{
|
||||
reset();
|
||||
}
|
||||
|
||||
// gets the time elapsed from construction.
|
||||
unsigned long long /*milliseconds*/ Timer::getTimePassed(){
|
||||
// get the new time
|
||||
auto end = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
|
||||
|
||||
// return the difference of the times
|
||||
return (end - start).count();
|
||||
}
|
||||
|
||||
void Timer::reset() {
|
||||
start = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
#include <chrono>
|
||||
|
||||
//Copied from https://stackoverflow.com/a/31488113
|
||||
|
||||
class Timer
|
||||
{
|
||||
using clock = std::chrono::steady_clock;
|
||||
using time_point_type = std::chrono::time_point < clock, std::chrono::milliseconds >;
|
||||
public:
|
||||
Timer();
|
||||
|
||||
// gets the time elapsed from construction.
|
||||
unsigned long long /*milliseconds*/ getTimePassed();
|
||||
|
||||
void reset();
|
||||
|
||||
private:
|
||||
time_point_type start;
|
||||
};
|
|
@ -0,0 +1,125 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{7912F978-B48C-4C5D-8BFD-5D1E22158E47}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>pandaJ2534DLLTest</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
<ProjectName>Tests</ProjectName>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
<UseOfMfc>false</UseOfMfc>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<AdditionalIncludeDirectories>$(VCInstallDir)UnitTest\include;%(AdditionalIncludeDirectories);$(SolutionDir)</AdditionalIncludeDirectories>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<UseFullPaths>true</UseFullPaths>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<AdditionalLibraryDirectories>$(VCInstallDir)UnitTest\lib;%(AdditionalLibraryDirectories)</AdditionalLibraryDirectories>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\pandaJ2534DLL\J2534_v0404.h" />
|
||||
<ClInclude Include="..\panda\panda.h" />
|
||||
<ClInclude Include="Loader4.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="TestHelpers.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="ECUsim_tests.cpp" />
|
||||
<ClCompile Include="Loader4.cpp" />
|
||||
<ClCompile Include="panda_tests.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="j2534_tests.cpp" />
|
||||
<ClCompile Include="TestHelpers.cpp" />
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ECUsim DLL\ECUsim DLL.vcxproj">
|
||||
<Project>{96e0e646-ee76-444d-9a77-a0cd7f781deb}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\pandaJ2534DLL\pandaJ2534DLL.vcxproj">
|
||||
<Project>{a2bb18a5-f26b-48d6-bbb5-b83d64473c77}</Project>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\panda\panda.vcxproj">
|
||||
<Project>{5528aefb-638d-49af-b9d4-965154e7d531}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,63 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Loader4.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\pandaJ2534DLL\J2534_v0404.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Timer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\panda\panda.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="TestHelpers.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="j2534_tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Loader4.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Timer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="TestHelpers.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="ECUsim_tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="panda_tests.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,187 @@
|
|||
#include "stdafx.h"
|
||||
#include "panda/panda.h"
|
||||
#include "TestHelpers.h"
|
||||
|
||||
#include <tchar.h>
|
||||
|
||||
using namespace Microsoft::VisualStudio::CppUnitTestFramework;
|
||||
using namespace panda;
|
||||
|
||||
namespace pandaTestNative
|
||||
{
|
||||
TEST_CLASS(DeviceDiscovery)
|
||||
{
|
||||
public:
|
||||
|
||||
TEST_METHOD(Panda_DevDiscover_ListDevices)
|
||||
{
|
||||
auto pandas_available = Panda::listAvailablePandas();
|
||||
Assert::IsTrue(pandas_available.size() > 0, _T("No pandas were found."));
|
||||
for (auto sn : pandas_available) {
|
||||
Assert::IsTrue(sn.size() == 24, _T("panda Serial Number not 24 characters long."));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_DevDiscover_OpenFirstDevice)
|
||||
{
|
||||
auto pandas_available = Panda::listAvailablePandas();
|
||||
Assert::IsTrue(pandas_available.size() > 0, _T("No pandas were found."));
|
||||
|
||||
auto p1 = Panda::openPanda(pandas_available[0]);
|
||||
Assert::IsFalse(p1 == nullptr, _T("Could not open panda."));
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_DevDiscover_OpenDeviceNoName)
|
||||
{
|
||||
auto pandas_available = Panda::listAvailablePandas();
|
||||
Assert::IsTrue(pandas_available.size() > 0, _T("No pandas were found."));
|
||||
|
||||
auto p1 = Panda::openPanda("");
|
||||
Assert::IsFalse(p1 == nullptr, _T("Could not open panda."));
|
||||
Assert::IsTrue(p1->get_usb_sn() == pandas_available[0], _T("Could not open panda."));
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_DevDiscover_OpenDeviceUnavailable)
|
||||
{
|
||||
auto p1 = Panda::openPanda("ZZZZZZZZZZZZZZZZZZZZZZZZ");
|
||||
Assert::IsTrue(p1 == nullptr, _T("Invalid sn still worked."));
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_DevDiscover_WillNotOpenAlreadyOpenedDevice)
|
||||
{
|
||||
auto pandas_available = Panda::listAvailablePandas();
|
||||
Assert::IsTrue(pandas_available.size() > 0, _T("No pandas were found."));
|
||||
|
||||
auto p1 = Panda::openPanda(pandas_available[0]);
|
||||
Assert::IsFalse(p1 == nullptr, _T("Could not open panda."));
|
||||
|
||||
auto p2 = Panda::openPanda(pandas_available[0]);
|
||||
Assert::IsTrue(p2 == nullptr, _T("Opened an already open panda."));
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_DevDiscover_OpenedDeviceNotListed)
|
||||
{
|
||||
auto pandas_available = Panda::listAvailablePandas();
|
||||
Assert::IsTrue(pandas_available.size() > 0, _T("No pandas were found."));
|
||||
|
||||
auto p1 = Panda::openPanda(pandas_available[0]);
|
||||
Assert::IsFalse(p1 == nullptr, _T("Could not open panda."));
|
||||
|
||||
auto pandas_available2 = Panda::listAvailablePandas();
|
||||
for (auto sn : pandas_available2) {
|
||||
Assert::IsFalse(p1->get_usb_sn() == sn, _T("Opened panda appears in list of available pandas."));
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS(CANOperations)
|
||||
{
|
||||
public:
|
||||
|
||||
TEST_METHOD(Panda_CAN_Echo)
|
||||
{
|
||||
auto p0 = getPanda(500, TRUE);
|
||||
|
||||
uint32_t addr = 0xAA;
|
||||
bool is_29b = FALSE;
|
||||
uint8_t candata[8];
|
||||
|
||||
for (auto canbus : { PANDA_CAN1, PANDA_CAN2, PANDA_CAN3 }) {
|
||||
uint8_t len = (rand() % 8) + 1;
|
||||
for (size_t i = 0; i < len; i++)
|
||||
candata[i] = rand() % 256;
|
||||
|
||||
p0->can_send(addr, is_29b, candata, len, canbus);
|
||||
Sleep(10);
|
||||
|
||||
auto can_msgs = p0->can_recv();
|
||||
|
||||
Assert::AreEqual<size_t>(2, can_msgs.size(), _T("Received the wrong number of CAN messages."), LINE_INFO());
|
||||
|
||||
for (auto msg : can_msgs) {
|
||||
Assert::IsTrue(msg.addr == addr, _T("Wrong addr."));
|
||||
Assert::IsTrue(msg.bus == canbus, _T("Wrong bus."));
|
||||
Assert::IsTrue(msg.len == len, _T("Wrong len."));
|
||||
Assert::AreEqual(memcmp(msg.dat, candata, msg.len), 0, _T("Received CAN data not equal"));
|
||||
for (int i = msg.len; i < 8; i++)
|
||||
Assert::IsTrue(msg.dat[i] == 0, _T("Received CAN data not trailed by 0s"));
|
||||
}
|
||||
|
||||
Assert::IsTrue(can_msgs[0].is_receipt, _T("Didn't get receipt."));
|
||||
Assert::IsFalse(can_msgs[1].is_receipt, _T("Didn't get echo."));
|
||||
}
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_CAN_ChangeBaud)
|
||||
{
|
||||
auto p0 = getPanda(250);
|
||||
auto p1 = getPanda(500);
|
||||
|
||||
p0->can_send(0xAA, FALSE, (const uint8_t*)"\x1\x2\x3\x4\x5\x6\x7\x8", 8, panda::PANDA_CAN1);
|
||||
panda_recv_loop(p0, 0);
|
||||
panda_recv_loop(p1, 0);
|
||||
|
||||
p0->set_can_speed_kbps(panda::PANDA_CAN1, 500);
|
||||
|
||||
auto panda_msg_recv = panda_recv_loop(p0, 1);
|
||||
check_panda_can_msg(panda_msg_recv[0], 0, 0xAA, FALSE, TRUE, "\x1\x2\x3\x4\x5\x6\x7\x8", LINE_INFO());
|
||||
panda_msg_recv = panda_recv_loop(p1, 1);
|
||||
check_panda_can_msg(panda_msg_recv[0], 0, 0xAA, FALSE, FALSE, "\x1\x2\x3\x4\x5\x6\x7\x8", LINE_INFO());
|
||||
|
||||
//////////////////
|
||||
|
||||
p0->set_can_speed_kbps(panda::PANDA_CAN1, 250);
|
||||
p0->can_send(0xC4, FALSE, (const uint8_t*)"\xA\B\xC\xD\xE\xF\x10\x11", 8, panda::PANDA_CAN1);
|
||||
panda_recv_loop(p0, 0);
|
||||
panda_recv_loop(p1, 0);
|
||||
|
||||
p1->set_can_speed_kbps(panda::PANDA_CAN1, 250);
|
||||
|
||||
panda_msg_recv = panda_recv_loop(p0, 1);
|
||||
check_panda_can_msg(panda_msg_recv[0], 0, 0xC4, FALSE, TRUE, "\xA\B\xC\xD\xE\xF\x10\x11", LINE_INFO());
|
||||
panda_msg_recv = panda_recv_loop(p1, 1);
|
||||
check_panda_can_msg(panda_msg_recv[0], 0, 0xC4, FALSE, FALSE, "\xA\B\xC\xD\xE\xF\x10\x11", LINE_INFO());
|
||||
}
|
||||
|
||||
TEST_METHOD(Panda_CAN_ClearClears)
|
||||
{
|
||||
auto p0 = getPanda(500, TRUE);
|
||||
p0->can_send(0xAA, FALSE, (const uint8_t*)"\x0\x1\x2\x3\x4\x5\x6\x7", 8, panda::PANDA_CAN1);
|
||||
Sleep(100);
|
||||
p0->can_clear(PANDA_CAN_RX);
|
||||
|
||||
auto can_msgs = p0->can_recv();
|
||||
Assert::IsTrue(can_msgs.size() == 0, _T("Received messages after a clear."));
|
||||
}
|
||||
};
|
||||
|
||||
TEST_CLASS(SerialOperations)
|
||||
{
|
||||
public:
|
||||
|
||||
TEST_METHOD(Panda_LIN_Echo)
|
||||
{
|
||||
auto p0 = getPanda(500);
|
||||
|
||||
for (auto lin_port : { SERIAL_LIN1, SERIAL_LIN2 }) {
|
||||
p0->serial_clear(lin_port);
|
||||
|
||||
for (int i = 0; i < 10; i++) {
|
||||
uint8_t len = (rand() % LIN_MSG_MAX_LEN) + 1;
|
||||
std::string lindata;
|
||||
lindata.reserve(len);
|
||||
|
||||
for (size_t j = 0; j < len; j++)
|
||||
lindata += (const char)(rand() % 256);
|
||||
|
||||
p0->serial_write(lin_port, lindata.c_str(), len);
|
||||
Sleep(10);
|
||||
|
||||
auto retdata = p0->serial_read(lin_port);
|
||||
Assert::AreEqual(retdata, lindata);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// pandaJ2534DLL Test.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|
|
@ -0,0 +1,14 @@
|
|||
#pragma once
|
||||
|
||||
#include "targetver.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
|
||||
// Windows Header Files:
|
||||
#include <windows.h>
|
||||
#include <tchar.h>
|
||||
|
||||
// Headers for CppUnitTest
|
||||
#include "CppUnitTest.h"
|
||||
#include <iomanip> //Used for formatting in TestHelpers.cpp
|
||||
#include <string>
|
||||
#include <array>
|
|
@ -0,0 +1,8 @@
|
|||
#pragma once
|
||||
|
||||
// Including SDKDDKVer.h defines the highest available Windows platform.
|
||||
|
||||
// If you wish to build your application for a previous Windows platform, include WinSDKVer.h and
|
||||
// set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h.
|
||||
|
||||
#include <SDKDDKVer.h>
|
|
@ -0,0 +1,57 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
|
||||
#include "J2534Frame.h"
|
||||
|
||||
class J2534Connection;
|
||||
|
||||
/**
|
||||
An Action represents a unit of work that can be scheduled for execution at a later time.
|
||||
Actions are not guaranteed to be run at their specified time, but a best effort is made.
|
||||
An Action will never execute early, but can execute later depending on what is in the
|
||||
queus.
|
||||
Many different operations are based on this base class. Instead of making a thread,
|
||||
consider if the work can be offloaded to the Task Queue.
|
||||
*/
|
||||
class Action
|
||||
{
|
||||
public:
|
||||
Action(
|
||||
std::weak_ptr<J2534Connection> connection,
|
||||
std::chrono::microseconds delay
|
||||
) : connection(connection), delay(delay) { };
|
||||
|
||||
Action(
|
||||
std::weak_ptr<J2534Connection> connection
|
||||
) : connection(connection), delay(std::chrono::microseconds(0)) { };
|
||||
|
||||
//The function called by the task runner when this action is to be invoked.
|
||||
virtual void execute() = 0;
|
||||
|
||||
//Reschedule this Action for now().
|
||||
void scheduleImmediate() {
|
||||
expire = std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
//Reschedule this Action relative to its last expiration time.
|
||||
void scheduleDelay() {
|
||||
expire += this->delay;
|
||||
}
|
||||
|
||||
//Reschedule this action {delay} after now().
|
||||
void scheduleImmediateDelay() {
|
||||
expire = std::chrono::steady_clock::now() + this->delay;
|
||||
}
|
||||
|
||||
//Reschedule this Action based on a specific base time.
|
||||
void schedule(std::chrono::time_point<std::chrono::steady_clock> starttine, BOOL adddelayed) {
|
||||
this->expire = starttine;
|
||||
if (adddelayed)
|
||||
expire += this->delay;
|
||||
}
|
||||
|
||||
std::weak_ptr<J2534Connection> connection;
|
||||
std::chrono::microseconds delay;
|
||||
//The timestamp at which point this Action is ready to be executed.
|
||||
std::chrono::time_point<std::chrono::steady_clock> expire;
|
||||
};
|
|
@ -0,0 +1,257 @@
|
|||
#include "stdafx.h"
|
||||
#include "J2534Connection.h"
|
||||
#include "Timer.h"
|
||||
|
||||
J2534Connection::J2534Connection(
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
) : panda_dev(panda_dev), ProtocolID(ProtocolID), Flags(Flags), BaudRate(BaudRate), port(0) { }
|
||||
|
||||
unsigned long J2534Connection::validateTxMsg(PASSTHRU_MSG* msg) {
|
||||
if (msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen())
|
||||
return ERR_INVALID_MSG;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
long J2534Connection::PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||||
//Timeout of 0 means return immediately. Non zero means WAIT for that time then return. Dafuk.
|
||||
long err_code = STATUS_NOERROR;
|
||||
Timer t = Timer();
|
||||
|
||||
unsigned long msgnum = 0;
|
||||
while (msgnum < *pNumMsgs) {
|
||||
if (Timeout > 0 && t.getTimePassed() >= Timeout) {
|
||||
err_code = ERR_TIMEOUT;
|
||||
break;
|
||||
}
|
||||
|
||||
//Synchronized won't work where we have to break out of a loop
|
||||
messageRxBuff_mutex.lock();
|
||||
if (this->messageRxBuff.empty()) {
|
||||
messageRxBuff_mutex.unlock();
|
||||
if (Timeout == 0)
|
||||
break;
|
||||
continue;
|
||||
}
|
||||
|
||||
auto msg_in = this->messageRxBuff.front();
|
||||
this->messageRxBuff.pop();
|
||||
messageRxBuff_mutex.unlock();
|
||||
|
||||
PASSTHRU_MSG *msg_out = &pMsg[msgnum++];
|
||||
msg_out->ProtocolID = this->ProtocolID;
|
||||
msg_out->DataSize = msg_in.Data.size();
|
||||
memcpy(msg_out->Data, msg_in.Data.c_str(), msg_in.Data.size());
|
||||
msg_out->Timestamp = msg_in.Timestamp;
|
||||
msg_out->RxStatus = msg_in.RxStatus;
|
||||
msg_out->ExtraDataIndex = msg_in.ExtraDataIndex;
|
||||
msg_out->TxFlags = 0;
|
||||
if (msgnum == *pNumMsgs) break;
|
||||
}
|
||||
|
||||
if (msgnum == 0)
|
||||
err_code = ERR_BUFFER_EMPTY;
|
||||
*pNumMsgs = msgnum;
|
||||
return err_code;
|
||||
}
|
||||
|
||||
long J2534Connection::PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||||
//There doesn't seem to be much reason to implement the timeout here.
|
||||
for (int msgnum = 0; msgnum < *pNumMsgs; msgnum++) {
|
||||
PASSTHRU_MSG* msg = &pMsg[msgnum];
|
||||
if (msg->ProtocolID != this->ProtocolID) {
|
||||
*pNumMsgs = msgnum;
|
||||
return ERR_MSG_PROTOCOL_ID;
|
||||
}
|
||||
|
||||
auto retcode = this->validateTxMsg(msg);
|
||||
if (retcode != STATUS_NOERROR) {
|
||||
*pNumMsgs = msgnum;
|
||||
return retcode;
|
||||
}
|
||||
|
||||
auto msgtx = this->parseMessageTx(*pMsg);
|
||||
if (msgtx != nullptr) //Nullptr is supported for unimplemented connection types.
|
||||
this->schedultMsgTx(std::dynamic_pointer_cast<Action>(msgtx));
|
||||
}
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
//The docs say that a device has to support 10 periodic messages, though more is ok.
|
||||
//It is easier to store them on the connection, so 10 per connection it is.
|
||||
long J2534Connection::PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval) {
|
||||
if (pMsg->DataSize < getMinMsgLen() || pMsg->DataSize > getMaxMsgSingleFrameLen()) return ERR_INVALID_MSG;
|
||||
if (pMsg->ProtocolID != this->ProtocolID) return ERR_MSG_PROTOCOL_ID;
|
||||
if (TimeInterval < 5 || TimeInterval > 65535) return ERR_INVALID_TIME_INTERVAL;
|
||||
|
||||
for (int i = 0; i < this->periodicMessages.size(); i++) {
|
||||
if (periodicMessages[i] != nullptr) continue;
|
||||
|
||||
*pMsgID = i;
|
||||
auto msgtx = this->parseMessageTx(*pMsg);
|
||||
if (msgtx != nullptr) {
|
||||
periodicMessages[i] = std::make_shared<MessagePeriodic>(std::chrono::microseconds(TimeInterval*1000), msgtx);
|
||||
periodicMessages[i]->scheduleImmediate();
|
||||
if (auto panda_dev = this->getPandaDev()) {
|
||||
panda_dev->insertActionIntoTaskList(periodicMessages[i]);
|
||||
}
|
||||
}
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
return ERR_EXCEEDED_LIMIT;
|
||||
}
|
||||
|
||||
long J2534Connection::PassThruStopPeriodicMsg(unsigned long MsgID) {
|
||||
if (MsgID >= this->periodicMessages.size() || this->periodicMessages[MsgID] == nullptr)
|
||||
return ERR_INVALID_MSG_ID;
|
||||
this->periodicMessages[MsgID]->cancel();
|
||||
this->periodicMessages[MsgID] = nullptr;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
long J2534Connection::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
|
||||
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) {
|
||||
for (int i = 0; i < this->filters.size(); i++) {
|
||||
if (filters[i] == nullptr) {
|
||||
try {
|
||||
auto newfilter = std::make_shared<J2534MessageFilter>(this, FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg);
|
||||
for (int check_idx = 0; check_idx < filters.size(); check_idx++) {
|
||||
if (filters[check_idx] == nullptr) continue;
|
||||
if (filters[check_idx] == newfilter) {
|
||||
filters[i] = nullptr;
|
||||
return ERR_NOT_UNIQUE;
|
||||
}
|
||||
}
|
||||
*pFilterID = i;
|
||||
filters[i] = newfilter;
|
||||
return STATUS_NOERROR;
|
||||
} catch (int e) {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
}
|
||||
return ERR_EXCEEDED_LIMIT;
|
||||
}
|
||||
|
||||
long J2534Connection::PassThruStopMsgFilter(unsigned long FilterID) {
|
||||
if (FilterID >= this->filters.size() || this->filters[FilterID] == nullptr)
|
||||
return ERR_INVALID_FILTER_ID;
|
||||
this->filters[FilterID] = nullptr;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
long J2534Connection::PassThruIoctl(unsigned long IoctlID, void *pInput, void *pOutput) {
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
long J2534Connection::init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput) { return STATUS_NOERROR; }
|
||||
long J2534Connection::initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput) { return STATUS_NOERROR; }
|
||||
long J2534Connection::clearTXBuff() { return STATUS_NOERROR; }
|
||||
long J2534Connection::clearRXBuff() {
|
||||
synchronized(messageRxBuff_mutex) {
|
||||
this->messageRxBuff = {};
|
||||
}
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
long J2534Connection::clearPeriodicMsgs() { return STATUS_NOERROR; }
|
||||
long J2534Connection::clearMsgFilters() {
|
||||
for (auto& filter : this->filters) filter = nullptr;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
void J2534Connection::setBaud(unsigned long baud) {
|
||||
this->BaudRate = baud;
|
||||
}
|
||||
|
||||
void J2534Connection::schedultMsgTx(std::shared_ptr<Action> msgout) {
|
||||
if (auto panda_ps = this->panda_dev.lock()) {
|
||||
synchronized(staged_writes_lock) {
|
||||
this->txbuff.push(msgout);
|
||||
panda_ps->registerConnectionTx(shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void J2534Connection::rescheduleExistingTxMsgs() {
|
||||
if (auto panda_ps = this->panda_dev.lock()) {
|
||||
synchronized(staged_writes_lock) {
|
||||
panda_ps->unstallConnectionTx(shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Works well as long as the protocol doesn't support flow control.
|
||||
void J2534Connection::processMessage(const J2534Frame& msg) {
|
||||
FILTER_RESULT filter_res = FILTER_RESULT_NEUTRAL;
|
||||
|
||||
for (auto filter : this->filters) {
|
||||
if (filter == nullptr) continue;
|
||||
FILTER_RESULT current_check_res = filter->check(msg);
|
||||
if (current_check_res == FILTER_RESULT_BLOCK) return;
|
||||
if (current_check_res == FILTER_RESULT_PASS) filter_res = FILTER_RESULT_PASS;
|
||||
}
|
||||
|
||||
if (filter_res == FILTER_RESULT_PASS) {
|
||||
addMsgToRxQueue(msg);
|
||||
}
|
||||
}
|
||||
|
||||
void J2534Connection::processIOCTLSetConfig(unsigned long Parameter, unsigned long Value) {
|
||||
switch (Parameter) {
|
||||
case DATA_RATE: // 5-500000
|
||||
this->setBaud(Value);
|
||||
case LOOPBACK: // 0 (OFF), 1 (ON) [0]
|
||||
this->loopback = (Value != 0);
|
||||
break;
|
||||
case ISO15765_WFT_MAX:
|
||||
break;
|
||||
case NODE_ADDRESS: // J1850PWM Related (Not supported by panda). HDS requires these to 'work'.
|
||||
case NETWORK_LINE:
|
||||
case P1_MIN: // A bunch of stuff relating to ISO9141 and ISO14230 that the panda
|
||||
case P1_MAX: // currently doesn't support. Don't let HDS know we can't use these.
|
||||
case P2_MIN:
|
||||
case P2_MAX:
|
||||
case P3_MIN:
|
||||
case P3_MAX:
|
||||
case P4_MIN:
|
||||
case P4_MAX:
|
||||
case W0:
|
||||
case W1:
|
||||
case W2:
|
||||
case W3:
|
||||
case W4:
|
||||
case W5:
|
||||
case TIDLE:
|
||||
case TINIL:
|
||||
case TWUP:
|
||||
case PARITY:
|
||||
case T1_MAX: // SCI related options. The panda does not appear to support this
|
||||
case T2_MAX:
|
||||
case T3_MAX:
|
||||
case T4_MAX:
|
||||
case T5_MAX:
|
||||
break; // Just smile and nod.
|
||||
default:
|
||||
printf("Got unknown SET code %X\n", Parameter);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long J2534Connection::processIOCTLGetConfig(unsigned long Parameter) {
|
||||
switch (Parameter) {
|
||||
case DATA_RATE:
|
||||
return this->getBaud();
|
||||
case LOOPBACK:
|
||||
return this->loopback;
|
||||
break;
|
||||
case BIT_SAMPLE_POINT:
|
||||
return 80;
|
||||
case SYNC_JUMP_WIDTH:
|
||||
return 15;
|
||||
default:
|
||||
// HDS rarely reads off values through ioctl GET_CONFIG, but it often
|
||||
// just wants the call to pass without erroring, so just don't do anything.
|
||||
printf("Got unknown code %X\n", Parameter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,141 @@
|
|||
#pragma once
|
||||
#include "panda/panda.h"
|
||||
#include "J2534_v0404.h"
|
||||
#include "synchronize.h"
|
||||
#include "J2534Frame.h"
|
||||
#include "PandaJ2534Device.h"
|
||||
#include "J2534MessageFilter.h"
|
||||
#include "MessagePeriodic.h"
|
||||
|
||||
class J2534Frame;
|
||||
class Action;
|
||||
class PandaJ2534Device;
|
||||
class J2534MessageFilter;
|
||||
|
||||
#define check_bmask(num, mask)(((num) & mask) == mask)
|
||||
|
||||
/**
|
||||
Class representing a generic J2534 Connection created by PassThruConnect,
|
||||
and is associated with a channelID given to the J2534 API user.
|
||||
Subclasses implement specific J2534 supported protocols.
|
||||
*/
|
||||
class J2534Connection : public std::enable_shared_from_this<J2534Connection> {
|
||||
friend class PandaJ2534Device;
|
||||
|
||||
public:
|
||||
J2534Connection(
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
);
|
||||
virtual ~J2534Connection() {};
|
||||
|
||||
//J2534 API functions
|
||||
|
||||
virtual long PassThruReadMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
|
||||
long PassThruWriteMsgs(PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
|
||||
virtual long PassThruStartPeriodicMsg(PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval);
|
||||
virtual long PassThruStopPeriodicMsg(unsigned long MsgID);
|
||||
|
||||
virtual long PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
|
||||
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID);
|
||||
|
||||
virtual long PassThruStopMsgFilter(unsigned long FilterID);
|
||||
virtual long PassThruIoctl(unsigned long IoctlID, void *pInput, void *pOutput);
|
||||
|
||||
//Functions for parsing messages to be send with PassThruWriteMsgs.
|
||||
|
||||
virtual unsigned long validateTxMsg(PASSTHRU_MSG* msg);
|
||||
virtual std::shared_ptr<MessageTx> parseMessageTx(PASSTHRU_MSG& msg) { return nullptr; };
|
||||
|
||||
//IOCTL functions
|
||||
|
||||
long init5b(SBYTE_ARRAY* pInput, SBYTE_ARRAY* pOutput);
|
||||
long initFast(PASSTHRU_MSG* pInput, PASSTHRU_MSG* pOutput);
|
||||
long clearTXBuff();
|
||||
long clearRXBuff();
|
||||
long clearPeriodicMsgs();
|
||||
long clearMsgFilters();
|
||||
|
||||
virtual void setBaud(unsigned long baud);
|
||||
|
||||
unsigned long getBaud() {
|
||||
return this->BaudRate;
|
||||
}
|
||||
|
||||
unsigned long getProtocol() {
|
||||
return this->ProtocolID;
|
||||
};
|
||||
|
||||
virtual bool isProtoCan() {
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
//Port is used in a protocol specific way to differentiate tranceivers.
|
||||
unsigned long getPort() {
|
||||
return this->port;
|
||||
}
|
||||
|
||||
virtual void processIOCTLSetConfig(unsigned long Parameter, unsigned long Value);
|
||||
|
||||
virtual unsigned long processIOCTLGetConfig(unsigned long Parameter);
|
||||
|
||||
//Called when the passthru device has received a message for this connection
|
||||
//Loopback messages are processed separately.
|
||||
virtual void processMessage(const J2534Frame& msg);
|
||||
|
||||
//Limitations on message size. Override in every subclass.
|
||||
|
||||
virtual unsigned long getMinMsgLen() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
virtual unsigned long getMaxMsgLen() {
|
||||
return 4128;
|
||||
}
|
||||
|
||||
virtual unsigned long getMaxMsgSingleFrameLen() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
//Add an Action to the Task Queue for future processing.
|
||||
//The task should be set its expire time before being submitted.
|
||||
void schedultMsgTx(std::shared_ptr<Action> msgout);
|
||||
|
||||
void rescheduleExistingTxMsgs();
|
||||
|
||||
std::shared_ptr<PandaJ2534Device> getPandaDev() {
|
||||
if (auto panda_dev_sp = this->panda_dev.lock())
|
||||
return panda_dev_sp;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
//Add a message to the queue read by PassThruReadMsgs().
|
||||
void addMsgToRxQueue(const J2534Frame& frame) {
|
||||
synchronized(messageRxBuff_mutex) {
|
||||
messageRxBuff.push(frame);
|
||||
}
|
||||
}
|
||||
|
||||
bool loopback = FALSE;
|
||||
|
||||
protected:
|
||||
unsigned long ProtocolID;
|
||||
unsigned long Flags;
|
||||
unsigned long BaudRate;
|
||||
unsigned long port;
|
||||
|
||||
std::weak_ptr<PandaJ2534Device> panda_dev;
|
||||
|
||||
Mutex messageRxBuff_mutex;
|
||||
std::queue<J2534Frame> messageRxBuff;
|
||||
|
||||
std::array<std::shared_ptr<J2534MessageFilter>, 10> filters;
|
||||
std::queue<std::shared_ptr<Action>> txbuff;
|
||||
|
||||
std::array<std::shared_ptr<MessagePeriodic>, 10> periodicMessages;
|
||||
|
||||
private:
|
||||
Mutex staged_writes_lock;
|
||||
};
|
|
@ -0,0 +1,41 @@
|
|||
#include "stdafx.h"
|
||||
#include "J2534Connection_CAN.h"
|
||||
#include "MessageTx_CAN.h"
|
||||
#include "Timer.h"
|
||||
|
||||
J2534Connection_CAN::J2534Connection_CAN(
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate) {
|
||||
this->port = 0;
|
||||
|
||||
if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
|
||||
throw ERR_INVALID_BAUDRATE;
|
||||
|
||||
panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, BaudRate/100);
|
||||
};
|
||||
|
||||
unsigned long J2534Connection_CAN::validateTxMsg(PASSTHRU_MSG* msg) {
|
||||
if ((msg->DataSize < this->getMinMsgLen() || msg->DataSize > this->getMaxMsgLen() ||
|
||||
(val_is_29bit(msg->TxFlags) != this->_is_29bit() && !check_bmask(this->Flags, CAN_ID_BOTH))))
|
||||
return ERR_INVALID_MSG;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageTx> J2534Connection_CAN::parseMessageTx(PASSTHRU_MSG& msg) {
|
||||
return std::dynamic_pointer_cast<MessageTx>(std::make_shared<MessageTx_CAN>(shared_from_this(), msg));
|
||||
}
|
||||
|
||||
void J2534Connection_CAN::setBaud(unsigned long BaudRate) {
|
||||
if (auto panda_dev = this->getPandaDev()) {
|
||||
if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
|
||||
throw ERR_NOT_SUPPORTED;
|
||||
|
||||
panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, (uint16_t)(BaudRate / 100));
|
||||
return J2534Connection::setBaud(BaudRate);
|
||||
} else {
|
||||
throw ERR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
#pragma once
|
||||
|
||||
#include "J2534Connection.h"
|
||||
#include "panda/panda.h"
|
||||
|
||||
#define val_is_29bit(num) check_bmask(num, CAN_29BIT_ID)
|
||||
|
||||
class J2534Connection_CAN : public J2534Connection {
|
||||
public:
|
||||
J2534Connection_CAN(
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
);
|
||||
|
||||
virtual unsigned long validateTxMsg(PASSTHRU_MSG* msg);
|
||||
|
||||
virtual std::shared_ptr<MessageTx> parseMessageTx(PASSTHRU_MSG& pMsg);
|
||||
|
||||
virtual void setBaud(unsigned long baud);
|
||||
|
||||
virtual unsigned long getMinMsgLen() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
virtual unsigned long getMaxMsgLen() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
virtual unsigned long getMaxMsgSingleFrameLen() {
|
||||
return 12;
|
||||
}
|
||||
|
||||
virtual bool isProtoCan() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool _is_29bit() {
|
||||
return (this->Flags & CAN_29BIT_ID) == CAN_29BIT_ID;
|
||||
}
|
||||
|
||||
};
|
|
@ -0,0 +1,229 @@
|
|||
#include "stdafx.h"
|
||||
#include "J2534Connection_ISO15765.h"
|
||||
#include "Timer.h"
|
||||
#include "constants_ISO15765.h"
|
||||
#include <chrono>
|
||||
|
||||
J2534Connection_ISO15765::J2534Connection_ISO15765(
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
) : J2534Connection(panda_dev, ProtocolID, Flags, BaudRate), wftMax(0) {
|
||||
this->port = 0;
|
||||
|
||||
if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
|
||||
throw ERR_INVALID_BAUDRATE;
|
||||
|
||||
panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, (uint16_t)(BaudRate / 100));
|
||||
}
|
||||
|
||||
unsigned long J2534Connection_ISO15765::validateTxMsg(PASSTHRU_MSG* msg) {
|
||||
if ((msg->DataSize < this->getMinMsgLen() + (msg_is_extaddr(msg) ? 1 : 0) ||
|
||||
msg->DataSize > this->getMaxMsgLen() + (msg_is_extaddr(msg) ? 1 : 0) ||
|
||||
(val_is_29bit(msg->TxFlags) != this->_is_29bit() && !check_bmask(this->Flags, CAN_ID_BOTH))))
|
||||
return ERR_INVALID_MSG;
|
||||
|
||||
int fid = get_matching_out_fc_filter_id(std::string((const char*)msg->Data, msg->DataSize), msg->TxFlags, 0xFFFFFFFF);
|
||||
if (msg->DataSize > getMaxMsgSingleFrameLen() && fid == -1) return ERR_NO_FLOW_CONTROL; //11 bytes (4 for CANid, 7 payload) is max length of input frame.
|
||||
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
std::shared_ptr<MessageTx> J2534Connection_ISO15765::parseMessageTx(PASSTHRU_MSG& msg) {
|
||||
int fid = get_matching_out_fc_filter_id(std::string((const char*)msg.Data, msg.DataSize), msg.TxFlags, 0xFFFFFFFF);
|
||||
if (msg.DataSize > getMaxMsgSingleFrameLen() && fid == -1) 1;
|
||||
|
||||
return std::dynamic_pointer_cast<MessageTx>(
|
||||
std::make_shared<MessageTx_ISO15765>(shared_from_this(), msg, (fid == -1) ? nullptr : this->filters[fid])
|
||||
);
|
||||
}
|
||||
|
||||
//https://happilyembedded.wordpress.com/2016/02/15/can-multiple-frame-transmission/
|
||||
void J2534Connection_ISO15765::processMessage(const J2534Frame& msg) {
|
||||
if (msg.ProtocolID != CAN) return;
|
||||
|
||||
int fid = get_matching_in_fc_filter_id(msg);
|
||||
if (fid == -1) return;
|
||||
|
||||
auto filter = this->filters[fid];
|
||||
bool is_ext_addr = check_bmask(filter->flags, ISO15765_ADDR_TYPE);
|
||||
uint8_t addrlen = is_ext_addr ? 5 : 4;
|
||||
|
||||
switch (msg_get_type(msg, addrlen)) {
|
||||
case FRAME_FLOWCTRL:
|
||||
{
|
||||
if (this->txbuff.size() == 0)
|
||||
return;
|
||||
if (msg.Data.size() < addrlen + 3) return;
|
||||
uint8_t flow_status = msg.Data[addrlen] & 0x0F;
|
||||
uint8_t block_size = msg.Data[addrlen + 1];
|
||||
uint8_t st_min = msg.Data[addrlen + 2];
|
||||
|
||||
auto txConvo = std::static_pointer_cast<MessageTx_ISO15765>(this->txbuff.front());
|
||||
switch (flow_status) {
|
||||
case FLOWCTRL_CONTINUE: {
|
||||
if (st_min > 0xF9) break;
|
||||
if (st_min >= 0xf1 && st_min <= 0xf9) {
|
||||
txConvo->flowControlContinue(block_size, std::chrono::microseconds((st_min & 0x0F) * 100));
|
||||
} else if(st_min <= 0x7f) {
|
||||
txConvo->flowControlContinue(block_size, std::chrono::microseconds(st_min * 1000));
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
txConvo->scheduleImmediate();
|
||||
this->rescheduleExistingTxMsgs();
|
||||
break;
|
||||
}
|
||||
case FLOWCTRL_WAIT:
|
||||
txConvo->flowControlWait(this->wftMax);
|
||||
break;
|
||||
case FLOWCTRL_ABORT:
|
||||
txConvo->flowControlAbort();
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRAME_SINGLE:
|
||||
{
|
||||
this->rxConversations[fid] = nullptr; //Reset any current transaction.
|
||||
|
||||
if (is_ext_addr) {
|
||||
if ((msg.Data[5] & 0x0F) > 6) return;
|
||||
} else {
|
||||
if ((msg.Data[4] & 0x0F) > 7) return;
|
||||
}
|
||||
|
||||
J2534Frame outframe(ISO15765, msg.RxStatus, 0, msg.Timestamp);
|
||||
if (msg.Data.size() != 8 && check_bmask(this->Flags, ISO15765_FRAME_PAD))
|
||||
outframe.RxStatus |= ISO15765_PADDING_ERROR;
|
||||
if (is_ext_addr)
|
||||
outframe.RxStatus |= ISO15765_ADDR_TYPE;
|
||||
outframe.Data = msg.Data.substr(0, addrlen) + msg.Data.substr(addrlen + 1, msg.Data[addrlen]);
|
||||
outframe.ExtraDataIndex = outframe.Data.size();
|
||||
|
||||
addMsgToRxQueue(outframe);
|
||||
break;
|
||||
}
|
||||
case FRAME_FIRST:
|
||||
{
|
||||
if (msg.Data.size() < 12) {
|
||||
//A frame was received that could have held more data.
|
||||
//No examples of this protocol show that happening, so
|
||||
//it will be assumed that it is grounds to reset rx.
|
||||
this->rxConversations[fid] = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
J2534Frame outframe(ISO15765, msg.RxStatus | START_OF_MESSAGE, 0, msg.Timestamp);
|
||||
if (is_ext_addr)
|
||||
outframe.RxStatus |= ISO15765_ADDR_TYPE;
|
||||
outframe.Data = msg.Data.substr(0, addrlen);
|
||||
|
||||
addMsgToRxQueue(outframe);
|
||||
|
||||
this->rxConversations[fid] = std::make_shared<MessageRx>(
|
||||
((msg.Data[addrlen] & 0x0F) << 8) | msg.Data[addrlen + 1],
|
||||
msg.Data.substr(addrlen + 2, 12 - (addrlen + 2)),
|
||||
msg.RxStatus, filter);
|
||||
|
||||
//TODO maybe the flow control should also be scheduled in the TX list.
|
||||
//Doing it this way because the filter can be 5 bytes in ext address mode.
|
||||
std::string flowfilter = filter->get_flowctrl();
|
||||
uint32_t flow_addr = (((uint8_t)flowfilter[0]) << 24) | ((uint8_t)(flowfilter[1]) << 16) | ((uint8_t)(flowfilter[2]) << 8) | ((uint8_t)flowfilter[3]);
|
||||
|
||||
std::string flowstrlresp;
|
||||
if (flowfilter.size() > 4)
|
||||
flowstrlresp += flowfilter[4];
|
||||
flowstrlresp += std::string("\x30\x00\x00", 3);
|
||||
|
||||
if (auto panda_dev_sp = this->panda_dev.lock()) {
|
||||
panda_dev_sp->panda->can_send(flow_addr, val_is_29bit(msg.RxStatus), (const uint8_t *)flowstrlresp.c_str(), (uint8_t)flowstrlresp.size(), panda::PANDA_CAN1);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case FRAME_CONSEC:
|
||||
{
|
||||
auto& convo = this->rxConversations[fid];
|
||||
if (convo == nullptr) return;
|
||||
|
||||
if (!convo->rx_add_frame(msg.Data[addrlen], (is_ext_addr ? 6 : 7), msg.Data.substr(addrlen + 1))) {
|
||||
//Delete this conversation.
|
||||
convo = nullptr;
|
||||
return;
|
||||
}
|
||||
|
||||
std::string final_msg;
|
||||
if (convo->flush_result(final_msg)) {
|
||||
convo = nullptr;
|
||||
J2534Frame outframe(ISO15765, msg.RxStatus, 0, msg.Timestamp);
|
||||
if (is_ext_addr)
|
||||
outframe.RxStatus |= ISO15765_ADDR_TYPE;
|
||||
outframe.Data = msg.Data.substr(0, addrlen) + final_msg;
|
||||
outframe.ExtraDataIndex = outframe.Data.size();
|
||||
|
||||
addMsgToRxQueue(outframe);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void J2534Connection_ISO15765::setBaud(unsigned long BaudRate) {
|
||||
if (auto panda_dev = this->getPandaDev()) {
|
||||
if (BaudRate % 100 || BaudRate < 10000 || BaudRate > 5000000)
|
||||
throw ERR_NOT_SUPPORTED;
|
||||
|
||||
panda_dev->panda->set_can_speed_cbps(panda::PANDA_CAN1, (uint16_t)(BaudRate / 100));
|
||||
return J2534Connection::setBaud(BaudRate);
|
||||
} else {
|
||||
throw ERR_DEVICE_NOT_CONNECTED;
|
||||
}
|
||||
}
|
||||
|
||||
long J2534Connection_ISO15765::PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg,
|
||||
PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) {
|
||||
|
||||
if (FilterType != FLOW_CONTROL_FILTER) return ERR_INVALID_FILTER_ID;
|
||||
return J2534Connection::PassThruStartMsgFilter(FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg, pFilterID);
|
||||
}
|
||||
|
||||
int J2534Connection_ISO15765::get_matching_out_fc_filter_id(const std::string& msgdata, unsigned long flags, unsigned long flagmask) {
|
||||
for (unsigned int i = 0; i < this->filters.size(); i++) {
|
||||
if (this->filters[i] == nullptr) continue;
|
||||
auto filter = this->filters[i]->get_flowctrl();
|
||||
if (filter == msgdata.substr(0, filter.size()) &&
|
||||
(this->filters[i]->flags & flagmask) == (flags & flagmask))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
int J2534Connection_ISO15765::get_matching_in_fc_filter_id(const J2534Frame& msg, unsigned long flagmask) {
|
||||
for (unsigned int i = 0; i < this->filters.size(); i++) {
|
||||
if (this->filters[i] == nullptr) continue;
|
||||
if (this->filters[i]->check(msg) == FILTER_RESULT_MATCH &&
|
||||
(this->filters[i]->flags & flagmask) == (msg.RxStatus & flagmask))
|
||||
return i;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void J2534Connection_ISO15765::processIOCTLSetConfig(unsigned long Parameter, unsigned long Value) {
|
||||
switch (Parameter) {
|
||||
case ISO15765_WFT_MAX:
|
||||
this->wftMax = Value;
|
||||
break;
|
||||
default:
|
||||
J2534Connection::processIOCTLSetConfig(Parameter, Value);
|
||||
}
|
||||
}
|
||||
|
||||
unsigned long J2534Connection_ISO15765::processIOCTLGetConfig(unsigned long Parameter) {
|
||||
switch (Parameter) {
|
||||
case ISO15765_WFT_MAX:
|
||||
return this->wftMax;
|
||||
default:
|
||||
return J2534Connection::processIOCTLGetConfig(Parameter);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
#pragma once
|
||||
#include <string>
|
||||
#include "J2534Connection.h"
|
||||
#include "J2534Connection_CAN.h"
|
||||
#include "MessageTx_ISO15765.h"
|
||||
#include "MessageRx.h"
|
||||
|
||||
class MessageTx_ISO15765;
|
||||
|
||||
typedef struct {
|
||||
std::string dispatched_msg;
|
||||
std::string remaining_payload;
|
||||
} PRESTAGED_WRITE;
|
||||
|
||||
class J2534Connection_ISO15765 : public J2534Connection {
|
||||
public:
|
||||
J2534Connection_ISO15765(
|
||||
std::shared_ptr<PandaJ2534Device> panda_dev,
|
||||
unsigned long ProtocolID,
|
||||
unsigned long Flags,
|
||||
unsigned long BaudRate
|
||||
);
|
||||
|
||||
virtual long PassThruStartMsgFilter(unsigned long FilterType, PASSTHRU_MSG * pMaskMsg, PASSTHRU_MSG * pPatternMsg, PASSTHRU_MSG * pFlowControlMsg, unsigned long * pFilterID);
|
||||
|
||||
int get_matching_out_fc_filter_id(const std::string & msgdata, unsigned long flags, unsigned long flagmask);
|
||||
|
||||
int get_matching_in_fc_filter_id(const J2534Frame& msg, unsigned long flagmask = CAN_29BIT_ID);
|
||||
|
||||
virtual unsigned long validateTxMsg(PASSTHRU_MSG* msg);
|
||||
|
||||
virtual std::shared_ptr<MessageTx> parseMessageTx(PASSTHRU_MSG& msg);
|
||||
|
||||
virtual void processMessage(const J2534Frame& msg);
|
||||
|
||||
virtual void setBaud(unsigned long baud);
|
||||
|
||||
virtual void processIOCTLSetConfig(unsigned long Parameter, unsigned long Value);
|
||||
|
||||
virtual unsigned long processIOCTLGetConfig(unsigned long Parameter);
|
||||
|
||||
virtual unsigned long getMinMsgLen() {
|
||||
return 4;
|
||||
}
|
||||
|
||||
virtual unsigned long getMaxMsgLen() {
|
||||
return 4099;
|
||||
};
|
||||
|
||||
virtual unsigned long getMaxMsgSingleFrameLen() {
|
||||
return 11;
|
||||
}
|
||||
|
||||
virtual bool _is_29bit() {
|
||||
return (this->Flags & CAN_29BIT_ID) == CAN_29BIT_ID;
|
||||
}
|
||||
|
||||
virtual bool isProtoCan() {
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
private:
|
||||
std::array<std::shared_ptr<MessageRx>, 10> rxConversations;
|
||||
unsigned int wftMax;
|
||||
};
|
|
@ -0,0 +1,48 @@
|
|||
#pragma once
|
||||
#include "J2534_v0404.h"
|
||||
#include "panda/panda.h"
|
||||
|
||||
/*A move convenient container for J2534 Messages than the static buffer provided by default.*/
|
||||
class J2534Frame {
|
||||
public:
|
||||
J2534Frame(unsigned long ProtocolID, unsigned long RxStatus=0, unsigned long TxFlags=0, unsigned long Timestamp=0) :
|
||||
ProtocolID(ProtocolID), RxStatus(RxStatus), TxFlags(TxFlags), Timestamp(Timestamp), ExtraDataIndex(0), Data("") { };
|
||||
|
||||
J2534Frame(const panda::PANDA_CAN_MSG& msg_in) {
|
||||
ProtocolID = CAN;
|
||||
ExtraDataIndex = 0;
|
||||
Data.reserve(msg_in.len + 4);
|
||||
Data += msg_in.addr >> 24;
|
||||
Data += (msg_in.addr >> 16) & 0xFF;
|
||||
Data += (msg_in.addr >> 8) & 0xFF;
|
||||
Data += msg_in.addr & 0xFF;
|
||||
Data += std::string((char*)&msg_in.dat, msg_in.len);
|
||||
Timestamp = msg_in.recv_time;
|
||||
RxStatus = (msg_in.addr_29b ? CAN_29BIT_ID : 0) |
|
||||
(msg_in.is_receipt ? TX_MSG_TYPE : 0);
|
||||
}
|
||||
|
||||
J2534Frame(const PASSTHRU_MSG& msg) {
|
||||
this->ProtocolID = msg.ProtocolID;
|
||||
this->RxStatus = msg.RxStatus;
|
||||
this->TxFlags = msg.TxFlags;
|
||||
this->Timestamp = msg.Timestamp;
|
||||
this->ExtraDataIndex = msg.ExtraDataIndex;
|
||||
this->Data = std::string((const char*)msg.Data, msg.DataSize);
|
||||
}
|
||||
|
||||
J2534Frame() {
|
||||
this->ProtocolID = 0;
|
||||
this->RxStatus = 0;
|
||||
this->TxFlags = 0;
|
||||
this->Timestamp = 0;
|
||||
this->ExtraDataIndex = 0;
|
||||
}
|
||||
|
||||
unsigned long ProtocolID;
|
||||
unsigned long RxStatus;
|
||||
unsigned long TxFlags;
|
||||
unsigned long Timestamp;
|
||||
unsigned long ExtraDataIndex;
|
||||
std::string Data;
|
||||
};
|
|
@ -0,0 +1,104 @@
|
|||
#include "stdafx.h"
|
||||
#include "J2534MessageFilter.h"
|
||||
#include "J2534Frame.h"
|
||||
|
||||
J2534MessageFilter::J2534MessageFilter(
|
||||
J2534Connection *const conn,
|
||||
unsigned int filtertype,
|
||||
PASSTHRU_MSG *pMaskMsg,
|
||||
PASSTHRU_MSG *pPatternMsg,
|
||||
PASSTHRU_MSG *pFlowControlMsg
|
||||
) : filtertype(filtertype), flags(0), conn(conn) {
|
||||
switch (filtertype) {
|
||||
case PASS_FILTER:
|
||||
case BLOCK_FILTER:
|
||||
if (pMaskMsg == NULL || pPatternMsg == NULL)
|
||||
throw ERR_NULL_PARAMETER;
|
||||
if (pFlowControlMsg != NULL)
|
||||
throw ERR_INVALID_FILTER_ID;
|
||||
if (pMaskMsg->DataSize != pPatternMsg->DataSize)
|
||||
throw ERR_INVALID_MSG;
|
||||
break;
|
||||
case FLOW_CONTROL_FILTER:
|
||||
if (conn->getProtocol() != ISO15765) throw ERR_MSG_PROTOCOL_ID; //CHECK
|
||||
if (pFlowControlMsg == NULL || pMaskMsg == NULL || pPatternMsg == NULL)
|
||||
throw ERR_NULL_PARAMETER;
|
||||
break;
|
||||
default:
|
||||
throw ERR_INVALID_MSG;
|
||||
}
|
||||
|
||||
if (!(conn->getMinMsgLen() < pMaskMsg->DataSize || pMaskMsg->DataSize < conn->getMaxMsgLen()))
|
||||
throw ERR_INVALID_MSG;
|
||||
if (conn->getProtocol() != pMaskMsg->ProtocolID)
|
||||
throw ERR_MSG_PROTOCOL_ID;
|
||||
this->maskMsg = std::string((char*)pMaskMsg->Data, pMaskMsg->DataSize);
|
||||
|
||||
if (!(conn->getMinMsgLen() < pPatternMsg->DataSize || pPatternMsg->DataSize < conn->getMaxMsgLen()))
|
||||
throw ERR_INVALID_MSG;
|
||||
if (conn->getProtocol() != pPatternMsg->ProtocolID)
|
||||
throw ERR_MSG_PROTOCOL_ID;
|
||||
this->patternMsg = std::string((char*)pPatternMsg->Data, pPatternMsg->DataSize);
|
||||
if (this->maskMsg.size() != this->patternMsg.size())
|
||||
throw ERR_INVALID_MSG;
|
||||
|
||||
if (pFlowControlMsg) {
|
||||
if (!(conn->getMinMsgLen() < pFlowControlMsg->DataSize || pFlowControlMsg->DataSize < conn->getMaxMsgLen()))
|
||||
throw ERR_INVALID_MSG;
|
||||
if (conn->getProtocol() != pFlowControlMsg->ProtocolID)
|
||||
throw ERR_MSG_PROTOCOL_ID;
|
||||
if (pMaskMsg->TxFlags != pPatternMsg->TxFlags || pMaskMsg->TxFlags != pFlowControlMsg->TxFlags)
|
||||
throw ERR_INVALID_MSG;
|
||||
if(pFlowControlMsg->TxFlags & ~(ISO15765_FRAME_PAD | CAN_29BIT_ID | ISO15765_ADDR_TYPE))
|
||||
throw ERR_INVALID_MSG;
|
||||
if ((pFlowControlMsg->TxFlags & ISO15765_ADDR_TYPE) == ISO15765_ADDR_TYPE) {
|
||||
if(pFlowControlMsg->DataSize != 5)
|
||||
throw ERR_INVALID_MSG;
|
||||
} else {
|
||||
if (pFlowControlMsg->DataSize != 4)
|
||||
throw ERR_INVALID_MSG;
|
||||
}
|
||||
this->flowCtrlMsg = std::string((char*)pFlowControlMsg->Data, pFlowControlMsg->DataSize);
|
||||
if (this->flowCtrlMsg.size() != this->patternMsg.size())
|
||||
throw ERR_INVALID_MSG;
|
||||
this->flags = pFlowControlMsg->TxFlags;
|
||||
}
|
||||
}
|
||||
|
||||
bool J2534MessageFilter::operator ==(const J2534MessageFilter &b) const {
|
||||
if (this->filtertype != b.filtertype) return FALSE;
|
||||
if (this->maskMsg != b.maskMsg) return FALSE;
|
||||
if (this->patternMsg != b.patternMsg) return FALSE;
|
||||
if (this->flowCtrlMsg != b.flowCtrlMsg) return FALSE;
|
||||
if (this->flags != b.flags) return FALSE;
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
FILTER_RESULT J2534MessageFilter::check(const J2534Frame& msg) {
|
||||
bool matches = TRUE;
|
||||
if (msg.Data.size() < this->maskMsg.size()) {
|
||||
matches = FALSE;
|
||||
} else {
|
||||
for (int i = 0; i < this->maskMsg.size(); i++) {
|
||||
if (this->patternMsg[i] != (msg.Data[i] & this->maskMsg[i])) {
|
||||
matches = FALSE;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch (this->filtertype) {
|
||||
case PASS_FILTER:
|
||||
return matches ? FILTER_RESULT_PASS : FILTER_RESULT_NEUTRAL;
|
||||
case BLOCK_FILTER:
|
||||
return matches ? FILTER_RESULT_BLOCK: FILTER_RESULT_NEUTRAL;
|
||||
case FLOW_CONTROL_FILTER:
|
||||
return matches ? FILTER_RESULT_MATCH : FILTER_RESULT_NOMATCH;
|
||||
default:
|
||||
throw std::out_of_range("Filtertype should not be able to be anything but PASS, BLOCK, or FLOW_CONTROL");
|
||||
}
|
||||
}
|
||||
|
||||
std::string J2534MessageFilter::get_flowctrl() {
|
||||
return std::string(this->flowCtrlMsg);
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
#pragma once
|
||||
#include "J2534_v0404.h"
|
||||
#include "J2534Connection.h"
|
||||
#include "J2534Frame.h"
|
||||
|
||||
typedef enum {
|
||||
FILTER_RESULT_BLOCK,
|
||||
FILTER_RESULT_NEUTRAL,
|
||||
FILTER_RESULT_PASS,
|
||||
FILTER_RESULT_NOMATCH = FILTER_RESULT_BLOCK,
|
||||
FILTER_RESULT_MATCH = FILTER_RESULT_PASS,
|
||||
} FILTER_RESULT;
|
||||
|
||||
//Forward declare
|
||||
class J2534Connection;
|
||||
|
||||
/* Represents a J2534 Message Filter created by PassThruStartMsgFilter.
|
||||
|
||||
J2534 uses filters to sort out messages in a simple and sane way. Except for
|
||||
flow control filters. J2534 v04.04 uses filters to manage 'conversations' in
|
||||
protocols that support flow control like ISO15765. The whole solution is a
|
||||
hack, and J2534 v05.00 greatly simplifies this concept. But we are using
|
||||
v04.04 so, here we are.
|
||||
*/
|
||||
class J2534MessageFilter {
|
||||
public:
|
||||
J2534MessageFilter(
|
||||
J2534Connection *const conn,
|
||||
unsigned int filtertype,
|
||||
PASSTHRU_MSG *pMaskMsg,
|
||||
PASSTHRU_MSG *pPatternMsg,
|
||||
PASSTHRU_MSG *pFlowControlMsg
|
||||
);
|
||||
|
||||
bool J2534MessageFilter::operator ==(const J2534MessageFilter &b) const;
|
||||
|
||||
FILTER_RESULT check(const J2534Frame& msg);
|
||||
std::string get_flowctrl();
|
||||
|
||||
unsigned long flags;
|
||||
J2534Connection *const conn;
|
||||
private:
|
||||
unsigned int filtertype;
|
||||
std::string maskMsg;
|
||||
std::string patternMsg;
|
||||
std::string flowCtrlMsg;
|
||||
};
|
|
@ -0,0 +1,428 @@
|
|||
//
|
||||
// Copyright (c) 2015-2016 DashLogic, Inc.
|
||||
// All Rights Reserved.
|
||||
//
|
||||
// http://www.dashlogic.com
|
||||
// sales@dashlogic.com
|
||||
//
|
||||
// Redistribution and use in source and binary forms, with or without
|
||||
// modification, including use for commercial purposes, are permitted
|
||||
// provided that the following conditions are met:
|
||||
//
|
||||
// 1. Redistributions of source code must retain the above copyright
|
||||
// notice, this list of conditions and the following disclaimer.
|
||||
//
|
||||
// 2. 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.
|
||||
//
|
||||
// 3. Neither the name of the copyright holder nor the names of its
|
||||
// contributors may be used to endorse or promote products derived
|
||||
// from this software without specific prior written permission.
|
||||
//
|
||||
// 4. Redistributions of any form whatsoever must retain the following
|
||||
// acknowledgment: 'This product includes software developed by
|
||||
// "DashLogic, Inc." (http://www.dashlogic.com/).'
|
||||
//
|
||||
// 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
|
||||
// HOLDER 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.
|
||||
//
|
||||
|
||||
|
||||
//
|
||||
// Formatting:
|
||||
// Indents: Use tabs only (1 tab per indent)
|
||||
// Tab Size: 4 spaces
|
||||
//
|
||||
// File Revision:
|
||||
// $Rev: 5216 $
|
||||
// $Date: 2016-03-15 09:32:34 -0600 (Tue, 15 Mar 2016) $
|
||||
//
|
||||
|
||||
#pragma once
|
||||
|
||||
#ifdef PANDAJ2534DLL_EXPORTS
|
||||
#define PANDAJ2534DLL_API extern "C" __declspec(dllexport)
|
||||
#else
|
||||
#define PANDAJ2534DLL_API
|
||||
//__declspec(dllimport)
|
||||
#endif
|
||||
|
||||
//
|
||||
// Platform-specific Defines:
|
||||
//
|
||||
// PTAPI: Define this yourself if you want a specific calling
|
||||
// convention or other modifiers on the Pass-Thru API
|
||||
// functions. Typically, on Windows, PTAPI will be defined
|
||||
// as WINAPI, which enables the __stdcall convention.
|
||||
//
|
||||
#define PTAPI __stdcall //WINAPI
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 ProtocolID Values
|
||||
//
|
||||
#define J1850VPW 0x01
|
||||
#define J1850PWM 0x02
|
||||
#define ISO9141 0x03
|
||||
#define ISO14230 0x04
|
||||
#define CAN 0x05
|
||||
#define ISO15765 0x06
|
||||
#define SCI_A_ENGINE 0x07
|
||||
#define SCI_A_TRANS 0x08
|
||||
#define SCI_B_ENGINE 0x09
|
||||
#define SCI_B_TRANS 0x0A
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 ProtocolID Values
|
||||
//
|
||||
#define J1850VPW_PS 0x00008000
|
||||
#define J1850PWM_PS 0x00008001
|
||||
#define ISO9141_PS 0x00008002
|
||||
#define ISO14230_PS 0x00008003
|
||||
#define CAN_PS 0x00008004
|
||||
#define ISO15765_PS 0x00008005
|
||||
#define J2610_PS 0x00008006
|
||||
#define SW_ISO15765_PS 0x00008007
|
||||
#define SW_CAN_PS 0x00008008
|
||||
#define GM_UART_PS 0x00008009
|
||||
#define CAN_CH1 0x00009000
|
||||
#define CAN_CH2 (CAN_CH1 + 1)
|
||||
#define CAN_CH128 (CAN_CH1 + 127)
|
||||
#define J1850VPW_CH1 0x00009080
|
||||
#define J1850VPW_CH2 (J1850VPW_CH1 + 1)
|
||||
#define J1850VPW_CH128 (J1850VPW_CH1 + 127)
|
||||
#define J1850PWM_CH1 0x00009160
|
||||
#define J1850PWM_CH2 (J1850PWM_CH1 + 1)
|
||||
#define J1850PWM_CH128 (J1850PWM_CH1 + 127)
|
||||
#define ISO9141_CH1 0x00009240
|
||||
#define ISO9141_CH2 (ISO9141_CH1 + 1)
|
||||
#define ISO9141_CH128 (ISO9141_CH1 + 127)
|
||||
#define ISO14230_CH1 0x00009320
|
||||
#define ISO14230_CH2 (ISO14230_CH1 + 1)
|
||||
#define ISO14230_CH128 (ISO14230_CH1 + 127)
|
||||
#define ISO15765_CH1 0x00009400
|
||||
#define ISO15765_CH2 (ISO15765_CH1 + 1)
|
||||
#define ISO15765_CH128 (ISO15765_CH1 + 127)
|
||||
#define SW_CAN_CAN_CH1 0x00009480
|
||||
#define SW_CAN_CAN_CH2 (SW_CAN_CAN_CH1 + 1)
|
||||
#define SW_CAN_CAN_CH128 (SW_CAN_CAN_CH1 + 127)
|
||||
#define SW_CAN_ISO15765_CH1 0x00009560
|
||||
#define SW_CAN_ISO15765_CH2 (SW_CAN_ISO15765_CH1 + 1)
|
||||
#define SW_CAN_ISO15765_CH128 (SW_CAN_ISO15765_CH1 + 127)
|
||||
#define J2610_CH1 0x00009640
|
||||
#define J2610_CH2 (J2610_CH1 + 1)
|
||||
#define J2610_CH128 (J2610_CH1 + 127)
|
||||
#define ANALOG_IN_CH1 0x0000C000
|
||||
#define ANALOG_IN_CH2 0x0000C001
|
||||
#define ANALOG_IN_CH32 0x0000C01F
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Error Values
|
||||
//
|
||||
#define STATUS_NOERROR 0x00 // Function call successful.
|
||||
#define ERR_NOT_SUPPORTED 0x01 // Device cannot support requested functionality mandated in J2534. Device is not fully SAE J2534 compliant.
|
||||
#define ERR_INVALID_CHANNEL_ID 0x02 // Invalid ChannelID value.
|
||||
#define ERR_INVALID_PROTOCOL_ID 0x03 // Invalid or unsupported ProtocolID, or there is a resource conflict (i.e. trying to connect to multiple mutually exclusive protocols such as J1850PWM and J1850VPW, or CAN and SCI, etc.).
|
||||
#define ERR_NULL_PARAMETER 0x04 // NULL pointer supplied where a valid pointer is required.
|
||||
#define ERR_INVALID_IOCTL_VALUE 0x05 // Invalid value for Ioctl parameter.
|
||||
#define ERR_INVALID_FLAGS 0x06 // Invalid flag values.
|
||||
#define ERR_FAILED 0x07 // Undefined error, use PassThruGetLastError() for text description.
|
||||
#define ERR_DEVICE_NOT_CONNECTED 0x08 // Unable to communicate with device.
|
||||
#define ERR_TIMEOUT 0x09 // Read or write timeout:
|
||||
// PassThruReadMsgs() - No message available to read or could not read the specified number of messages. The actual number of messages read is placed in <NumMsgs>.
|
||||
// PassThruWriteMsgs() - Device could not write the specified number of messages. The actual number of messages sent on the vehicle network is placed in <NumMsgs>.
|
||||
#define ERR_INVALID_MSG 0x0A // Invalid message structure pointed to by pMsg.
|
||||
#define ERR_INVALID_TIME_INTERVAL 0x0B // Invalid TimeInterval value.
|
||||
#define ERR_EXCEEDED_LIMIT 0x0C // Exceeded maximum number of message IDs or allocated space.
|
||||
#define ERR_INVALID_MSG_ID 0x0D // Invalid MsgID value.
|
||||
#define ERR_DEVICE_IN_USE 0x0E // Device is currently open.
|
||||
#define ERR_INVALID_IOCTL_ID 0x0F // Invalid IoctlID value.
|
||||
#define ERR_BUFFER_EMPTY 0x10 // Protocol message buffer empty, no messages available to read.
|
||||
#define ERR_BUFFER_FULL 0x11 // Protocol message buffer full. All the messages specified may not have been transmitted.
|
||||
#define ERR_BUFFER_OVERFLOW 0x12 // Indicates a buffer overflow occurred and messages were lost.
|
||||
#define ERR_PIN_INVALID 0x13 // Invalid pin number, pin number already in use, or voltage already applied to a different pin.
|
||||
#define ERR_CHANNEL_IN_USE 0x14 // Channel number is currently connected.
|
||||
#define ERR_MSG_PROTOCOL_ID 0x15 // Protocol type in the message does not match the protocol associated with the Channel ID
|
||||
#define ERR_INVALID_FILTER_ID 0x16 // Invalid Filter ID value.
|
||||
#define ERR_NO_FLOW_CONTROL 0x17 // No flow control filter set or matched (for ProtocolID ISO15765 only).
|
||||
#define ERR_NOT_UNIQUE 0x18 // A CAN ID in pPatternMsg or pFlowControlMsg matches either ID in an existing FLOW_CONTROL_FILTER
|
||||
#define ERR_INVALID_BAUDRATE 0x19 // The desired baud rate cannot be achieved within the tolerance specified in SAE J2534-1 Section 6.5
|
||||
#define ERR_INVALID_DEVICE_ID 0x1A // Device ID invalid.
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Connect Flags
|
||||
//
|
||||
#define CAN_29BIT_ID 0x0100
|
||||
#define ISO9141_NO_CHECKSUM 0x0200
|
||||
#define CAN_ID_BOTH 0x0800
|
||||
#define ISO9141_K_LINE_ONLY 0x1000
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Filter Type Values
|
||||
//
|
||||
#define PASS_FILTER 0x00000001
|
||||
#define BLOCK_FILTER 0x00000002
|
||||
#define FLOW_CONTROL_FILTER 0x00000003
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Programming Voltage Pin Numbers
|
||||
//
|
||||
#define AUXILIARY_OUTPUT_PIN 0
|
||||
#define SAE_J1962_CONNECTOR_PIN_6 6
|
||||
#define SAE_J1962_CONNECTOR_PIN_9 9
|
||||
#define SAE_J1962_CONNECTOR_PIN_11 11
|
||||
#define SAE_J1962_CONNECTOR_PIN_12 12
|
||||
#define SAE_J1962_CONNECTOR_PIN_13 13
|
||||
#define SAE_J1962_CONNECTOR_PIN_14 14
|
||||
#define SAE_J1962_CONNECTOR_PIN_15 15 // Short to ground only
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Programming Voltage Values
|
||||
//
|
||||
#define SHORT_TO_GROUND 0xFFFFFFFE
|
||||
#define VOLTAGE_OFF 0xFFFFFFFF
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 API Version Values
|
||||
//
|
||||
#define J2534_APIVER_FEBRUARY_2002 "02.02"
|
||||
#define J2534_APIVER_NOVEMBER_2004 "04.04"
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 IOCTL ID Values
|
||||
//
|
||||
#define GET_CONFIG 0x01 // pInput = SCONFIG_LIST, pOutput = NULL
|
||||
#define SET_CONFIG 0x02 // pInput = SCONFIG_LIST, pOutput = NULL
|
||||
#define READ_VBATT 0x03 // pInput = NULL, pOutput = unsigned long
|
||||
#define FIVE_BAUD_INIT 0x04 // pInput = SBYTE_ARRAY, pOutput = SBYTE_ARRAY
|
||||
#define FAST_INIT 0x05 // pInput = PASSTHRU_MSG, pOutput = PASSTHRU_MSG
|
||||
#define CLEAR_TX_BUFFER 0x07 // pInput = NULL, pOutput = NULL
|
||||
#define CLEAR_RX_BUFFER 0x08 // pInput = NULL, pOutput = NULL
|
||||
#define CLEAR_PERIODIC_MSGS 0x09 // pInput = NULL, pOutput = NULL
|
||||
#define CLEAR_MSG_FILTERS 0x0A // pInput = NULL, pOutput = NULL
|
||||
#define CLEAR_FUNCT_MSG_LOOKUP_TABLE 0x0B // pInput = NULL, pOutput = NULL
|
||||
#define ADD_TO_FUNCT_MSG_LOOKUP_TABLE 0x0C // pInput = SBYTE_ARRAY, pOutput = NULL
|
||||
#define DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE 0x0D // pInput = SBYTE_ARRAY, pOutput = NULL
|
||||
#define READ_PROG_VOLTAGE 0x0E // pInput = NULL, pOutput = unsigned long
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 IOCTL ID Values
|
||||
//
|
||||
#define SW_CAN_HS 0x00008000 // pInput = NULL, pOutput = NULL
|
||||
#define SW_CAN_NS 0x00008001 // pInput = NULL, pOutput = NULL
|
||||
#define SET_POLL_RESPONSE 0x00008002 // pInput = SBYTE_ARRAY, pOutput = NULL
|
||||
#define BECOME_MASTER 0x00008003 // pInput = unsigned char, pOutput = NULL
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Configuration Parameter Values
|
||||
// Default value is enclosed in square brackets "[" and "]"
|
||||
//
|
||||
#define DATA_RATE 0x01 // 5-500000
|
||||
#define LOOPBACK 0x03 // 0 (OFF), 1 (ON) [0]
|
||||
#define NODE_ADDRESS 0x04 // J1850PWM: 0x00-0xFF
|
||||
#define NETWORK_LINE 0x05 // J1850PWM: 0 (BUS_NORMAL), 1 (BUS_PLUS), 2 (BUS_MINUS) [0]
|
||||
#define P1_MIN 0x06 // ISO9141 or ISO14230: Not used by interface
|
||||
#define P1_MAX 0x07 // ISO9141 or ISO14230: 0x1-0xFFFF (.5 ms per bit) [40 (20ms)]
|
||||
#define P2_MIN 0x08 // ISO9141 or ISO14230: Not used by interface
|
||||
#define P2_MAX 0x09 // ISO9141 or ISO14230: Not used by interface
|
||||
#define P3_MIN 0x0A // ISO9141 or ISO14230: 0x0-0xFFFF (.5 ms per bit) [110 (55ms)]
|
||||
#define P3_MAX 0x0B // ISO9141 or ISO14230: Not used by interface
|
||||
#define P4_MIN 0x0C // ISO9141 or ISO14230: 0x0-0xFFFF (.5 ms per bit) [10 (5ms)]
|
||||
#define P4_MAX 0x0D // ISO9141 or ISO14230: Not used by interface
|
||||
#define W0 0x19 // ISO9141: 0x0-0xFFFF (1 ms per bit) [300]
|
||||
#define W1 0x0E // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [300]
|
||||
#define W2 0x0F // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [20]
|
||||
#define W3 0x10 // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [20]
|
||||
#define W4 0x11 // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [50]
|
||||
#define W5 0x12 // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [300]
|
||||
#define TIDLE 0x13 // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [300]
|
||||
#define TINIL 0x14 // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [25]
|
||||
#define TWUP 0x15 // ISO9141 or ISO14230: 0x0-0xFFFF (1 ms per bit) [50]
|
||||
#define PARITY 0x16 // ISO9141 or ISO14230: 0 (NO_PARITY), 1 (ODD_PARITY), 2 (EVEN_PARITY) [0]
|
||||
#define BIT_SAMPLE_POINT 0x17 // CAN: 0-100 (1% per bit) [80]
|
||||
#define SYNC_JUMP_WIDTH 0x18 // CAN: 0-100 (1% per bit) [15]
|
||||
#define T1_MAX 0x1A // SCI: 0x0-0xFFFF (1 ms per bit) [20]
|
||||
#define T2_MAX 0x1B // SCI: 0x0-0xFFFF (1 ms per bit) [100]
|
||||
#define T3_MAX 0x24 // SCI: 0x0-0xFFFF (1 ms per bit) [50]
|
||||
#define T4_MAX 0x1C // SCI: 0x0-0xFFFF (1 ms per bit) [20]
|
||||
#define T5_MAX 0x1D // SCI: 0x0-0xFFFF (1 ms per bit) [100]
|
||||
#define ISO15765_BS 0x1E // ISO15765: 0x0-0xFF [0]
|
||||
#define ISO15765_STMIN 0x1F // ISO15765: 0x0-0xFF [0]
|
||||
#define ISO15765_BS_TX 0x22 // ISO15765: 0x0-0xFF,0xFFFF [0xFFFF]
|
||||
#define ISO15765_STMIN_TX 0x23 // ISO15765: 0x0-0xFF,0xFFFF [0xFFFF]
|
||||
#define DATA_BITS 0x20 // ISO9141 or ISO14230: 0 (8 data bits), 1 (7 data bits) [0]
|
||||
#define FIVE_BAUD_MOD 0x21 // ISO9141 or ISO14230: 0 (ISO 9141-2/14230-4), 1 (Inv KB2), 2 (Inv Addr), 3 (ISO 9141) [0]
|
||||
#define ISO15765_WFT_MAX 0x25 // ISO15765: 0x0-0xFF [0]
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 Configuration Parameter Values
|
||||
// Default value is enclosed in square brackets "[" and "]"
|
||||
//
|
||||
#define CAN_MIXED_FORMAT 0x00008000 // See #defines below. [0]
|
||||
#define J1962_PINS 0x00008001 // 0xPPSS PP: 0x00-0x10 SS: 0x00-0x10 PP!=SS, except 0x0000. Exclude pins 4, 5, and 16. [0]
|
||||
#define SW_CAN_HS_DATA_RATE 0x00008010 // SWCAN: 5-500000 [83333]
|
||||
#define SW_CAN_SPEEDCHANGE_ENABLE 0x00008011 // SWCAN: 0 (DISABLE_SPDCHANGE), 1 (ENABLE_SPDCHANGE) [0]
|
||||
#define SW_CAN_RES_SWITCH 0x00008012 // SWCAN: 0 (DISCONNECT_RESISTOR), 1 (CONNECT_RESISTOR), 2 (AUTO_ RESISTOR) [0]
|
||||
#define ACTIVE_CHANNELS 0x00008020 // ANALOG: 0-0xFFFFFFFF
|
||||
#define SAMPLE_RATE 0x00008021 // ANALOG: 0-0xFFFFFFFF [0] (high bit changes meaning from samples/sec to seconds/sample)
|
||||
#define SAMPLES_PER_READING 0x00008022 // ANALOG: 1-0xFFFFFFFF [1]
|
||||
#define READINGS_PER_MSG 0x00008023 // ANALOG: 1-0x00000408 (1 - 1032) [1]
|
||||
#define AVERAGING_METHOD 0x00008024 // ANALOG: 0-0xFFFFFFFF [0]
|
||||
#define SAMPLE_RESOLUTION 0x00008025 // ANALOG READ-ONLY: 0x1-0x20 (1 - 32)
|
||||
#define INPUT_RANGE_LOW 0x00008026 // ANALOG READ-ONLY: 0x80000000-0x7FFFFFFF (-2147483648-2147483647)
|
||||
#define INPUT_RANGE_HIGH 0x00008027 // ANALOG READ-ONLY: 0x80000000-0x7FFFFFFF (-2147483648-2147483647)
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 Mixed-Mode/Format CAN Definitions
|
||||
//
|
||||
#define CAN_MIXED_FORMAT_OFF 0 // Messages will be treated as ISO 15765 ONLY.
|
||||
#define CAN_MIXED_FORMAT_ON 1 // Messages will be treated as either ISO 15765 or an unformatted CAN frame.
|
||||
#define CAN_MIXED_FORMAT_ALL_FRAMES 2 // Messages will be treated as ISO 15765, an unformatted CAN frame, or both.
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 Analog Channel Averaging Method Definitions
|
||||
//
|
||||
#define SIMPLE_AVERAGE 0x00000000 // Simple arithmetic mean
|
||||
#define MAX_LIMIT_AVERAGE 0x00000001 // Choose the biggest value
|
||||
#define MIN_LIMIT_AVERAGE 0x00000002 // Choose the lowest value
|
||||
#define MEDIAN_AVERAGE 0x00000003 // Choose arithmetic median
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 RxStatus Definitions
|
||||
//
|
||||
#define TX_MSG_TYPE 0x0001
|
||||
#define START_OF_MESSAGE 0x0002
|
||||
#define RX_BREAK 0x0004
|
||||
#define TX_INDICATION 0x0008
|
||||
#define ISO15765_PADDING_ERROR 0x0010
|
||||
#define ISO15765_ADDR_TYPE 0x0080
|
||||
//#define CAN_29BIT_ID 0x0100 // Defined above
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 RxStatus Definitions
|
||||
//
|
||||
#define SW_CAN_HV_RX 0x00010000 // SWCAN Channels Only
|
||||
#define SW_CAN_HS_RX 0x00020000 // SWCAN Channels Only
|
||||
#define SW_CAN_NS_RX 0x00040000 // SWCAN Channels Only
|
||||
#define OVERFLOW_ 0x00010000 // Analog Input Channels Only
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 TxFlags Definitions
|
||||
//
|
||||
#define ISO15765_FRAME_PAD 0x0040
|
||||
//#define ISO15765_ADDR_TYPE 0x0080 // Defined above
|
||||
//#define CAN_29BIT_ID 0x0100 // Defined above
|
||||
#define WAIT_P3_MIN_ONLY 0x0200
|
||||
#define SCI_MODE 0x400000
|
||||
#define SCI_TX_VOLTAGE 0x800000
|
||||
|
||||
|
||||
//
|
||||
// J2534-2 TxFlags Definitions
|
||||
//
|
||||
#define SW_CAN_HV_TX 0x00000400
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Structure Definitions
|
||||
//
|
||||
typedef struct
|
||||
{
|
||||
unsigned long Parameter; // Name of parameter
|
||||
unsigned long Value; // Value of the parameter
|
||||
} SCONFIG;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long NumOfParams; // Number of SCONFIG elements
|
||||
SCONFIG* ConfigPtr; // Array of SCONFIG
|
||||
} SCONFIG_LIST;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long NumOfBytes; // Number of bytes in the array
|
||||
unsigned char* BytePtr; // Array of bytes
|
||||
} SBYTE_ARRAY;
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
unsigned long ProtocolID;
|
||||
unsigned long RxStatus;
|
||||
unsigned long TxFlags;
|
||||
unsigned long Timestamp;
|
||||
unsigned long DataSize;
|
||||
unsigned long ExtraDataIndex;
|
||||
unsigned char Data[4128];
|
||||
} PASSTHRU_MSG;
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Function Prototypes
|
||||
//
|
||||
PANDAJ2534DLL_API long PTAPI PassThruOpen(void *pName, unsigned long *pDeviceID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruClose(unsigned long DeviceID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long BaudRate, unsigned long *pChannelID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruDisconnect(unsigned long ChannelID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruReadMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruWriteMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStartPeriodicMsg(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStopPeriodicMsg(unsigned long ChannelID, unsigned long MsgID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStartMsgFilter(unsigned long ChannelID, unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg, PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStopMsgFilter(unsigned long ChannelID, unsigned long FilterID);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruSetProgrammingVoltage(unsigned long DeviceID, unsigned long PinNumber, unsigned long Voltage);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruReadVersion(unsigned long DeviceID, char *pFirmwareVersion, char *pDllVersion, char *pApiVersion);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruGetLastError(char *pErrorDescription);
|
||||
PANDAJ2534DLL_API long PTAPI PassThruIoctl(unsigned long ChannelID, unsigned long IoctlID, void *pInput, void *pOutput);
|
||||
|
||||
|
||||
//
|
||||
// J2534-1 v04.04 Function Typedefs
|
||||
// These function typedefs allow simpler use of the J2534 API by
|
||||
// allowing you to do things like this:
|
||||
// PTCONNECT pPassThruConnectFunc = GetProcAddress(hModule, "PassThruConnect");
|
||||
// if (pPassThruConnectFunc == NULL)
|
||||
// return FALSE;
|
||||
// pPassThruConnectFunc(DeviceID, CAN, CAN_29BIT_ID, 500000, &ChannelID);
|
||||
//
|
||||
typedef long (PTAPI *PTOPEN)(void *pName, unsigned long *pDeviceID);
|
||||
typedef long (PTAPI *PTCLOSE)(unsigned long DeviceID);
|
||||
typedef long (PTAPI *PTCONNECT)(unsigned long DeviceID, unsigned long ProtocolID, unsigned long Flags, unsigned long BaudRate, unsigned long *pChannelID);
|
||||
typedef long (PTAPI *PTDISCONNECT)(unsigned long ChannelID);
|
||||
typedef long (PTAPI *PTREADMSGS)(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
|
||||
typedef long (PTAPI *PTWRITEMSGS)(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout);
|
||||
typedef long (PTAPI *PTSTARTPERIODICMSG)(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval);
|
||||
typedef long (PTAPI *PTSTOPPERIODICMSG)(unsigned long ChannelID, unsigned long MsgID);
|
||||
typedef long (PTAPI *PTSTARTMSGFILTER)(unsigned long ChannelID, unsigned long FilterType, PASSTHRU_MSG *pMaskMsg, PASSTHRU_MSG *pPatternMsg, PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID);
|
||||
typedef long (PTAPI *PTSTOPMSGFILTER)(unsigned long ChannelID, unsigned long FilterID);
|
||||
typedef long (PTAPI *PTSETPROGRAMMINGVOLTAGE)(unsigned long DeviceID, unsigned long PinNumber, unsigned long Voltage);
|
||||
typedef long (PTAPI *PTREADVERSION)(unsigned long DeviceID, char *pFirmwareVersion, char *pDllVersion, char *pApiVersion);
|
||||
typedef long (PTAPI *PTGETLASTERROR)(char *pErrorDescription);
|
||||
typedef long (PTAPI *PTIOCTL)(unsigned long ChannelID, unsigned long IoctlID, void *pInput, void *pOutput);
|
|
@ -0,0 +1,30 @@
|
|||
#include "stdafx.h"
|
||||
#include "MessagePeriodic.h"
|
||||
#include "J2534Connection.h"
|
||||
|
||||
MessagePeriodic::MessagePeriodic(
|
||||
std::chrono::microseconds delay,
|
||||
std::shared_ptr<MessageTx> msg
|
||||
) : Action(msg->connection, delay), msg(msg), runyet(FALSE), active(TRUE) { };
|
||||
|
||||
void MessagePeriodic::execute() {
|
||||
if (!this->active) return;
|
||||
if (this->runyet) {
|
||||
if (msg->isFinished()) {
|
||||
msg->reset();
|
||||
msg->execute();
|
||||
}
|
||||
} else {
|
||||
this->runyet = TRUE;
|
||||
msg->execute();
|
||||
}
|
||||
|
||||
if (auto conn_sp = this->connection.lock()) {
|
||||
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
|
||||
//Scheduling must be relative to now incase there was a long stall that
|
||||
//would case it to be super far behind and try to catch up forever.
|
||||
this->scheduleImmediateDelay();
|
||||
panda_dev_sp->insertActionIntoTaskList(shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#include "Action.h"
|
||||
#include "MessageTx.h"
|
||||
|
||||
class J2534Connection;
|
||||
|
||||
/* A message that is resent on a given period. Created with calls to PassThruStartPeriodicMessage.
|
||||
|
||||
Instead of making each J2534 protocol implementation have to implement periodic message
|
||||
functionality, this class takes a message to be sent, and passes along the execute call
|
||||
to the message, then reschedules itself.
|
||||
*/
|
||||
class MessagePeriodic : public Action, public std::enable_shared_from_this<Action>
|
||||
{
|
||||
public:
|
||||
MessagePeriodic(
|
||||
std::chrono::microseconds delay,
|
||||
std::shared_ptr<MessageTx> msg
|
||||
);
|
||||
|
||||
virtual void execute();
|
||||
|
||||
void cancel() {
|
||||
this->active = FALSE;
|
||||
}
|
||||
|
||||
protected:
|
||||
std::shared_ptr<MessageTx> msg;
|
||||
|
||||
private:
|
||||
BOOL runyet;
|
||||
BOOL active;
|
||||
};
|
|
@ -0,0 +1,61 @@
|
|||
#pragma once
|
||||
|
||||
class MessageRx
|
||||
{
|
||||
public:
|
||||
MessageRx(
|
||||
unsigned long size,
|
||||
std::string piece,
|
||||
unsigned long rxFlags,
|
||||
std::shared_ptr<J2534MessageFilter> filter
|
||||
) : expected_size(size & 0xFFF), flags(rxFlags) {
|
||||
msg.reserve(expected_size);
|
||||
msg = piece;
|
||||
next_part = 1;
|
||||
};
|
||||
|
||||
bool rx_add_frame(uint8_t pci_byte, unsigned int max_packet_size, const std::string piece) {
|
||||
if ((pci_byte & 0x0F) != this->next_part) {
|
||||
//TODO: Maybe this should instantly fail the transaction.
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
this->next_part = (this->next_part + 1) % 0x10;
|
||||
unsigned int payload_len = min(expected_size - msg.size(), max_packet_size);
|
||||
if (piece.size() < payload_len) {
|
||||
//A frame was received that could have held more data.
|
||||
//No examples of this protocol show that happening, so
|
||||
//it will be assumed that it is grounds to reset rx.
|
||||
return FALSE;
|
||||
}
|
||||
msg += piece.substr(0, payload_len);
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
unsigned int bytes_remaining() {
|
||||
return this->expected_size - this->msg.size();
|
||||
}
|
||||
|
||||
bool is_ready() {
|
||||
return this->msg.size() == this->expected_size;
|
||||
}
|
||||
|
||||
bool flush_result(std::string& final_msg) {
|
||||
if (this->msg.size() == this->expected_size) {
|
||||
final_msg = this->msg;
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
uint8_t getNextConsecutiveFrameId() {
|
||||
return this->next_part++;
|
||||
}
|
||||
|
||||
std::weak_ptr<J2534MessageFilter> filter;
|
||||
unsigned long flags;
|
||||
unsigned long expected_size;
|
||||
std::string msg;
|
||||
unsigned char next_part;
|
||||
};
|
|
@ -0,0 +1,25 @@
|
|||
#pragma once
|
||||
#include "Action.h"
|
||||
#include "J2534Frame.h"
|
||||
|
||||
class J2534Connection;
|
||||
|
||||
class MessageTx : public Action, public std::enable_shared_from_this<MessageTx>
|
||||
{
|
||||
public:
|
||||
MessageTx(
|
||||
std::weak_ptr<J2534Connection> connection_in,
|
||||
PASSTHRU_MSG& to_send
|
||||
) : Action(connection_in), fullmsg(to_send) { };
|
||||
|
||||
virtual BOOL checkTxReceipt(J2534Frame frame) = 0;
|
||||
|
||||
virtual BOOL isFinished() = 0;
|
||||
|
||||
virtual BOOL txReady() = 0;
|
||||
|
||||
virtual void reset() = 0;
|
||||
|
||||
protected:
|
||||
J2534Frame fullmsg;
|
||||
};
|
|
@ -0,0 +1,43 @@
|
|||
#include "stdafx.h"
|
||||
#include "J2534Connection.h"
|
||||
#include "MessageTxTimeout.h"
|
||||
|
||||
MessageTxTimeoutable::MessageTxTimeoutable(
|
||||
std::weak_ptr<J2534Connection> connection,
|
||||
PASSTHRU_MSG& to_send
|
||||
) : MessageTx(connection, to_send), recvCount(0) { };
|
||||
|
||||
void MessageTxTimeoutable::scheduleTimeout(std::chrono::microseconds timeoutus) {
|
||||
if (auto conn_sp = this->connection.lock()) {
|
||||
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
|
||||
auto timeoutobj = std::make_shared<MessageTxTimeout>(std::static_pointer_cast<MessageTxTimeoutable>(shared_from_this()), timeoutus);
|
||||
panda_dev_sp->scheduleAction(std::static_pointer_cast<Action>(timeoutobj), TRUE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageTxTimeoutable::scheduleTimeout(unsigned long timeoutus) {
|
||||
scheduleTimeout(std::chrono::microseconds(timeoutus));
|
||||
}
|
||||
|
||||
|
||||
|
||||
MessageTxTimeout::MessageTxTimeout(
|
||||
std::shared_ptr<MessageTxTimeoutable> msg,
|
||||
std::chrono::microseconds timeout
|
||||
) : Action(msg->connection), msg(msg), lastRecvCount(msg->getRecvCount()) {
|
||||
delay = timeout;
|
||||
};
|
||||
|
||||
MessageTxTimeout::MessageTxTimeout(
|
||||
std::shared_ptr<MessageTxTimeoutable> msg,
|
||||
unsigned long timeout
|
||||
) : MessageTxTimeout(msg, std::chrono::microseconds(timeout * 1000)) { };
|
||||
|
||||
void MessageTxTimeout::execute() {
|
||||
if (auto msg_sp = this->msg.lock()) {
|
||||
if (msg_sp->getRecvCount() == this->lastRecvCount) {
|
||||
msg_sp->onTimeout();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,52 @@
|
|||
#pragma once
|
||||
#include "Action.h"
|
||||
#include "MessageTx.h"
|
||||
|
||||
class MessageTxTimeout;
|
||||
|
||||
/* A special type of MessageTx for multipart messages that supports being canceled with a timeout.*/
|
||||
class MessageTxTimeoutable : public MessageTx
|
||||
{
|
||||
public:
|
||||
MessageTxTimeoutable(
|
||||
std::weak_ptr<J2534Connection> connection,
|
||||
PASSTHRU_MSG& to_send
|
||||
);
|
||||
|
||||
unsigned long getRecvCount() {
|
||||
return recvCount;
|
||||
}
|
||||
|
||||
virtual void onTimeout() = 0;
|
||||
|
||||
protected:
|
||||
unsigned long recvCount;
|
||||
|
||||
void scheduleTimeout(std::chrono::microseconds timeoutus);
|
||||
|
||||
void scheduleTimeout(unsigned long timeoutus);
|
||||
};
|
||||
|
||||
|
||||
/* An Action that cancels MessageTxTimeoutableif the Timeout Actoin executes
|
||||
before the MessageTxTimeoutableif renews its timeout.
|
||||
*/
|
||||
class MessageTxTimeout : public Action
|
||||
{
|
||||
public:
|
||||
MessageTxTimeout(
|
||||
std::shared_ptr<MessageTxTimeoutable> msg,
|
||||
std::chrono::microseconds timeout
|
||||
);
|
||||
|
||||
MessageTxTimeout(
|
||||
std::shared_ptr<MessageTxTimeoutable> msg,
|
||||
unsigned long timeout
|
||||
);
|
||||
|
||||
virtual void execute();
|
||||
|
||||
private:
|
||||
std::weak_ptr<MessageTxTimeoutable> msg;
|
||||
unsigned long lastRecvCount;
|
||||
};
|
|
@ -0,0 +1,44 @@
|
|||
#include "stdafx.h"
|
||||
#include "MessageTx_CAN.h"
|
||||
#include "J2534Connection_CAN.h"
|
||||
|
||||
MessageTx_CAN::MessageTx_CAN(
|
||||
std::shared_ptr<J2534Connection> connection_in,
|
||||
PASSTHRU_MSG& to_send
|
||||
) : MessageTx(connection_in, to_send), sentyet(FALSE), txInFlight(FALSE) {};
|
||||
|
||||
void MessageTx_CAN::execute() {
|
||||
uint32_t addr = ((uint8_t)fullmsg.Data[0]) << 24 | ((uint8_t)fullmsg.Data[1]) << 16 |
|
||||
((uint8_t)fullmsg.Data[2]) << 8 | ((uint8_t)fullmsg.Data[3]);
|
||||
|
||||
if (auto conn_sp = std::static_pointer_cast<J2534Connection_CAN>(this->connection.lock())) {
|
||||
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
|
||||
auto payload = fullmsg.Data.substr(4);
|
||||
if (panda_dev_sp->panda->can_send(addr, check_bmask(this->fullmsg.TxFlags, CAN_29BIT_ID),
|
||||
(const uint8_t*)payload.c_str(), (uint8_t)payload.size(), panda::PANDA_CAN1) == FALSE) {
|
||||
return;
|
||||
}
|
||||
this->txInFlight = TRUE;
|
||||
this->sentyet = TRUE;
|
||||
panda_dev_sp->txMsgsAwaitingEcho.push(shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Returns TRUE if receipt is consumed by the msg, FALSE otherwise.
|
||||
BOOL MessageTx_CAN::checkTxReceipt(J2534Frame frame) {
|
||||
if (txReady()) return FALSE;
|
||||
if (frame.Data == fullmsg.Data && ((this->fullmsg.TxFlags & CAN_29BIT_ID) == (frame.RxStatus & CAN_29BIT_ID))) {
|
||||
txInFlight = FALSE;
|
||||
if (auto conn_sp = std::static_pointer_cast<J2534Connection_CAN>(this->connection.lock()))
|
||||
if (conn_sp->loopback)
|
||||
conn_sp->addMsgToRxQueue(frame);
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
void MessageTx_CAN::reset() {
|
||||
sentyet = FALSE;
|
||||
txInFlight = FALSE;
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include "MessageTx.h"
|
||||
|
||||
class J2534Connection;
|
||||
|
||||
class MessageTx_CAN : public MessageTx
|
||||
{
|
||||
public:
|
||||
MessageTx_CAN(
|
||||
std::shared_ptr<J2534Connection> connection_in,
|
||||
PASSTHRU_MSG& to_send
|
||||
);
|
||||
|
||||
virtual void execute();
|
||||
|
||||
//Returns TRUE if receipt is consumed by the msg, FALSE otherwise.
|
||||
virtual BOOL checkTxReceipt(J2534Frame frame);
|
||||
|
||||
virtual BOOL isFinished() {
|
||||
return !txInFlight && sentyet;
|
||||
};
|
||||
|
||||
virtual BOOL txReady() {
|
||||
return !sentyet;
|
||||
};
|
||||
|
||||
virtual void reset();
|
||||
|
||||
private:
|
||||
BOOL sentyet;
|
||||
BOOL txInFlight;
|
||||
};
|
|
@ -0,0 +1,180 @@
|
|||
#include "stdafx.h"
|
||||
#include "MessageTx_ISO15765.h"
|
||||
#include "constants_ISO15765.h"
|
||||
|
||||
//in microseconsa
|
||||
#define TIMEOUT_FC 250000 //Flow Control
|
||||
#define TIMEOUT_CF 250000 //Consecutive Frames
|
||||
|
||||
MessageTx_ISO15765::MessageTx_ISO15765(
|
||||
std::shared_ptr<J2534Connection> connection_in,
|
||||
PASSTHRU_MSG& to_send,
|
||||
std::shared_ptr<J2534MessageFilter> filter
|
||||
) : MessageTxTimeoutable(connection_in, to_send), filter(filter), frames_sent(0),
|
||||
consumed_count(0), txInFlight(FALSE), sendAll(FALSE), block_size(0), numWaitFrames(0), didtimeout(FALSE), issuspended(FALSE){
|
||||
|
||||
CANid = ((uint8_t)fullmsg.Data[0]) << 24 | ((uint8_t)fullmsg.Data[1]) << 16 |
|
||||
((uint8_t)fullmsg.Data[2]) << 8 | ((uint8_t)fullmsg.Data[3]);
|
||||
|
||||
payload = fullmsg.Data.substr(addressLength());
|
||||
|
||||
if (check_bmask(fullmsg.TxFlags, ISO15765_ADDR_TYPE))
|
||||
data_prefix = fullmsg.Data[4];
|
||||
|
||||
if (payload.size() <= (7 - data_prefix.size())) {
|
||||
isMultipart = FALSE;
|
||||
auto framepayload = data_prefix + std::string(1, (char)payload.size()) + payload;
|
||||
if (check_bmask(this->fullmsg.TxFlags, ISO15765_FRAME_PAD))
|
||||
framepayload += std::string(8 - framepayload.size(), '\x00');
|
||||
framePayloads.push_back(framepayload);
|
||||
} else {
|
||||
isMultipart = TRUE;
|
||||
unsigned long first_payload_len = 6 - data_prefix.size(); // 5 or 6
|
||||
std::string framepayload = data_prefix +
|
||||
(char)(0x10 | ((payload.size() >> 8) & 0xF)) +
|
||||
(char)(payload.size() & 0xFF) +
|
||||
payload.substr(0, first_payload_len);
|
||||
framePayloads.push_back(framepayload);
|
||||
|
||||
unsigned int pktnum = 1;
|
||||
uint8_t CFDatSize = 7 - data_prefix.size();
|
||||
while (TRUE) {
|
||||
framepayload = data_prefix + (char)(0x20 | (pktnum % 0x10)) +
|
||||
payload.substr(first_payload_len + (CFDatSize * (pktnum-1)), CFDatSize);
|
||||
|
||||
if (check_bmask(this->fullmsg.TxFlags, ISO15765_FRAME_PAD))
|
||||
framepayload += std::string(8 - framepayload.size(), '\x00');
|
||||
framePayloads.push_back(framepayload);
|
||||
if (first_payload_len + (CFDatSize * pktnum) >= payload.size()) break;
|
||||
pktnum++;
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
unsigned int MessageTx_ISO15765::addressLength() {
|
||||
return check_bmask(fullmsg.TxFlags, ISO15765_ADDR_TYPE) ? 5 : 4;
|
||||
}
|
||||
|
||||
void MessageTx_ISO15765::execute() {
|
||||
if (didtimeout || issuspended) return;
|
||||
if (this->frames_sent >= this->framePayloads.size()) return;
|
||||
if (block_size == 0 && !sendAll && this->frames_sent > 0) return;
|
||||
if (block_size > 0 && !sendAll) block_size--;
|
||||
|
||||
if (auto conn_sp = this->connection.lock()) {
|
||||
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
|
||||
auto& outFramePayload = this->framePayloads[this->frames_sent];
|
||||
if (panda_dev_sp->panda->can_send(this->CANid, check_bmask(this->fullmsg.TxFlags, CAN_29BIT_ID),
|
||||
(const uint8_t*)outFramePayload.c_str(), (uint8_t)outFramePayload.size(), panda::PANDA_CAN1) == FALSE) {
|
||||
return;
|
||||
}
|
||||
|
||||
this->txInFlight = TRUE;
|
||||
this->frames_sent++;
|
||||
panda_dev_sp->txMsgsAwaitingEcho.push(shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Returns TRUE if receipt is consumed by the msg, FALSE otherwise.
|
||||
BOOL MessageTx_ISO15765::checkTxReceipt(J2534Frame frame) {
|
||||
if (!txInFlight) return FALSE;
|
||||
if (frame.Data.size() >= addressLength() + 1 && (frame.Data[addressLength()] & 0xF0) == FRAME_FLOWCTRL) return FALSE;
|
||||
|
||||
if (frame.Data == fullmsg.Data.substr(0, 4) + framePayloads[frames_sent - 1] &&
|
||||
((this->fullmsg.TxFlags & CAN_29BIT_ID) == (frame.RxStatus & CAN_29BIT_ID))) { //Check receipt is expected
|
||||
txInFlight = FALSE; //Received the expected receipt. Allow another msg to be sent.
|
||||
|
||||
if (this->recvCount == 0 && this->framePayloads.size() > 1)
|
||||
scheduleTimeout(TIMEOUT_FC);
|
||||
|
||||
if (frames_sent == framePayloads.size()) { //Check message done
|
||||
if (auto conn_sp = std::static_pointer_cast<J2534Connection_ISO15765>(this->connection.lock())) {
|
||||
unsigned long flags = (filter == nullptr) ? fullmsg.TxFlags : this->filter->flags;
|
||||
|
||||
J2534Frame outframe(ISO15765);
|
||||
outframe.Timestamp = frame.Timestamp;
|
||||
outframe.RxStatus = TX_INDICATION | (flags & (ISO15765_ADDR_TYPE | CAN_29BIT_ID));
|
||||
outframe.Data = frame.Data.substr(0, addressLength());
|
||||
conn_sp->addMsgToRxQueue(outframe);
|
||||
|
||||
if (conn_sp->loopback) {
|
||||
J2534Frame outframe(ISO15765);
|
||||
outframe.Timestamp = frame.Timestamp;
|
||||
outframe.RxStatus = TX_MSG_TYPE | (flags & (ISO15765_ADDR_TYPE | CAN_29BIT_ID));
|
||||
outframe.Data = this->fullmsg.Data;
|
||||
conn_sp->addMsgToRxQueue(outframe);
|
||||
}
|
||||
|
||||
} //TODO what if fails
|
||||
} else {
|
||||
//Restart timeout if we are waiting for a flow control frame.
|
||||
//FC frames are required when we are not sending all, the
|
||||
//current block_size batch has not been sent, a FC message has
|
||||
//already been received (differentiating from first frame), the
|
||||
//message is not finished, and there is more than one frame in
|
||||
//the message.
|
||||
if (block_size == 0 && recvCount != 0 && !sendAll && !this->isFinished() && this->framePayloads.size() > 1)
|
||||
scheduleTimeout(TIMEOUT_CF);
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
BOOL MessageTx_ISO15765::isFinished() {
|
||||
return this->frames_sent == this->framePayloads.size() && !txInFlight;
|
||||
}
|
||||
|
||||
BOOL MessageTx_ISO15765::txReady() {
|
||||
return block_size > 0 || sendAll || this->frames_sent == 0;
|
||||
}
|
||||
|
||||
void MessageTx_ISO15765::reset() {
|
||||
frames_sent = 0;
|
||||
consumed_count = 0;
|
||||
block_size = 0;
|
||||
txInFlight = FALSE;
|
||||
sendAll = FALSE;
|
||||
numWaitFrames = 0;
|
||||
didtimeout = FALSE;
|
||||
}
|
||||
|
||||
void MessageTx_ISO15765::onTimeout() {
|
||||
didtimeout = TRUE;
|
||||
if (auto conn_sp = std::static_pointer_cast<J2534Connection_ISO15765>(this->connection.lock())) {
|
||||
if (auto panda_dev_sp = conn_sp->getPandaDev()) {
|
||||
panda_dev_sp->removeConnectionTopAction(conn_sp, shared_from_this());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void MessageTx_ISO15765::flowControlContinue(uint8_t block_size, std::chrono::microseconds separation_time) {
|
||||
this->issuspended = FALSE;
|
||||
this->block_size = block_size;
|
||||
this->delay = separation_time;
|
||||
this->sendAll = block_size == 0;
|
||||
this->recvCount++;
|
||||
}
|
||||
|
||||
void MessageTx_ISO15765::flowControlWait(unsigned long N_WFTmax) {
|
||||
this->issuspended = TRUE;
|
||||
this->recvCount++;
|
||||
this->numWaitFrames++;
|
||||
this->sendAll = FALSE;
|
||||
this->block_size = block_size;
|
||||
this->delay = std::chrono::microseconds(0);
|
||||
//Docs are vague on if 0 means NO WAITS ALLOWED or NO LIMIT TO WAITS.
|
||||
//It is less likely to cause issue if NO LIMIT is assumed.
|
||||
if (N_WFTmax > 0 && this->numWaitFrames > N_WFTmax) {
|
||||
this->onTimeout(); //Trigger self destruction of message.
|
||||
} else {
|
||||
scheduleTimeout(TIMEOUT_FC);
|
||||
}
|
||||
}
|
||||
|
||||
void MessageTx_ISO15765::flowControlAbort() {
|
||||
this->recvCount++; //Invalidate future timeout actions.
|
||||
this->onTimeout(); //Trigger self destruction of message.
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
#pragma once
|
||||
#include "MessageTxTimeout.h"
|
||||
#include "J2534Connection_ISO15765.h"
|
||||
|
||||
class J2534Connection_ISO15765;
|
||||
|
||||
/**
|
||||
A specialized message type that can handle J2534 single and multi
|
||||
frame (with flow control) writes.
|
||||
*/
|
||||
class MessageTx_ISO15765 : public MessageTxTimeoutable
|
||||
{
|
||||
public:
|
||||
MessageTx_ISO15765(
|
||||
std::shared_ptr<J2534Connection> connection,
|
||||
PASSTHRU_MSG& to_send,
|
||||
std::shared_ptr<J2534MessageFilter> filter
|
||||
);
|
||||
|
||||
unsigned int addressLength();
|
||||
|
||||
virtual void execute();
|
||||
|
||||
virtual BOOL checkTxReceipt(J2534Frame frame);
|
||||
|
||||
virtual BOOL isFinished();
|
||||
|
||||
virtual BOOL txReady();
|
||||
|
||||
virtual void reset();
|
||||
|
||||
virtual void onTimeout();
|
||||
|
||||
//Functions for ISO15765 flow control
|
||||
|
||||
void MessageTx_ISO15765::flowControlContinue(uint8_t block_size, std::chrono::microseconds separation_time);
|
||||
void MessageTx_ISO15765::flowControlWait(unsigned long N_WFTmax);
|
||||
void MessageTx_ISO15765::flowControlAbort();
|
||||
|
||||
std::shared_ptr<J2534MessageFilter> filter;
|
||||
unsigned long frames_sent;
|
||||
unsigned long consumed_count;
|
||||
uint8_t block_size;
|
||||
unsigned long CANid;
|
||||
std::string data_prefix;
|
||||
std::string payload;
|
||||
BOOL isMultipart;
|
||||
std::vector<std::string> framePayloads;
|
||||
BOOL txInFlight;
|
||||
BOOL sendAll;
|
||||
unsigned int numWaitFrames;
|
||||
BOOL didtimeout;
|
||||
BOOL issuspended;
|
||||
};
|
|
@ -0,0 +1,214 @@
|
|||
#include "stdafx.h"
|
||||
#include "PandaJ2534Device.h"
|
||||
#include "J2534Frame.h"
|
||||
|
||||
PandaJ2534Device::PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda) : txInProgress(FALSE) {
|
||||
this->panda = std::move(new_panda);
|
||||
|
||||
this->panda->set_esp_power(FALSE);
|
||||
this->panda->set_safety_mode(panda::SAFETY_ALLOUTPUT);
|
||||
this->panda->set_can_loopback(FALSE);
|
||||
this->panda->set_alt_setting(1);
|
||||
|
||||
DWORD canListenThreadID;
|
||||
this->thread_kill_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
this->can_thread_handle = CreateThread(NULL, 0, _can_recv_threadBootstrap, (LPVOID)this, 0, &canListenThreadID);
|
||||
|
||||
DWORD flowControlSendThreadID;
|
||||
this->flow_control_wakeup_event = CreateEvent(NULL, TRUE, FALSE, NULL);
|
||||
this->flow_control_thread_handle = CreateThread(NULL, 0, _msg_tx_threadBootstrap, (LPVOID)this, 0, &flowControlSendThreadID);
|
||||
};
|
||||
|
||||
PandaJ2534Device::~PandaJ2534Device() {
|
||||
SetEvent(this->thread_kill_event);
|
||||
DWORD res = WaitForSingleObject(this->can_thread_handle, INFINITE);
|
||||
CloseHandle(this->can_thread_handle);
|
||||
|
||||
res = WaitForSingleObject(this->flow_control_thread_handle, INFINITE);
|
||||
CloseHandle(this->flow_control_thread_handle);
|
||||
|
||||
CloseHandle(this->flow_control_wakeup_event);
|
||||
CloseHandle(this->thread_kill_event);
|
||||
}
|
||||
|
||||
std::shared_ptr<PandaJ2534Device> PandaJ2534Device::openByName(std::string sn) {
|
||||
auto p = panda::Panda::openPanda("");
|
||||
if (p == nullptr)
|
||||
return nullptr;
|
||||
return std::unique_ptr<PandaJ2534Device>(new PandaJ2534Device(std::move(p)));
|
||||
}
|
||||
|
||||
DWORD PandaJ2534Device::closeChannel(unsigned long ChannelID) {
|
||||
if (this->connections.size() <= ChannelID) return ERR_INVALID_CHANNEL_ID;
|
||||
if (this->connections[ChannelID] == nullptr) return ERR_INVALID_CHANNEL_ID;
|
||||
this->connections[ChannelID] = nullptr;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
DWORD PandaJ2534Device::addChannel(std::shared_ptr<J2534Connection>& conn, unsigned long* channel_id) {
|
||||
int channel_index = -1;
|
||||
for (unsigned int i = 0; i < this->connections.size(); i++)
|
||||
if (this->connections[i] == nullptr) {
|
||||
channel_index = i;
|
||||
break;
|
||||
}
|
||||
|
||||
if (channel_index == -1) {
|
||||
if (this->connections.size() == 0xFFFF) //channelid max 16 bits
|
||||
return ERR_FAILED; //Too many channels
|
||||
this->connections.push_back(nullptr);
|
||||
channel_index = this->connections.size() - 1;
|
||||
}
|
||||
|
||||
this->connections[channel_index] = conn;
|
||||
|
||||
*channel_id = channel_index;
|
||||
return STATUS_NOERROR;
|
||||
}
|
||||
|
||||
DWORD PandaJ2534Device::can_recv_thread() {
|
||||
DWORD err = TRUE;
|
||||
while (err) {
|
||||
std::vector<panda::PANDA_CAN_MSG> msg_recv;
|
||||
err = this->panda->can_recv_async(this->thread_kill_event, msg_recv);
|
||||
for (auto msg_in : msg_recv) {
|
||||
J2534Frame msg_out(msg_in);
|
||||
|
||||
if (msg_in.is_receipt) {
|
||||
synchronized(task_queue_mutex) {
|
||||
if (txMsgsAwaitingEcho.size() > 0) {
|
||||
auto msgtx = txMsgsAwaitingEcho.front();
|
||||
if (auto conn = msgtx->connection.lock()) {
|
||||
if (conn->isProtoCan() && conn->getPort() == msg_in.bus) {
|
||||
if (msgtx->checkTxReceipt(msg_out)) {
|
||||
//Things to check:
|
||||
// Frame not for this msg: Drop frame and alert. Error?
|
||||
// Frame is for this msg, more tx frames required after a FC frame: Wait for FC frame to come and trigger next tx.
|
||||
// Frame is for this msg, more tx frames required: Schedule next tx frame.
|
||||
// Frame is for this msg, and is the final frame of the msg: Let conn process full msg, If another msg from this conn is available, register it.
|
||||
txMsgsAwaitingEcho.pop(); //Remove the TX object and schedule record.
|
||||
|
||||
if (msgtx->isFinished()) {
|
||||
this->removeConnectionTopAction(conn, msgtx);
|
||||
} else {
|
||||
if (msgtx->txReady()) { //Not finished, ready to send next frame.
|
||||
msgtx->schedule(msg_in.recv_time_point, TRUE);
|
||||
this->insertActionIntoTaskList(msgtx);
|
||||
} else {
|
||||
//Not finished, but next frame not ready (maybe waiting for flow control).
|
||||
//Do not schedule more messages from this connection.
|
||||
//this->ConnTxSet.erase(conn);
|
||||
//Removing this means new messages queued can kickstart the queue and overstep the current message.
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
//Connection has died. Clear out the tx entry from device records.
|
||||
txMsgsAwaitingEcho.pop();
|
||||
this->ConnTxSet.erase(conn); //connection is already dead, no need to schedule future tx msgs.
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (auto& conn : this->connections)
|
||||
if (conn->isProtoCan() && conn->getPort() == msg_in.bus)
|
||||
conn->processMessage(msg_out);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
DWORD PandaJ2534Device::msg_tx_thread() {
|
||||
const HANDLE subscriptions[] = { this->flow_control_wakeup_event, this->thread_kill_event };
|
||||
DWORD sleepDuration = INFINITE;
|
||||
while (TRUE) {
|
||||
DWORD res = WaitForMultipleObjects(2, subscriptions, FALSE, sleepDuration);
|
||||
if (res == WAIT_OBJECT_0 + 1) return 0;
|
||||
if (res != WAIT_OBJECT_0 && res != WAIT_TIMEOUT) {
|
||||
printf("Got an unexpected wait result in flow_control_write_thread. Res: %d; GetLastError: %d\n. Terminating thread.", res, GetLastError());
|
||||
return 0;
|
||||
}
|
||||
ResetEvent(this->flow_control_wakeup_event);
|
||||
|
||||
while (TRUE) {
|
||||
synchronized(task_queue_mutex) { //implemented with for loop. Consumes breaks.
|
||||
if (this->task_queue.size() == 0) {
|
||||
sleepDuration = INFINITE;
|
||||
goto break_flow_ctrl_loop;
|
||||
}
|
||||
if (std::chrono::steady_clock::now() >= this->task_queue.front()->expire) {
|
||||
auto task = this->task_queue.front(); //Get the scheduled tx record.
|
||||
this->task_queue.pop_front();
|
||||
task->execute();
|
||||
} else { //Ran out of things that need to be sent now. Sleep!
|
||||
auto time_diff = std::chrono::duration_cast<std::chrono::milliseconds>
|
||||
(this->task_queue.front()->expire - std::chrono::steady_clock::now());
|
||||
sleepDuration = max(1, time_diff.count());
|
||||
goto break_flow_ctrl_loop;
|
||||
}
|
||||
}
|
||||
}
|
||||
break_flow_ctrl_loop:
|
||||
continue;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Place the Action in the task queue based on the Action's expiration time,
|
||||
//then signal the thread that processes actions.
|
||||
void PandaJ2534Device::insertActionIntoTaskList(std::shared_ptr<Action> action) {
|
||||
synchronized(task_queue_mutex) {
|
||||
auto iter = this->task_queue.begin();
|
||||
for (; iter != this->task_queue.end(); iter++) {
|
||||
if (action->expire < (*iter)->expire) break;
|
||||
}
|
||||
this->task_queue.insert(iter, action);
|
||||
}
|
||||
SetEvent(this->flow_control_wakeup_event);
|
||||
}
|
||||
|
||||
void PandaJ2534Device::scheduleAction(std::shared_ptr<Action> msg, BOOL startdelayed) {
|
||||
if(startdelayed)
|
||||
msg->scheduleImmediateDelay();
|
||||
else
|
||||
msg->scheduleImmediate();
|
||||
this->insertActionIntoTaskList(msg);
|
||||
}
|
||||
|
||||
void PandaJ2534Device::registerConnectionTx(std::shared_ptr<J2534Connection> conn) {
|
||||
synchronized(connTXSet_mutex) {
|
||||
auto ret = this->ConnTxSet.insert(conn);
|
||||
if (ret.second == FALSE) return; //Conn already exists.
|
||||
this->scheduleAction(conn->txbuff.front());
|
||||
}
|
||||
}
|
||||
|
||||
void PandaJ2534Device::unstallConnectionTx(std::shared_ptr<J2534Connection> conn) {
|
||||
synchronized(connTXSet_mutex) {
|
||||
auto ret = this->ConnTxSet.insert(conn);
|
||||
if (ret.second == TRUE) return; //Conn already exists.
|
||||
this->insertActionIntoTaskList(conn->txbuff.front());
|
||||
}
|
||||
}
|
||||
|
||||
void PandaJ2534Device::removeConnectionTopAction(std::shared_ptr<J2534Connection> conn, std::shared_ptr<MessageTx> msg) {
|
||||
synchronized(task_queue_mutex) {
|
||||
if (conn->txbuff.size() == 0)
|
||||
return;
|
||||
if (conn->txbuff.front() != msg)
|
||||
return;
|
||||
conn->txbuff.pop(); //Remove the top TX message from the connection tx queue.
|
||||
|
||||
//Remove the connection from the active connection list if no more messages are scheduled with this connection.
|
||||
if (conn->txbuff.size() == 0) {
|
||||
//Update records showing the connection no longer has a tx record scheduled.
|
||||
this->ConnTxSet.erase(conn);
|
||||
} else {
|
||||
//Add the next scheduled tx from this conn
|
||||
this->scheduleAction(conn->txbuff.front());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
#include <memory>
|
||||
#include <list>
|
||||
#include <queue>
|
||||
#include <set>
|
||||
#include <chrono>
|
||||
#include "J2534_v0404.h"
|
||||
#include "panda/panda.h"
|
||||
#include "synchronize.h"
|
||||
#include "Action.h"
|
||||
#include "MessageTx.h"
|
||||
#include "J2534Connection.h"
|
||||
|
||||
class J2534Connection;
|
||||
class Action;
|
||||
class MessageTx;
|
||||
|
||||
/**
|
||||
Class representing a physical panda adapter. Instances are created by
|
||||
PassThruOpen in the J2534 API. A Device can create one or more
|
||||
J2534Connections.
|
||||
*/
|
||||
class PandaJ2534Device {
|
||||
public:
|
||||
PandaJ2534Device(std::unique_ptr<panda::Panda> new_panda);
|
||||
|
||||
~PandaJ2534Device();
|
||||
|
||||
static std::shared_ptr<PandaJ2534Device> openByName(std::string sn);
|
||||
|
||||
DWORD closeChannel(unsigned long ChannelID);
|
||||
DWORD addChannel(std::shared_ptr<J2534Connection>& conn, unsigned long* channel_id);
|
||||
|
||||
std::unique_ptr<panda::Panda> panda;
|
||||
std::vector<std::shared_ptr<J2534Connection>> connections;
|
||||
|
||||
//Place the Action in the task queue based on the Action's expiration time,
|
||||
//then signal the thread that processes actions.
|
||||
void insertActionIntoTaskList(std::shared_ptr<Action> action);
|
||||
|
||||
void scheduleAction(std::shared_ptr<Action> msg, BOOL startdelayed=FALSE);
|
||||
|
||||
void registerConnectionTx(std::shared_ptr<J2534Connection> conn);
|
||||
|
||||
//Resume sending messages from the provided Connection's TX queue.
|
||||
void unstallConnectionTx(std::shared_ptr<J2534Connection> conn);
|
||||
|
||||
//Cleans up several queues after a message completes, is canceled, or otherwise goes away.
|
||||
void removeConnectionTopAction(std::shared_ptr<J2534Connection> conn, std::shared_ptr<MessageTx> msg);
|
||||
|
||||
//Messages that have been sent on the wire will be echoed by the panda when
|
||||
//transmission is complete. This tracks what is still waiting to hear an echo.
|
||||
std::queue<std::shared_ptr<MessageTx>> txMsgsAwaitingEcho;
|
||||
|
||||
private:
|
||||
HANDLE thread_kill_event;
|
||||
|
||||
HANDLE can_thread_handle;
|
||||
static DWORD WINAPI _can_recv_threadBootstrap(LPVOID This) {
|
||||
return ((PandaJ2534Device*)This)->can_recv_thread();
|
||||
}
|
||||
DWORD can_recv_thread();
|
||||
|
||||
HANDLE flow_control_wakeup_event;
|
||||
HANDLE flow_control_thread_handle;
|
||||
static DWORD WINAPI _msg_tx_threadBootstrap(LPVOID This) {
|
||||
return ((PandaJ2534Device*)This)->msg_tx_thread();
|
||||
}
|
||||
DWORD msg_tx_thread();
|
||||
std::list<std::shared_ptr<Action>> task_queue;
|
||||
Mutex task_queue_mutex;
|
||||
|
||||
std::queue<std::shared_ptr<J2534Connection>> ConnTxQueue;
|
||||
std::set<std::shared_ptr<J2534Connection>> ConnTxSet;
|
||||
Mutex connTXSet_mutex;
|
||||
BOOL txInProgress;
|
||||
};
|
|
@ -0,0 +1,17 @@
|
|||
#include "stdafx.h"
|
||||
#include "Timer.h"
|
||||
|
||||
|
||||
Timer::Timer()
|
||||
{
|
||||
start = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
|
||||
}
|
||||
|
||||
// gets the time elapsed from construction.
|
||||
unsigned long long /*milliseconds*/ Timer::getTimePassed(){
|
||||
// get the new time
|
||||
auto end = std::chrono::time_point_cast<std::chrono::milliseconds>(clock::now());
|
||||
|
||||
// return the difference of the times
|
||||
return (end - start).count();
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
#pragma once
|
||||
#include <chrono>
|
||||
|
||||
//Copied from https://stackoverflow.com/a/31488113
|
||||
|
||||
class Timer
|
||||
{
|
||||
using clock = std::chrono::steady_clock;
|
||||
using time_point_type = std::chrono::time_point < clock, std::chrono::milliseconds >;
|
||||
public:
|
||||
Timer();
|
||||
|
||||
// gets the time elapsed from construction.
|
||||
unsigned long long /*milliseconds*/ getTimePassed();
|
||||
|
||||
private:
|
||||
time_point_type start;
|
||||
};
|
|
@ -0,0 +1,20 @@
|
|||
#pragma once
|
||||
|
||||
#define msg_is_extaddr(msg) check_bmask(msg->TxFlags, ISO15765_ADDR_TYPE)
|
||||
#define msg_is_padded(msg) check_bmask(msg->TxFlags, ISO15765_FRAME_PAD)
|
||||
|
||||
#define FRAME_SINGLE 0x00
|
||||
#define FRAME_FIRST 0x10
|
||||
#define FRAME_CONSEC 0x20
|
||||
#define FRAME_FLOWCTRL 0x30
|
||||
|
||||
#define FLOWCTRL_CONTINUE 0
|
||||
#define FLOWCTRL_WAIT 1
|
||||
#define FLOWCTRL_ABORT 2
|
||||
|
||||
#define msg_get_type(msg, addrlen) ((msg).Data[addrlen] & 0xF0)
|
||||
|
||||
#define is_single(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_SINGLE)
|
||||
#define is_first(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_FIRST)
|
||||
#define is_consecutive(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_CONSEC)
|
||||
#define is_flowctrl(msg, addrlen) (msg_get_type(msg, addrlen) == FRAME_FLOWCTRL)
|
|
@ -0,0 +1,22 @@
|
|||
// dllmain.cpp : Defines the entry point for the DLL application.
|
||||
#include "dllmain.h"
|
||||
|
||||
HMODULE thisdll;
|
||||
|
||||
BOOL APIENTRY DllMain( HMODULE hModule,
|
||||
DWORD ul_reason_for_call,
|
||||
LPVOID lpReserved
|
||||
)
|
||||
{
|
||||
thisdll = hModule;
|
||||
|
||||
switch (ul_reason_for_call)
|
||||
{
|
||||
case DLL_PROCESS_ATTACH:
|
||||
case DLL_THREAD_ATTACH:
|
||||
case DLL_THREAD_DETACH:
|
||||
case DLL_PROCESS_DETACH:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
|
@ -0,0 +1,4 @@
|
|||
#pragma once
|
||||
#include "stdafx.h"
|
||||
|
||||
extern HMODULE thisdll;
|
|
@ -0,0 +1,433 @@
|
|||
// pandaJ2534DLL.cpp : Defines the exported functions for the DLL application.
|
||||
// Protocol derived from the following sites (which shall be referred to as The Protocol Reference #).
|
||||
// https://web.archive.org/web/20130805013326/https://tunertools.com/prodimages/DrewTech/Manuals/PassThru_API-1.pdf
|
||||
// http://web.archive.org/web/20170910063536/http://www.tiecar.net/downloads/SAE_J2534_2002.pdf
|
||||
|
||||
#include "stdafx.h"
|
||||
#include "J2534_v0404.h"
|
||||
#include "panda/panda.h"
|
||||
#include "J2534Connection.h"
|
||||
#include "J2534Connection_CAN.h"
|
||||
#include "J2534Connection_ISO15765.h"
|
||||
#include "PandaJ2534Device.h"
|
||||
#include "dllmain.h"
|
||||
|
||||
// A quick way to avoid the name mangling that __stdcall liked to do
|
||||
#define EXPORT comment(linker, "/EXPORT:" __FUNCTION__ "=" __FUNCDNAME__)
|
||||
|
||||
std::vector<std::shared_ptr<PandaJ2534Device>> pandas;
|
||||
|
||||
int J25334LastError = 0;
|
||||
|
||||
std::string GetProductAndVersion(TCHAR* szFilename)//std::string & strProductName, std::string & strProductVersion)
|
||||
{
|
||||
// allocate a block of memory for the version info
|
||||
DWORD dummy;
|
||||
DWORD dwSize = GetFileVersionInfoSize(szFilename, &dummy);
|
||||
if (dwSize == 0) {
|
||||
return "error";
|
||||
}
|
||||
std::vector<BYTE> data(dwSize);
|
||||
|
||||
// load the version info
|
||||
if (!GetFileVersionInfo(szFilename, NULL, dwSize, &data[0])) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
// get the name and version strings
|
||||
LPVOID pvProductName = NULL;
|
||||
unsigned int iProductNameLen = 0;
|
||||
LPVOID pvProductVersion = NULL;
|
||||
unsigned int iProductVersionLen = 0;
|
||||
|
||||
// 040904b0 is a language id.
|
||||
if (!VerQueryValueA(&data[0], "\\StringFileInfo\\040904b0\\ProductName", &pvProductName, &iProductNameLen) ||
|
||||
!VerQueryValueA(&data[0], "\\StringFileInfo\\040904b0\\ProductVersion", &pvProductVersion, &iProductVersionLen)) {
|
||||
return "error";
|
||||
}
|
||||
|
||||
std::string ver_str = std::string((char*)pvProductVersion, iProductVersionLen-1);
|
||||
std::string prod_str = std::string((char*)pvProductName, iProductNameLen-1);
|
||||
std::string full_ver = prod_str + std::string(": ") + ver_str;
|
||||
return full_ver;
|
||||
}
|
||||
|
||||
long ret_code(long code) {
|
||||
J25334LastError = code;
|
||||
return code;
|
||||
}
|
||||
|
||||
#define EXTRACT_DID(CID) (CID & 0xFFFF)
|
||||
#define EXTRACT_CID(CID) ((CID >> 16) & 0xFFFF)
|
||||
|
||||
long check_valid_DeviceID(unsigned long DeviceID) {
|
||||
uint16_t dev_id = EXTRACT_DID(DeviceID);
|
||||
if (pandas.size() <= dev_id || pandas[dev_id] == nullptr)
|
||||
return ret_code(ERR_INVALID_DEVICE_ID);
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
|
||||
long check_valid_ChannelID(unsigned long ChannelID) {
|
||||
uint16_t dev_id = EXTRACT_DID(ChannelID);;
|
||||
uint16_t con_id = EXTRACT_CID(ChannelID);
|
||||
|
||||
if (pandas.size() <= dev_id || pandas[dev_id] == nullptr)
|
||||
return ret_code(ERR_INVALID_CHANNEL_ID);
|
||||
|
||||
if (pandas[dev_id]->connections.size() <= con_id) return ret_code(ERR_INVALID_CHANNEL_ID);
|
||||
if (pandas[dev_id]->connections[con_id] == nullptr) return ret_code(ERR_DEVICE_NOT_CONNECTED);
|
||||
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
|
||||
//Do not call without checking if the device/channel id exists first.
|
||||
#define get_device(DeviceID) (pandas[EXTRACT_DID(DeviceID)])
|
||||
#define get_channel(ChannelID) (get_device(ChannelID)->connections[EXTRACT_CID(ChannelID)])
|
||||
|
||||
PANDAJ2534DLL_API long PTAPI PassThruOpen(void *pName, unsigned long *pDeviceID) {
|
||||
#pragma EXPORT
|
||||
if (pDeviceID == NULL) return ret_code(ERR_NULL_PARAMETER);
|
||||
std::string sn = (pName == NULL) ? "" : std::string((char*)pName);
|
||||
if (sn == "J2534-2:")
|
||||
sn = "";
|
||||
|
||||
auto new_panda = PandaJ2534Device::openByName(sn);
|
||||
if (new_panda == nullptr) {
|
||||
if(sn == "" && pandas.size() == 1)
|
||||
return ret_code(ERR_DEVICE_IN_USE);
|
||||
for (auto& pn : pandas) {
|
||||
if (pn->panda->get_usb_sn() == sn)
|
||||
return ret_code(ERR_DEVICE_IN_USE);
|
||||
}
|
||||
return ret_code(ERR_DEVICE_NOT_CONNECTED);
|
||||
}
|
||||
|
||||
int panda_index = -1;
|
||||
for (unsigned int i = 0; i < pandas.size(); i++)
|
||||
if (pandas[i] == nullptr) {
|
||||
panda_index = i;
|
||||
pandas[panda_index] = std::move(new_panda);
|
||||
break;
|
||||
}
|
||||
|
||||
if (panda_index == -1) {
|
||||
if(pandas.size() == 0xFFFF) //device id will be 16 bit to fit channel next to it.
|
||||
return ret_code(ERR_FAILED); //Too many pandas. Off the endangered species list.
|
||||
pandas.push_back(std::move(new_panda));
|
||||
panda_index = pandas.size()-1;
|
||||
}
|
||||
|
||||
*pDeviceID = panda_index;
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruClose(unsigned long DeviceID) {
|
||||
#pragma EXPORT
|
||||
if (check_valid_DeviceID(DeviceID) != STATUS_NOERROR) return J25334LastError;
|
||||
get_device(DeviceID) = nullptr;
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruConnect(unsigned long DeviceID, unsigned long ProtocolID,
|
||||
unsigned long Flags, unsigned long BaudRate, unsigned long *pChannelID) {
|
||||
#pragma EXPORT
|
||||
if (pChannelID == NULL) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (check_valid_DeviceID(DeviceID) != STATUS_NOERROR) return J25334LastError;
|
||||
auto& panda = get_device(DeviceID);
|
||||
|
||||
std::shared_ptr<J2534Connection> conn;
|
||||
|
||||
//TODO check if channel can be made
|
||||
try {
|
||||
switch (ProtocolID) {
|
||||
//SW seems to refer to Single Wire. https://www.nxp.com/files-static/training_pdf/20451_BUS_COMM_WBT.pdf
|
||||
//SW_ protocols may be touched on here: https://www.iso.org/obp/ui/#iso:std:iso:22900:-2:ed-1:v1:en
|
||||
case J1850VPW: //These protocols are outdated and will not be supported. HDS wants them to not fail to open.
|
||||
case J1850PWM:
|
||||
case J1850VPW_PS:
|
||||
case J1850PWM_PS:
|
||||
case ISO9141: //This protocol could be implemented if 5 BAUD init support is added to the panda.
|
||||
case ISO9141_PS:
|
||||
conn = std::make_shared<J2534Connection>(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
case ISO14230: //Only supporting Fast init until panda adds support for 5 BAUD init.
|
||||
case ISO14230_PS:
|
||||
conn = std::make_shared<J2534Connection>(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
case CAN:
|
||||
case CAN_PS:
|
||||
//case SW_CAN_PS:
|
||||
conn = std::make_shared<J2534Connection_CAN>(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
case ISO15765:
|
||||
case ISO15765_PS:
|
||||
conn = std::make_shared<J2534Connection_ISO15765>(panda, ProtocolID, Flags, BaudRate);
|
||||
break;
|
||||
//case SW_ISO15765_PS: // SW = Single Wire. GMLAN is a SW CAN protocol
|
||||
//case GM_UART_PS: // PS = Pin Select. Handles different ports.
|
||||
//Looks like SCI based protocols may not be compatible with the panda:
|
||||
//http://mdhmotors.com/can-communications-vehicle-network-protocols/3/
|
||||
//case SCI_A_ENGINE:
|
||||
//case SCI_A_TRANS:
|
||||
//case SCI_B_ENGINE:
|
||||
//case SCI_B_TRANS:
|
||||
//case J2610_PS:
|
||||
default:
|
||||
return ret_code(ERR_INVALID_PROTOCOL_ID);
|
||||
}
|
||||
} catch (int e) {
|
||||
return ret_code(e);
|
||||
}
|
||||
|
||||
unsigned long channel_index;
|
||||
unsigned long err = panda->addChannel(conn, &channel_index);
|
||||
if (err == STATUS_NOERROR)
|
||||
*pChannelID = (channel_index << 16) | DeviceID;
|
||||
|
||||
return ret_code(err);
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruDisconnect(unsigned long ChannelID) {
|
||||
#pragma EXPORT
|
||||
unsigned long res = check_valid_DeviceID(ChannelID);
|
||||
if (res == ERR_INVALID_DEVICE_ID) return ret_code(ERR_INVALID_CHANNEL_ID);
|
||||
if (res != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_device(ChannelID)->closeChannel(EXTRACT_CID(ChannelID)));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruReadMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg,
|
||||
unsigned long *pNumMsgs, unsigned long Timeout) {
|
||||
#pragma EXPORT
|
||||
if (pMsg == NULL || pNumMsgs == NULL) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_channel(ChannelID)->PassThruReadMsgs(pMsg, pNumMsgs, Timeout));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruWriteMsgs(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pNumMsgs, unsigned long Timeout) {
|
||||
#pragma EXPORT
|
||||
if (pMsg == NULL || pNumMsgs == NULL) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_channel(ChannelID)->PassThruWriteMsgs(pMsg, pNumMsgs, Timeout));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStartPeriodicMsg(unsigned long ChannelID, PASSTHRU_MSG *pMsg, unsigned long *pMsgID, unsigned long TimeInterval) {
|
||||
#pragma EXPORT
|
||||
if (pMsg == NULL || pMsgID == NULL) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_channel(ChannelID)->PassThruStartPeriodicMsg(pMsg, pMsgID, TimeInterval));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStopPeriodicMsg(unsigned long ChannelID, unsigned long MsgID) {
|
||||
#pragma EXPORT
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_channel(ChannelID)->PassThruStopPeriodicMsg(MsgID));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStartMsgFilter(unsigned long ChannelID, unsigned long FilterType, PASSTHRU_MSG *pMaskMsg,
|
||||
PASSTHRU_MSG *pPatternMsg, PASSTHRU_MSG *pFlowControlMsg, unsigned long *pFilterID) {
|
||||
#pragma EXPORT
|
||||
if (FilterType != PASS_FILTER && FilterType != BLOCK_FILTER && FilterType != FLOW_CONTROL_FILTER) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (!pFilterID || (!pMaskMsg && !pPatternMsg && !pFlowControlMsg)) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_channel(ChannelID)->PassThruStartMsgFilter(FilterType, pMaskMsg, pPatternMsg, pFlowControlMsg, pFilterID));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruStopMsgFilter(unsigned long ChannelID, unsigned long FilterID) {
|
||||
#pragma EXPORT
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
return ret_code(get_channel(ChannelID)->PassThruStopMsgFilter(FilterID));
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruSetProgrammingVoltage(unsigned long DeviceID, unsigned long PinNumber, unsigned long Voltage) {
|
||||
#pragma EXPORT
|
||||
//Unused
|
||||
if (check_valid_DeviceID(DeviceID) != STATUS_NOERROR) return J25334LastError;
|
||||
auto& panda = get_device(DeviceID);
|
||||
|
||||
switch (Voltage) {
|
||||
case SHORT_TO_GROUND:
|
||||
break;
|
||||
case VOLTAGE_OFF:
|
||||
break;
|
||||
default:
|
||||
if (!(5000 <= Voltage && Voltage <= 20000))
|
||||
return ret_code(ERR_NOT_SUPPORTED);
|
||||
break;
|
||||
}
|
||||
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruReadVersion(unsigned long DeviceID, char *pFirmwareVersion, char *pDllVersion, char *pApiVersion) {
|
||||
#pragma EXPORT
|
||||
if (!pFirmwareVersion || !pDllVersion || !pApiVersion) return ret_code(ERR_NULL_PARAMETER);
|
||||
if (check_valid_DeviceID(DeviceID) != STATUS_NOERROR) return J25334LastError;
|
||||
|
||||
auto& panda = get_device(DeviceID);
|
||||
auto fw_version = panda->panda->get_version();
|
||||
strcpy_s(pFirmwareVersion, 80, fw_version.c_str());
|
||||
|
||||
std::string j2534dll_ver;
|
||||
TCHAR pandalib_filename[MAX_PATH + 1] = { 0 };
|
||||
if (GetModuleFileName(thisdll, pandalib_filename, MAX_PATH) == 0) {
|
||||
j2534dll_ver = "error";
|
||||
} else {
|
||||
j2534dll_ver = GetProductAndVersion(pandalib_filename);
|
||||
}
|
||||
std::string pandalib_ver = GetProductAndVersion(_T("panda.dll"));
|
||||
std::string fullver = "(" + j2534dll_ver + "; " + pandalib_ver + ")";
|
||||
strcpy_s(pDllVersion, 80, fullver.c_str());
|
||||
|
||||
strcpy_s(pApiVersion, 80, J2534_APIVER_NOVEMBER_2004);
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruGetLastError(char *pErrorDescription) {
|
||||
#pragma EXPORT
|
||||
if (pErrorDescription == NULL) return ret_code(ERR_NULL_PARAMETER);
|
||||
switch (J25334LastError) {
|
||||
case STATUS_NOERROR:
|
||||
strcpy_s(pErrorDescription, 80, "Function call successful.");
|
||||
break;
|
||||
case ERR_NOT_SUPPORTED:
|
||||
strcpy_s(pErrorDescription, 80, "Device cannot support requested functionality mandated in J2534.");
|
||||
break;
|
||||
case ERR_INVALID_CHANNEL_ID:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid ChannelID value.");
|
||||
break;
|
||||
case ERR_INVALID_PROTOCOL_ID:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid or unsupported ProtocolID, or resource conflict.");
|
||||
break;
|
||||
case ERR_NULL_PARAMETER:
|
||||
strcpy_s(pErrorDescription, 80, "NULL pointer supplied where a valid pointer is required.");
|
||||
break;
|
||||
case ERR_INVALID_IOCTL_VALUE:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid value for Ioctl parameter.");
|
||||
break;
|
||||
case ERR_INVALID_FLAGS:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid flag values.");
|
||||
break;
|
||||
case ERR_FAILED:
|
||||
strcpy_s(pErrorDescription, 80, "Undefined error.");
|
||||
break;
|
||||
case ERR_DEVICE_NOT_CONNECTED:
|
||||
strcpy_s(pErrorDescription, 80, "Unable to communicate with device.");
|
||||
break;
|
||||
case ERR_TIMEOUT:
|
||||
strcpy_s(pErrorDescription, 80, "Read or write timeout:");
|
||||
// PassThruReadMsgs() - No message available to read or could not read the specified number of messages. The actual number of messages read is placed in <NumMsgs>.
|
||||
// PassThruWriteMsgs() - Device could not write the specified number of messages. The actual number of messages sent on the vehicle network is placed in <NumMsgs>.
|
||||
break;
|
||||
case ERR_INVALID_MSG:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid message structure pointed to by pMsg.");
|
||||
break;
|
||||
case ERR_INVALID_TIME_INTERVAL:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid TimeInterval value.");
|
||||
break;
|
||||
case ERR_EXCEEDED_LIMIT:
|
||||
strcpy_s(pErrorDescription, 80, "Exceeded maximum number of message IDs or allocated space.");
|
||||
break;
|
||||
case ERR_INVALID_MSG_ID:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid MsgID value.");
|
||||
break;
|
||||
case ERR_DEVICE_IN_USE:
|
||||
strcpy_s(pErrorDescription, 80, "Device is currently open.");
|
||||
break;
|
||||
case ERR_INVALID_IOCTL_ID:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid IoctlID value.");
|
||||
break;
|
||||
case ERR_BUFFER_EMPTY:
|
||||
strcpy_s(pErrorDescription, 80, "Protocol message buffer empty.");
|
||||
break;
|
||||
case ERR_BUFFER_FULL:
|
||||
strcpy_s(pErrorDescription, 80, "Protocol message buffer full. Messages may have been lost.");
|
||||
break;
|
||||
case ERR_BUFFER_OVERFLOW:
|
||||
strcpy_s(pErrorDescription, 80, "A buffer overflow occurred and messages were lost.");
|
||||
break;
|
||||
case ERR_PIN_INVALID:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid pin number, or pin number already in use.");
|
||||
break;
|
||||
case ERR_CHANNEL_IN_USE:
|
||||
strcpy_s(pErrorDescription, 80, "Channel number is currently connected.");
|
||||
break;
|
||||
case ERR_MSG_PROTOCOL_ID:
|
||||
strcpy_s(pErrorDescription, 80, "The Message's Protocol does not match the Channel's protocol.");
|
||||
break;
|
||||
case ERR_INVALID_FILTER_ID:
|
||||
strcpy_s(pErrorDescription, 80, "Invalid Filter ID value.");
|
||||
break;
|
||||
case ERR_NO_FLOW_CONTROL:
|
||||
strcpy_s(pErrorDescription, 80, "No flow control filter set or matched.");
|
||||
break;
|
||||
case ERR_NOT_UNIQUE:
|
||||
strcpy_s(pErrorDescription, 80, "This filter already exists.");
|
||||
break;
|
||||
case ERR_INVALID_BAUDRATE:
|
||||
strcpy_s(pErrorDescription, 80, "The desired baud rate cannot be achieved within SAE tolerance.");
|
||||
break;
|
||||
case ERR_INVALID_DEVICE_ID:
|
||||
strcpy_s(pErrorDescription, 80, "Device ID invalid.");
|
||||
break;
|
||||
}
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
||||
PANDAJ2534DLL_API long PTAPI PassThruIoctl(unsigned long ChannelID, unsigned long IoctlID,
|
||||
void *pInput, void *pOutput) {
|
||||
#pragma EXPORT
|
||||
if (check_valid_ChannelID(ChannelID) != STATUS_NOERROR) return J25334LastError;
|
||||
auto& dev_entry = get_device(ChannelID);
|
||||
//get_channel(ChannelID)
|
||||
|
||||
switch (IoctlID) {
|
||||
case GET_CONFIG:
|
||||
{
|
||||
SCONFIG_LIST *inconfig = (SCONFIG_LIST*)pInput;
|
||||
if (inconfig == NULL)
|
||||
return ret_code(ERR_NULL_PARAMETER);
|
||||
for (unsigned int i = 0; i < inconfig->NumOfParams; i++) {
|
||||
try {
|
||||
inconfig->ConfigPtr[i].Value = get_channel(ChannelID)->processIOCTLGetConfig(inconfig->ConfigPtr[i].Parameter);
|
||||
} catch (int e) {
|
||||
return ret_code(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SET_CONFIG:
|
||||
{
|
||||
SCONFIG_LIST *inconfig = (SCONFIG_LIST*)pInput;
|
||||
if (inconfig == NULL)
|
||||
return ret_code(ERR_NULL_PARAMETER);
|
||||
for (unsigned int i = 0; i < inconfig->NumOfParams; i++) {
|
||||
try {
|
||||
get_channel(ChannelID)->processIOCTLSetConfig(inconfig->ConfigPtr[i].Parameter, inconfig->ConfigPtr[i].Value);
|
||||
} catch (int e) {
|
||||
return ret_code(e);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
case READ_VBATT:
|
||||
panda::PANDA_HEALTH health = dev_entry->panda->get_health();
|
||||
*(unsigned long*)pOutput = health.voltage;
|
||||
break;
|
||||
case FIVE_BAUD_INIT:
|
||||
if (!pInput || !pOutput) return ret_code(ERR_NULL_PARAMETER);
|
||||
return ret_code(get_channel(ChannelID)->init5b((SBYTE_ARRAY*)pInput, (SBYTE_ARRAY*)pOutput));
|
||||
case FAST_INIT:
|
||||
if (!pInput || !pOutput) return ret_code(ERR_NULL_PARAMETER);
|
||||
return ret_code(get_channel(ChannelID)->initFast((PASSTHRU_MSG*)pInput, (PASSTHRU_MSG*)pOutput));
|
||||
case CLEAR_TX_BUFFER:
|
||||
return ret_code(get_channel(ChannelID)->clearTXBuff());
|
||||
case CLEAR_RX_BUFFER:
|
||||
return ret_code(get_channel(ChannelID)->clearRXBuff());
|
||||
case CLEAR_PERIODIC_MSGS:
|
||||
return ret_code(get_channel(ChannelID)->clearPeriodicMsgs());
|
||||
case CLEAR_MSG_FILTERS:
|
||||
return ret_code(get_channel(ChannelID)->clearMsgFilters());
|
||||
case CLEAR_FUNCT_MSG_LOOKUP_TABLE: // LOOKUP TABLE IS RELATED TO J1850 PWM. Unsupported.
|
||||
if (!pInput) return ret_code(ERR_NULL_PARAMETER);
|
||||
return ret_code(STATUS_NOERROR);
|
||||
case ADD_TO_FUNCT_MSG_LOOKUP_TABLE: // LOOKUP TABLE IS RELATED TO J1850 PWM. Unsupported.
|
||||
if (!pInput) return ret_code(ERR_NULL_PARAMETER);
|
||||
return ret_code(STATUS_NOERROR);
|
||||
case DELETE_FROM_FUNCT_MSG_LOOKUP_TABLE: // LOOKUP TABLE IS RELATED TO J1850 PWM. Unsupported.
|
||||
return ret_code(STATUS_NOERROR);
|
||||
case READ_PROG_VOLTAGE:
|
||||
*(unsigned long*)pOutput = 0;
|
||||
break;
|
||||
default:
|
||||
printf("Got unknown IIOCTL %X\n", IoctlID);
|
||||
}
|
||||
|
||||
return ret_code(STATUS_NOERROR);
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project DefaultTargets="Build" ToolsVersion="14.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup Label="ProjectConfigurations">
|
||||
<ProjectConfiguration Include="Debug|Win32">
|
||||
<Configuration>Debug</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
<ProjectConfiguration Include="Release|Win32">
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Win32</Platform>
|
||||
</ProjectConfiguration>
|
||||
</ItemGroup>
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>{A2BB18A5-F26B-48D6-BBB5-B83D64473C77}</ProjectGuid>
|
||||
<Keyword>Win32Proj</Keyword>
|
||||
<RootNamespace>pandaJ2534DLL</RootNamespace>
|
||||
<WindowsTargetPlatformVersion>8.1</WindowsTargetPlatformVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>true</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
|
||||
<ConfigurationType>DynamicLibrary</ConfigurationType>
|
||||
<UseDebugLibraries>false</UseDebugLibraries>
|
||||
<PlatformToolset>v140</PlatformToolset>
|
||||
<WholeProgramOptimization>true</WholeProgramOptimization>
|
||||
<CharacterSet>Unicode</CharacterSet>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
|
||||
<ImportGroup Label="ExtensionSettings">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="Shared">
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
|
||||
</ImportGroup>
|
||||
<PropertyGroup Label="UserMacros" />
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<LinkIncremental>true</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
<TargetName>pandaJ2534_0404_32</TargetName>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<LinkIncremental>false</LinkIncremental>
|
||||
<OutDir>$(SolutionDir)$(Configuration)_$(PlatformShortName)\</OutDir>
|
||||
<TargetName>pandaJ2534_0404_32</TargetName>
|
||||
</PropertyGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
<ClCompile>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<Optimization>Disabled</Optimization>
|
||||
<PreprocessorDefinitions>WIN32;_DEBUG;_WINDOWS;_USRDLL;PANDAJ2534DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);version.lib;$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
<ClCompile>
|
||||
<WarningLevel>Level3</WarningLevel>
|
||||
<PrecompiledHeader>Use</PrecompiledHeader>
|
||||
<Optimization>MaxSpeed</Optimization>
|
||||
<FunctionLevelLinking>true</FunctionLevelLinking>
|
||||
<IntrinsicFunctions>true</IntrinsicFunctions>
|
||||
<PreprocessorDefinitions>WIN32;NDEBUG;_WINDOWS;_USRDLL;PANDAJ2534DLL_EXPORTS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
|
||||
<SDLCheck>true</SDLCheck>
|
||||
<AdditionalIncludeDirectories>$(SolutionDir);</AdditionalIncludeDirectories>
|
||||
</ClCompile>
|
||||
<Link>
|
||||
<SubSystem>Windows</SubSystem>
|
||||
<EnableCOMDATFolding>true</EnableCOMDATFolding>
|
||||
<OptimizeReferences>true</OptimizeReferences>
|
||||
<GenerateDebugInformation>true</GenerateDebugInformation>
|
||||
<AdditionalDependencies>kernel32.lib;user32.lib;gdi32.lib;winspool.lib;comdlg32.lib;advapi32.lib;shell32.lib;ole32.lib;oleaut32.lib;uuid.lib;odbc32.lib;odbccp32.lib;%(AdditionalDependencies);version.lib;$(OutDir)panda.lib</AdditionalDependencies>
|
||||
</Link>
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\panda\panda.h" />
|
||||
<ClInclude Include="constants_ISO15765.h" />
|
||||
<ClInclude Include="dllmain.h" />
|
||||
<ClInclude Include="MessagePeriodic.h" />
|
||||
<ClInclude Include="MessageRx.h" />
|
||||
<ClInclude Include="J2534Connection.h" />
|
||||
<ClInclude Include="J2534Connection_CAN.h" />
|
||||
<ClInclude Include="J2534Connection_ISO15765.h" />
|
||||
<ClInclude Include="J2534Frame.h" />
|
||||
<ClInclude Include="J2534MessageFilter.h" />
|
||||
<ClInclude Include="J2534_v0404.h" />
|
||||
<ClInclude Include="Action.h" />
|
||||
<ClInclude Include="MessageTx.h" />
|
||||
<ClInclude Include="MessageTxTimeout.h" />
|
||||
<ClInclude Include="MessageTx_CAN.h" />
|
||||
<ClInclude Include="MessageTx_ISO15765.h" />
|
||||
<ClInclude Include="PandaJ2534Device.h" />
|
||||
<ClInclude Include="resource.h" />
|
||||
<ClInclude Include="stdafx.h" />
|
||||
<ClInclude Include="synchronize.h" />
|
||||
<ClInclude Include="targetver.h" />
|
||||
<ClInclude Include="Timer.h" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</PrecompiledHeader>
|
||||
<CompileAsManaged Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">false</CompileAsManaged>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="J2534Connection.cpp" />
|
||||
<ClCompile Include="J2534Connection_CAN.cpp" />
|
||||
<ClCompile Include="J2534Connection_ISO15765.cpp" />
|
||||
<ClCompile Include="J2534MessageFilter.cpp" />
|
||||
<ClCompile Include="MessagePeriodic.cpp" />
|
||||
<ClCompile Include="MessageTxTimeout.cpp" />
|
||||
<ClCompile Include="MessageTx_CAN.cpp" />
|
||||
<ClCompile Include="MessageTx_ISO15765.cpp" />
|
||||
<ClCompile Include="PandaJ2534Device.cpp" />
|
||||
<ClCompile Include="pandaJ2534DLL.cpp" />
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">Create</PrecompiledHeader>
|
||||
<PrecompiledHeader Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">Create</PrecompiledHeader>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Timer.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\panda\panda.vcxproj">
|
||||
<Project>{5528aefb-638d-49af-b9d4-965154e7d531}</Project>
|
||||
</ProjectReference>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="pandaJ2534DLL.rc" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ClassDiagram.cd" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
|
@ -0,0 +1,155 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Filter Include="Source Files">
|
||||
<UniqueIdentifier>{4FC737F1-C7A5-4376-A066-2A32D752A2FF}</UniqueIdentifier>
|
||||
<Extensions>cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files">
|
||||
<UniqueIdentifier>{93995380-89BD-4b04-88EB-625FBE52EBFB}</UniqueIdentifier>
|
||||
<Extensions>h;hh;hpp;hxx;hm;inl;inc;xsd</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Resource Files">
|
||||
<UniqueIdentifier>{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}</UniqueIdentifier>
|
||||
<Extensions>rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms</Extensions>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\depends">
|
||||
<UniqueIdentifier>{a4cd0bce-0a2a-43d9-9c9f-b21a3b607e90}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\boilerplate">
|
||||
<UniqueIdentifier>{a85ee263-380d-4d37-b167-6629cfd5177f}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\boilerplate">
|
||||
<UniqueIdentifier>{010a0176-a146-4d3a-824a-fd683904774d}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\J2534_CAN">
|
||||
<UniqueIdentifier>{71c9502a-ee59-4d5e-873f-c9cc792e7c76}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Header Files\J2534_ISO15765">
|
||||
<UniqueIdentifier>{4fd3183a-c457-430c-b762-f767a5788bca}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\J2534_ISO15765">
|
||||
<UniqueIdentifier>{53cd179e-22d8-43e2-bc61-516d3861fae6}</UniqueIdentifier>
|
||||
</Filter>
|
||||
<Filter Include="Source Files\J2534_CAN">
|
||||
<UniqueIdentifier>{08d548b5-4d0b-4ce4-85e6-5ff3fc987758}</UniqueIdentifier>
|
||||
</Filter>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="J2534Connection.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="PandaJ2534Device.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Timer.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="J2534MessageFilter.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="synchronize.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="J2534Connection_CAN.h">
|
||||
<Filter>Header Files\J2534_CAN</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="J2534Connection_ISO15765.h">
|
||||
<Filter>Header Files\J2534_ISO15765</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="J2534_v0404.h">
|
||||
<Filter>Header Files\depends</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="..\panda\panda.h">
|
||||
<Filter>Header Files\depends</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="dllmain.h">
|
||||
<Filter>Header Files\boilerplate</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="resource.h">
|
||||
<Filter>Header Files\boilerplate</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="stdafx.h">
|
||||
<Filter>Header Files\boilerplate</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="targetver.h">
|
||||
<Filter>Header Files\boilerplate</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="J2534Frame.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageTx_ISO15765.h">
|
||||
<Filter>Header Files\J2534_ISO15765</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageRx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="constants_ISO15765.h">
|
||||
<Filter>Header Files\J2534_ISO15765</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageTx_CAN.h">
|
||||
<Filter>Header Files\J2534_CAN</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageTxTimeout.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="Action.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessageTx.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="MessagePeriodic.h">
|
||||
<Filter>Header Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="pandaJ2534DLL.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="J2534Connection.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="PandaJ2534Device.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Timer.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="J2534MessageFilter.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="J2534Connection_CAN.cpp">
|
||||
<Filter>Source Files\J2534_CAN</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="J2534Connection_ISO15765.cpp">
|
||||
<Filter>Source Files\J2534_ISO15765</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="dllmain.cpp">
|
||||
<Filter>Source Files\boilerplate</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="stdafx.cpp">
|
||||
<Filter>Source Files\boilerplate</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MessageTx_ISO15765.cpp">
|
||||
<Filter>Source Files\J2534_ISO15765</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MessageTxTimeout.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MessageTx_CAN.cpp">
|
||||
<Filter>Source Files\J2534_CAN</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="MessagePeriodic.cpp">
|
||||
<Filter>Source Files</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ResourceCompile Include="pandaJ2534DLL.rc">
|
||||
<Filter>Resource Files</Filter>
|
||||
</ResourceCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="ClassDiagram.cd" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,14 @@
|
|||
//{{NO_DEPENDENCIES}}
|
||||
// Microsoft Visual C++ generated include file.
|
||||
// Used by pandaJ2534DLL.rc
|
||||
|
||||
// Next default values for new objects
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 101
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1001
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
|
@ -0,0 +1,8 @@
|
|||
// stdafx.cpp : source file that includes just the standard includes
|
||||
// pandaJ2534DLL.pch will be the pre-compiled header
|
||||
// stdafx.obj will contain the pre-compiled type information
|
||||
|
||||
#include "stdafx.h"
|
||||
|
||||
// TODO: reference any additional headers you need in STDAFX.H
|
||||
// and not in this file
|