320 lines
9.2 KiB
C++
320 lines
9.2 KiB
C++
/*
|
|
; Project: Open Vehicle Monitor System
|
|
; Date: 15th September 2020
|
|
;
|
|
; Changes:
|
|
; 1.0 Initial release
|
|
;
|
|
; (C) 2011 Michael Stegen / Stegen Electronics
|
|
; (C) 2011-2017 Mark Webb-Johnson
|
|
; (C) 2011 Sonny Chen @ EPRO/DX
|
|
; (C) 2020 Chris Staite
|
|
;
|
|
; Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
; of this software and associated documentation files (the "Software"), to deal
|
|
; in the Software without restriction, including without limitation the rights
|
|
; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
; copies of the Software, and to permit persons to whom the Software is
|
|
; furnished to do so, subject to the following conditions:
|
|
;
|
|
; The above copyright notice and this permission notice shall be included in
|
|
; all copies or substantial portions of the Software.
|
|
;
|
|
; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
; THE SOFTWARE.
|
|
*/
|
|
|
|
#include "ovms_log.h"
|
|
static const char *TAG = "re-tp";
|
|
|
|
#include "retools_testerpresent.h"
|
|
#include "vehicle.h"
|
|
|
|
namespace {
|
|
|
|
bool ReadHexString(const char* value, unsigned long& output)
|
|
{
|
|
char* ptr = nullptr;
|
|
errno = 0;
|
|
output = strtoul(value, &ptr, 16);
|
|
if (ptr == value || errno != 0 || *ptr)
|
|
{
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
canbus* GetCan(int bus)
|
|
{
|
|
char name[] = "canx";
|
|
name[3] = '0' + bus;
|
|
auto can = reinterpret_cast<canbus*>(MyPcpApp.FindDeviceByName(name));
|
|
if (can != nullptr && (can->GetPowerMode() != On || can->m_mode != CAN_MODE_ACTIVE))
|
|
{
|
|
can = nullptr;
|
|
}
|
|
return can;
|
|
}
|
|
|
|
} // anon namespace
|
|
|
|
OvmsReToolsTesterPresent::OvmsReToolsTesterPresent(
|
|
canbus* bus, uint16_t ecu, int interval) :
|
|
m_bus(bus),
|
|
m_id(ecu),
|
|
m_ticker(0u),
|
|
m_interval(interval)
|
|
{ }
|
|
|
|
void OvmsReToolsTesterPresent::Ticker1()
|
|
{
|
|
++m_ticker;
|
|
if ((m_ticker % m_interval) == 0)
|
|
{
|
|
SendTesterPresent();
|
|
}
|
|
}
|
|
|
|
void OvmsReToolsTesterPresent::SendTesterPresent()
|
|
{
|
|
CAN_frame_t testerFrame = {
|
|
m_bus,
|
|
nullptr,
|
|
{ .B = { 8, 0, CAN_no_RTR, CAN_frame_std, 0 } },
|
|
m_id,
|
|
{ .u8 = {
|
|
(ISOTP_FT_SINGLE<<4) + 2, VEHICLE_POLL_TYPE_TESTERPRESENT, 0, 0, 0, 0, 0, 0
|
|
} }
|
|
};
|
|
if (m_bus->Write(&testerFrame) == ESP_FAIL)
|
|
{
|
|
ESP_LOGE(TAG, "Error sending tester present to %03x", m_id);
|
|
}
|
|
}
|
|
|
|
class OvmsReToolsTesterPresentInit
|
|
{
|
|
public:
|
|
OvmsReToolsTesterPresentInit();
|
|
~OvmsReToolsTesterPresentInit();
|
|
|
|
void Start();
|
|
void Stop();
|
|
|
|
private:
|
|
static void Start(int, OvmsWriter*, OvmsCommand*, int, const char* const*);
|
|
static void List(int, OvmsWriter*, OvmsCommand*, int, const char* const*);
|
|
static void Stop(int, OvmsWriter*, OvmsCommand*, int, const char* const*);
|
|
static void StopAll(int, OvmsWriter*, OvmsCommand*, int, const char* const*);
|
|
|
|
void Ticker1(std::string, void*);
|
|
|
|
bool m_registered;
|
|
OvmsMutex m_testersMutex;
|
|
std::vector<OvmsReToolsTesterPresent> m_testers;
|
|
} OvmsReToolsTesterPresentInitInstance __attribute__ ((init_priority (8801)));
|
|
|
|
OvmsReToolsTesterPresentInit::OvmsReToolsTesterPresentInit() :
|
|
m_registered(false),
|
|
m_testersMutex(),
|
|
m_testers()
|
|
{
|
|
OvmsCommand* cmd_reobdii = MyCommandApp.FindCommandFullName("re obdii");
|
|
if (cmd_reobdii == nullptr)
|
|
{
|
|
ESP_LOGE(TAG, "Tester present command depends on re command");
|
|
return;
|
|
}
|
|
OvmsCommand* cmd_tester = cmd_reobdii->RegisterCommand(
|
|
"tester", "Tester present sender"
|
|
);
|
|
cmd_tester->RegisterCommand(
|
|
"start", "Start sending a tester present signal to an ECU",
|
|
PickOvmsCommandExecuteCallback(OvmsReToolsTesterPresentInit::Start),
|
|
"<bus> <ecu> <interval>", 3, 3
|
|
);
|
|
cmd_tester->RegisterCommand(
|
|
"list", "List current tester present signals",
|
|
&OvmsReToolsTesterPresentInit::List
|
|
);
|
|
cmd_tester->RegisterCommand(
|
|
"stop", "Stop tester present for an ECU",
|
|
PickOvmsCommandExecuteCallback(OvmsReToolsTesterPresentInit::Stop),
|
|
"<bus> <ecu>", 2, 2
|
|
);
|
|
cmd_tester->RegisterCommand(
|
|
"stopall", "Stop tester present for all ECUs",
|
|
&OvmsReToolsTesterPresentInit::StopAll
|
|
);
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::Start()
|
|
{
|
|
if (m_registered == true)
|
|
{
|
|
return;
|
|
}
|
|
ESP_LOGD(TAG, "Starting tester present ticker");
|
|
MyEvents.RegisterEvent(
|
|
TAG, "ticker.1",
|
|
std::bind(
|
|
&OvmsReToolsTesterPresentInit::Ticker1, this,
|
|
std::placeholders::_1, std::placeholders::_2
|
|
)
|
|
);
|
|
m_registered = true;
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::Stop()
|
|
{
|
|
if (m_registered == false)
|
|
{
|
|
return;
|
|
}
|
|
ESP_LOGD(TAG, "Stopping tester present ticker");
|
|
MyEvents.DeregisterEvent(TAG);
|
|
m_registered = false;
|
|
}
|
|
|
|
OvmsReToolsTesterPresentInit::~OvmsReToolsTesterPresentInit()
|
|
{
|
|
Stop();
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::Ticker1(std::string, void*)
|
|
{
|
|
OvmsMutexLock lock(&OvmsReToolsTesterPresentInitInstance.m_testersMutex);
|
|
for (auto& tester : OvmsReToolsTesterPresentInitInstance.m_testers)
|
|
{
|
|
tester.Ticker1();
|
|
}
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::Start(
|
|
int, OvmsWriter* writer, OvmsCommand*, int, const char* const* argv)
|
|
{
|
|
unsigned long bus, ecu;
|
|
bool valid = true;
|
|
if (!ReadHexString(argv[0], bus) || bus < 1 || bus > 4)
|
|
{
|
|
writer->printf("Error: Invalid bus to scan %s", argv[0]);
|
|
valid = false;
|
|
}
|
|
if (!ReadHexString(argv[1], ecu) || ecu <= 0 || ecu >= 0xfff)
|
|
{
|
|
writer->printf("Error: Invalid ECU Id to scan %s", argv[1]);
|
|
valid = false;
|
|
}
|
|
int interval = atoi(argv[2]);
|
|
if (interval <= 0)
|
|
{
|
|
writer->printf("Error: Invalid interval %s", argv[2]);
|
|
valid = false;
|
|
}
|
|
if (!valid)
|
|
{
|
|
return;
|
|
}
|
|
canbus* can = GetCan(bus);
|
|
if (can == nullptr)
|
|
{
|
|
writer->printf("CAN not started in active mode, please start and try again");
|
|
valid = false;
|
|
}
|
|
if (valid)
|
|
{
|
|
OvmsMutexLock lock(&OvmsReToolsTesterPresentInitInstance.m_testersMutex);
|
|
for (auto& tester : OvmsReToolsTesterPresentInitInstance.m_testers)
|
|
{
|
|
if (tester.Bus() == can && tester.Ecu() == ecu)
|
|
{
|
|
writer->printf("Already sending tester present to that ECU");
|
|
return;
|
|
}
|
|
}
|
|
if (OvmsReToolsTesterPresentInitInstance.m_testers.empty())
|
|
{
|
|
OvmsReToolsTesterPresentInitInstance.Start();
|
|
}
|
|
OvmsReToolsTesterPresentInitInstance.m_testers.push_back(
|
|
OvmsReToolsTesterPresent(can, ecu, interval)
|
|
);
|
|
}
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::List(
|
|
int, OvmsWriter* writer, OvmsCommand*, int, const char* const*)
|
|
{
|
|
OvmsMutexLock lock(&OvmsReToolsTesterPresentInitInstance.m_testersMutex);
|
|
for (auto& tester : OvmsReToolsTesterPresentInitInstance.m_testers)
|
|
{
|
|
writer->printf(
|
|
"Tester present sending to %03x on bus %d every %d seconds",
|
|
tester.Ecu(), tester.Bus()->m_busnumber + 1, tester.Interval()
|
|
);
|
|
}
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::Stop(
|
|
int, OvmsWriter* writer, OvmsCommand*, int, const char* const* argv)
|
|
{
|
|
unsigned long bus, ecu;
|
|
bool valid = true;
|
|
if (!ReadHexString(argv[0], bus) || bus < 1 || bus > 4)
|
|
{
|
|
writer->printf("Error: Invalid bus %s", argv[0]);
|
|
valid = false;
|
|
}
|
|
if (!ReadHexString(argv[1], ecu) || ecu <= 0 || ecu >= 0xfff)
|
|
{
|
|
writer->printf("Error: Invalid ECU Id %s", argv[1]);
|
|
valid = false;
|
|
}
|
|
if (!valid)
|
|
{
|
|
return;
|
|
}
|
|
|
|
OvmsMutexLock lock(&OvmsReToolsTesterPresentInitInstance.m_testersMutex);
|
|
auto it = OvmsReToolsTesterPresentInitInstance.m_testers.begin();
|
|
while (it != OvmsReToolsTesterPresentInitInstance.m_testers.end())
|
|
{
|
|
if (it->Bus()->m_busnumber + 1 == bus && it->Ecu() == ecu)
|
|
{
|
|
OvmsReToolsTesterPresentInitInstance.m_testers.erase(it);
|
|
writer->puts("Stopped sending");
|
|
break;
|
|
}
|
|
++it;
|
|
}
|
|
if (it == OvmsReToolsTesterPresentInitInstance.m_testers.end())
|
|
{
|
|
writer->puts("Error: Not sending tester present to that");
|
|
}
|
|
if (OvmsReToolsTesterPresentInitInstance.m_testers.empty())
|
|
{
|
|
OvmsReToolsTesterPresentInitInstance.Stop();
|
|
}
|
|
}
|
|
|
|
void OvmsReToolsTesterPresentInit::StopAll(
|
|
int, OvmsWriter* writer, OvmsCommand*, int, const char* const*)
|
|
{
|
|
OvmsMutexLock lock(&OvmsReToolsTesterPresentInitInstance.m_testersMutex);
|
|
if (OvmsReToolsTesterPresentInitInstance.m_testers.empty())
|
|
{
|
|
writer->puts("Error: Not sending tester present to anything");
|
|
}
|
|
else
|
|
{
|
|
OvmsReToolsTesterPresentInitInstance.m_testers.clear();
|
|
OvmsReToolsTesterPresentInitInstance.Stop();
|
|
writer->puts("Stopped all");
|
|
}
|
|
}
|