OVMS3/OVMS.V3/components/vehicle/vehicle_duktape.cpp

515 lines
12 KiB
C++

/*
; Project: Open Vehicle Monitor System
; Date: 14th March 2017
;
; Changes:
; 1.0 Initial release
;
; (C) 2011 Michael Stegen / Stegen Electronics
; (C) 2011-2017 Mark Webb-Johnson
; (C) 2011 Sonny Chen @ EPRO/DX
;
; 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 = "vehicle";
#include <stdio.h>
#include <algorithm>
#include <ovms_command.h>
#include <ovms_script.h>
#include <ovms_metrics.h>
#include <ovms_notify.h>
#include <metrics_standard.h>
#ifdef CONFIG_OVMS_COMP_WEBSERVER
#include <ovms_webserver.h>
#endif // #ifdef CONFIG_OVMS_COMP_WEBSERVER
#include <ovms_peripherals.h>
#include <string_writer.h>
#include "vehicle.h"
#ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleType(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle != NULL)
{
duk_push_string(ctx, MyVehicleFactory.m_currentvehicletype.c_str());
return 1;
}
else
{
return 0;
}
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleWakeup(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
switch(MyVehicleFactory.m_currentvehicle->CommandWakeup())
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleHomelink(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
int homelink = duk_to_int(ctx,0);
int durationms = duk_to_int(ctx,-1);
if (durationms==0) durationms = 1000;
if ((homelink<1)||(homelink>3))
{ duk_push_boolean(ctx, 0); }
else if (durationms < 100)
{ duk_push_boolean(ctx, 0); }
else
{
switch(MyVehicleFactory.m_currentvehicle->CommandHomelink(homelink-1, durationms))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleClimateControl(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
bool on = duk_to_boolean(ctx,0);
switch(MyVehicleFactory.m_currentvehicle->CommandClimateControl(on))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleLock(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
const char* pin = duk_safe_to_string(ctx, 0);
switch(MyVehicleFactory.m_currentvehicle->CommandLock(pin))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleUnlock(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
const char* pin = duk_safe_to_string(ctx, 0);
switch(MyVehicleFactory.m_currentvehicle->CommandUnlock(pin))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleValet(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
const char* pin = duk_safe_to_string(ctx, 0);
switch(MyVehicleFactory.m_currentvehicle->CommandActivateValet(pin))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleUnvalet(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
const char* pin = duk_safe_to_string(ctx, 0);
switch(MyVehicleFactory.m_currentvehicle->CommandDeactivateValet(pin))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleSetChargeMode(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
const char* mode = duk_safe_to_string(ctx, 0);
OvmsVehicle::vehicle_mode_t tmode = (OvmsVehicle::vehicle_mode_t)chargemode_key(mode);
switch(MyVehicleFactory.m_currentvehicle->CommandSetChargeMode(tmode))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleSetChargeCurrent(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
int limit = duk_to_int(ctx,0);
switch(MyVehicleFactory.m_currentvehicle->CommandSetChargeCurrent(limit))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleSetChargeTimer(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
bool timeron = duk_to_boolean(ctx,0);
int timerstart = duk_to_int(ctx,-1);
switch(MyVehicleFactory.m_currentvehicle->CommandSetChargeTimer(timeron, timerstart))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleStopCharge(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
switch(MyVehicleFactory.m_currentvehicle->CommandStopCharge())
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleStartCharge(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
switch(MyVehicleFactory.m_currentvehicle->CommandStartCharge())
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleStartCooldown(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
switch(MyVehicleFactory.m_currentvehicle->CommandCooldown(true))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleStopCooldown(duk_context *ctx)
{
if (MyVehicleFactory.m_currentvehicle==NULL)
{
duk_push_boolean(ctx, 0);
}
else
{
switch(MyVehicleFactory.m_currentvehicle->CommandCooldown(false))
{
case OvmsVehicle::Success:
duk_push_boolean(ctx, 1);
break;
default:
duk_push_boolean(ctx, 0);
break;
}
}
return 1;
}
/**
* DukOvmsVehicleObdRequest: OBD/UDS PollSingleRequest wrapper (synchronous)
*
* Javascript API:
* var obdResult = OvmsVehicle.ObdRequest({
* txid: <int>,
* rxid: <int>,
* request: <string>|<Uint8Array>, // hex encoded string or binary byte array
* [bus: <string>,] // default: "can1"
* [timeout: <int>,] // in ms, default: 3000
* [protocol: <int>,] // default: 0 = ISOTP_STD, see vehicle.h
* });
*
* obdResult = {
* error: <int>, // see PollSingleRequest, 0 = success
* errordesc: <string>, // error description / emtpy on success
* response: <Uint8Array>, // only if error = 0: binary response byte array
* response_hex: <string>, // only if error = 0: hex encoded response string
* }
*/
duk_ret_t OvmsVehicleFactory::DukOvmsVehicleObdRequest(duk_context *ctx)
{
DukContext dc(ctx);
int error = 0;
std::string errordesc;
std::string bus = "can1";
uint32_t txid = 0, rxid = 0;
std::string request, response;
int timeout = 3000;
uint8_t protocol = ISOTP_STD;
if (!MyVehicleFactory.m_currentvehicle)
{
error = -1000;
errordesc = "No vehicle module selected";
}
else if (!duk_is_object(ctx, 0))
{
error = -1001;
errordesc = "No request object given";
}
else
{
// Read arguments:
if (duk_get_prop_string(ctx, 0, "bus"))
bus = duk_to_string(ctx, -1);
duk_pop(ctx);
if (duk_get_prop_string(ctx, 0, "timeout"))
timeout = duk_to_int(ctx, -1);
duk_pop(ctx);
if (duk_get_prop_string(ctx, 0, "protocol"))
protocol = duk_to_int(ctx, -1);
duk_pop(ctx);
if (duk_get_prop_string(ctx, 0, "txid"))
txid = duk_to_int(ctx, -1);
else
error = -1002;
duk_pop(ctx);
if (duk_get_prop_string(ctx, 0, "rxid"))
rxid = duk_to_int(ctx, -1);
else
error = -1002;
duk_pop(ctx);
if (duk_get_prop_string(ctx, 0, "request"))
{
if (duk_is_buffer_data(ctx, -1))
{
size_t size;
void *data = duk_get_buffer_data(ctx, -1, &size);
request.resize(size, '\0');
memcpy(&request[0], data, size);
}
else
{
request = hexdecode(duk_to_string(ctx, -1));
}
}
duk_pop(ctx);
// Validate arguments:
canbus* device = (canbus*)MyPcpApp.FindDeviceByName(bus.c_str());
if (error != 0)
{
errordesc = "Missing mandatory argument";
}
else if (device == NULL || (txid <= 0 || (txid != 0x7df && rxid <= 0) ||
request.size() == 0) || timeout <= 0)
{
error = -1003;
errordesc = "Invalid argument";
}
// Execute request:
if (error == 0)
{
error = MyVehicleFactory.m_currentvehicle->PollSingleRequest(
device, txid, rxid, request, response, timeout, protocol);
if (error == POLLSINGLE_TXFAILURE)
errordesc = "Transmission failure (CAN bus error)";
else if (error < 0)
errordesc = "Timeout waiting for poller/response";
else if (error)
{
errordesc = "Request failed with response error code " + int_to_hex((uint8_t)error);
const char* errname = MyVehicleFactory.m_currentvehicle->PollResultCodeName(error);
if (errname)
{
errordesc += ' ';
errordesc += errname;
}
}
}
}
// Push result object:
duk_idx_t obj_idx = dc.PushObject();
dc.Push(error);
dc.PutProp(obj_idx, "error");
dc.Push(errordesc);
dc.PutProp(obj_idx, "errordesc");
if (!error)
{
dc.PushBinary(response);
dc.PutProp(obj_idx, "response");
dc.Push(hexencode(response));
dc.PutProp(obj_idx, "response_hex");
}
return 1;
}
#endif // #ifdef CONFIG_OVMS_SC_JAVASCRIPT_DUKTAPE