Merge pull request #49 from diamondman/feature/–J2534_windows_driver

Feature/j2534 windows driver
master
George Hotz 2017-12-07 17:31:16 -08:00 committed by GitHub
commit 15bfed8d34
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
117 changed files with 9835 additions and 0 deletions

306
drivers/windows/.gitignore vendored 100644
View File

@ -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

View File

@ -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;
}

View File

@ -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>

View File

@ -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>

View File

@ -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

View 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

View File

@ -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>

View File

@ -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>

View File

@ -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>

View File

@ -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 "";
}
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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

View 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

View File

@ -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>

View File

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 348 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 112 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 93 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

View File

@ -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 vendors
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 frames 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. Its
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 doesnt 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 filters 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
partners 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

View File

@ -0,0 +1,2 @@
#32 bit: HKEY_LOCAL_MACHINE\SOFTWARE\PassThruSupport
#64 bit: HKEY_LOCAL_MACHINE\SOFTWARE\WOW6432Node\PassThruSupport

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 45 KiB

View File

@ -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.

View File

@ -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) &lt; 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>

View File

@ -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>

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

View File

@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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;
};
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

View File

@ -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>

View File

@ -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>

Binary file not shown.

View File

@ -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

View 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>

View File

@ -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>

View File

@ -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());
}
};
}

View File

@ -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);
}

View File

@ -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

View File

@ -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;
}

View File

@ -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);

View File

@ -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());
}

View File

@ -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;
};

File diff suppressed because it is too large Load Diff

View File

@ -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>

View File

@ -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>

View File

@ -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);
}
}
}
};
}

View File

@ -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

View 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>

View File

@ -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>

View File

@ -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;
};

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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;
}
}

View File

@ -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;
}
};

View File

@ -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);
}
}

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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);
}

View File

@ -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;
};

View File

@ -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);

View File

@ -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());
}
}
}

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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;
};

View File

@ -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();
}
}
}

View File

@ -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;
};

View File

@ -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;
}

View File

@ -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;
};

View File

@ -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.
}

View File

@ -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;
};

View File

@ -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());
}
}
}

View File

@ -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;
};

View File

@ -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();
}

View File

@ -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;
};

View File

@ -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)

View File

@ -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;
}

View File

@ -0,0 +1,4 @@
#pragma once
#include "stdafx.h"
extern HMODULE thisdll;

View File

@ -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);
}

Binary file not shown.

View File

@ -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>

View File

@ -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>

View File

@ -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

View File

@ -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

Some files were not shown because too many files have changed in this diff Show More