//============================================================================ // Name: // mki.cpp // // Summary: // A pretty simple class for controlling the parts // we can on the mercedes-combi-instrument // // Created on: // Okt 1, 2010 // // Author: // Christian Steiger //============================================================================ #include "mki.h" // constructor mki::mki() { // set data m_alert = 0; // clean up structs memset(&m_can_id_200, 0, sizeof(m_can_id_200)); memset(&m_can_id_208, 0, sizeof(m_can_id_208)); memset(&m_can_id_210, 0, sizeof(m_can_id_210)); memset(&m_can_id_308, 0, sizeof(m_can_id_308)); memset(&m_can_id_312, 0, sizeof(m_can_id_312)); memset(&m_can_id_550, 0, sizeof(m_can_id_550)); memset(&m_can_id_608, 0, sizeof(m_can_id_608)); // set message ids m_can_id_200.can_id = 0x200; m_can_id_208.can_id = 0x208; m_can_id_210.can_id = 0x210; m_can_id_308.can_id = 0x308; m_can_id_312.can_id = 0x312; m_can_id_550.can_id = 0x550; m_can_id_608.can_id = 0x608; // set message length m_can_id_200.can_dlc = 8; m_can_id_208.can_dlc = 8; m_can_id_210.can_dlc = 8; m_can_id_308.can_dlc = 8; m_can_id_312.can_dlc = 8; m_can_id_550.can_dlc = 8; m_can_id_608.can_dlc = 8; } // destructor mki::~mki() { } //============================================================================ // Summary: // Connects to an socket can interface. // Parameters: // [in] interface - name of the can interface, e.g. can0, vcan0 // [out] 0 on success, -1 on failure, sets errno. //============================================================================ int mki::connect( const char* const interface ) { return m_can.connect( interface ); } //============================================================================ // Summary: // Enables some of the available lamps in the cockpit. // // Possible values are: // MKI_ABS, MKI_ESP, MKI_ENGINE, MKI_WARN, // MKI_WARN_BLINK, MKI_FUEL_LOW // MKI_HANDBRAKE will cause alarm beep when Mph > 0 // // Combine them via logical OR to enable more than one at the same time. // Each call will reset the lamp status, so a setLamps(0) will disable all. // // Parameters: // [in] lamps - bitmask which contains the lamps to activate. //============================================================================ void mki::setLamps( const unsigned int lamps ) { // erase the used bytes to make things easier m_can_id_200.data[0] = 0; m_can_id_308.data[3] = 0; // activate handbrake lamp. can cause alarm beep when moving if ( lamps & MKI_HANDBRAKE ) m_can_id_200.data[0] |= 0x02; // activate abs lamp if ( lamps & MKI_ABS ) m_can_id_200.data[0] |= 0x04; // activate esp lamp if ( lamps & MKI_ESP ) m_can_id_200.data[0] |= 0x08; // activate warning triangle if ( lamps & MKI_WARN ) m_can_id_200.data[0] |= 0x10; // activate warning triangle and let it blink. ignores MKI_WARN. if ( lamps & MKI_WARN_BLINK ) m_can_id_200.data[0] |= 0x20; // activate fuel low lamp if ( lamps & MKI_FUEL_LOW ) m_can_id_308.data[3] |= 0x01; // activate engine lamp if ( lamps & MKI_ENGINE ) m_can_id_308.data[3] |= 0x02; } void mki::setLampsOff( void ) { // erase the used bytes to make things easier m_can_id_200.data[0] = 0; m_can_id_308.data[3] = 0; // activate handbrake lamp. can cause alarm beep when moving m_can_id_200.data[0] |= 0x00; } //============================================================================ // Summary: // Sets the Rpm. // Parameters: // [in] rpm - the rpm to be set, only values between 0 and 7000 make sense. //============================================================================ void mki::setRpm( const unsigned short rpm ) { // dont allow values higher than 7000, or you may not see anyhting const unsigned short int rpm_ = (rpm > 7000) ? 7000 : rpm; // convert the rpm for the message bytes const unsigned short int hbyte = rpm_ / 250; const unsigned short int lbyte = rpm_ - (hbyte * 250); // set variables m_can_id_308.data[1] = hbyte; m_can_id_308.data[2] = lbyte; } //============================================================================ // Summary: // Sets the Mph. // Parameters: // [in] mph - the mph to be set, only values between 0 and 160 make sense. //============================================================================ void mki::setMph( const unsigned char mph ) { // calculate low and high byte unsigned short int hbyte = mph / 10; unsigned short int lbyte = (mph - (hbyte * 10)) * 25; // filter high byte, since bit 6 and 7 make the hbyte value invalid hbyte &= 0x3F; // set address 0x200 properties m_can_id_200.data[2] = hbyte; m_can_id_200.data[3] = lbyte; m_can_id_200.data[4] = hbyte; m_can_id_200.data[5] = lbyte; // set address 0x208 properties m_can_id_208.data[4] = hbyte; m_can_id_208.data[5] = lbyte; m_can_id_208.data[6] = hbyte; m_can_id_208.data[7] = lbyte; } //============================================================================ // Summary: // Sets the cooling water temperature. // Just give the value you want to see in degree, e.g. setCWTemp(85). // Only values between 40 and 130 make sense, everything else // wont be displayed due to display limitatios. // // Parameters: // [in] temp - the temperature to be set. //============================================================================ void mki::setCWTemp( const unsigned char temp ) { // we need to add an offset of 40 to show the temperature 1:1, // since the display wont show anything when we reach 0xFF, // we will simply limit the value to the highest possible setting. m_can_id_608.data[0] = ((temp + 40) > 176) ? 176 : temp + 40; } //============================================================================ // Summary: // Sets the properties of the limit mode which is shown in the lcd-display. // // Possible values are: // MKI_LIMIT = activates a big limit view in the lcd-display, // if no changes are made it will switch back and forth // between the main and limit display for a short while, // and then stays in the main mode. // MKI_LIMIT_TEXT = activates a small limit text in the main display mode. // MKI_PERMANENT = make the MKI_LIMIT view permanently visible. // MKI_EXCEED = alarm beep and "exceeded" message in the limit view. // MKI_WINTER_TYRE = switches "limit" text to "winter tyre limit". // MKI_MPH_BLINK = let the mph value blink. // MKI_NO_MPH = show --- instad of the mph value. // // The mph value shown there can be controlled with setLimitMph(mph); // // Parameters: // [in] flags - a bitmask which control the different modes. //============================================================================ void mki::setDisplay( const unsigned int flags ) { // just kill the data content except for byte 7 // makes life much easier for us in this function unsigned short int i; for (i = 0; i < 7; i++) m_can_id_210.data[i] = 0; // enable limit display if ( flags & MKI_LIMIT ) m_can_id_210.data[5] |= 0x01; // set permanent limit display if ( flags & MKI_PERMANENT ) m_can_id_210.data[3] = 0x80; // shall the mph value blink? if ( flags & MKI_MPH_BLINK ) m_can_id_210.data[5] |= 0x02; // --- instead of mph value? if ( flags & MKI_NO_MPH ) m_can_id_210.data[5] |= 0x08; // enable winter tyre message instad of limit if ( flags & MKI_NO_MPH ) m_can_id_210.data[5] |= 0x08; // exceed warning with alarm sound if ( flags & MKI_EXCEED ) m_can_id_210.data[4] |= 0x01; // exceed warning with alarm sound if ( flags & MKI_LIMIT_TEXT ) m_can_id_210.data[4] |= 0x08; } //============================================================================ // Summary: // Sets the Mph you see in the limit display if you activate // it via setDisplay(MKI_LIMIT) or setDisplay(MKI_LIMIT_TEXT). // Parameters: // [in] mph - the mph to be set, a value between 0 and 255. //============================================================================ void mki::setDisplayMph( const unsigned char mph ) { // just copy the value m_can_id_210.data[7] = mph; } //============================================================================ // Summary: // Sets an alert message. Possible alerts are: // // MKI_OIL_LOW = shows "engine oil level, stop. ENGINE OFF!" alert. // MKI_TIRE_PRESSURE = shows "tire pressure low, check tires". // MKI_TIRE_DEFECT = shows "tire pressure low, caution tire defect!". // // The alerts can be combined via logical OR, in this case it will // alert beep once for every error and then switch back and forth // between the enabled alerts, MKI_TIRE_DEFECT however overrides // MKI_TIRE_PRESSURE, so you wont see it after setting MKI_TIRE_DEFECT. // // To deactivate the alerts just call setAlert(0). // It can also take a second or two until the alert gets active. // // Parameters: // [in] alert - see the description above. //============================================================================ void mki::setAlert( const unsigned int alert ) { // we have a alert if (alert) { // set the appropiate variable so // sendData() will send the 0x550 message m_alert = 1; // kill byte to make things easier m_can_id_550.data[0] = 0; // tire pressure low alert if ( alert & MKI_TIRE_PRESSURE ) m_can_id_550.data[0] |= 0x10; // tire defect alert if ( alert & MKI_TIRE_DEFECT ) m_can_id_550.data[0] |= 0x20; } else { // unset the appropiate variable so // sendData() wont send the 0x550 message m_alert = 0; } } //============================================================================ // Summary: // Sends all the messages the display needs to function. // You need to call this command every 50ms or so to keep // everything working, best use a while-loop like this: // // while (1) { mki_object.sendData(); usleep(50000); } // // It may be tedious, but makes usage a bit easier, and you can decide // on your own how to implement it (let it run in a seperate pthread or so). // // Be aware that the function itself sleeps a good time to prevent // write buffer overflows, together its roughly 50ms, // 60ms if you enabled alerts. // // Parameters: // none //============================================================================ // TODO mki::sendData() - Implement error handling to make it more solid. void mki::sendData(void) { // sleep 10ms between the messages to prevent // write buffer error that will happen otherwise. m_can.writeMsg(&m_can_id_200); usleep(1000); m_can.writeMsg(&m_can_id_208); usleep(1000); m_can.writeMsg(&m_can_id_210); usleep(1000); m_can.writeMsg(&m_can_id_308); usleep(1000); m_can.writeMsg(&m_can_id_312); usleep(1000); m_can.writeMsg(&m_can_id_608); usleep(1000); // Only write 550 if we have alerts if (m_alert) { m_can.writeMsg(&m_can_id_550); usleep(1000); } } //============================================================================ // Summary: // Sets the Kmh. // Works the same wike like setMph(), the Kmh will be converted // into Mph and then shown on the display. // // Parameters: // [in] mph - the mph to be set, only values between 0 and 255 make sense. //============================================================================ void mki::setKmh ( const unsigned char kmh ) { // convert bewteen kmh and mph // and call the appropiate function setMph( (char)(kmh * 0.6f) ); } //============================================================================ // Summary: // Sets the Kmh for the limit modes. // Works the same wike like setDisplayMph(), the Kmh will be converted // into Mph and then shown on the display if you used // setDisplay(MKI_LIMIT) or setDisplay(MKI_LIMIT_TEXT). // // Parameters: // [in] mph - the mph to be set, only values between 0 and 255 make sense. //============================================================================ void mki::setDisplayKmh ( const unsigned char kmh ) { // convert bewteen kmh and mph // and call the appropiate function setMph( (char)(kmh * 0.6f) ); } //============================================================================ // Summary: // Gives back a pointer to the CanIO class that is used to connect // to the can interface. Allows you to set some properties like // hideErrors() or Loopback. Be cautious with it, the mki-class isnt // really prepared for some of the errors you could cause with it. // // Parameters: // [out] mph - the mph to be set, only values between 0 and 255 make sense. //============================================================================ // TODO mki::getInterface - Try to optimize the class in a way that allows us to remove this function. // At the moment the error handling is pretty bad, so you will get spammed with error messages or // gibberisch when you try to send and the interface isnt up for example, so this needs work. CanIO* mki::getInterface(void) { // return the reference return &m_can; }