diff options
| author | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
|---|---|---|
| committer | Sven Eisenhauer <sven@sven-eisenhauer.net> | 2023-11-10 15:11:48 +0100 |
| commit | 33613a85afc4b1481367fbe92a17ee59c240250b (patch) | |
| tree | 670b842326116b376b505ec2263878912fca97e2 /Master/Real-Time Systems/mki/src | |
| download | Studium-33613a85afc4b1481367fbe92a17ee59c240250b.tar.gz Studium-33613a85afc4b1481367fbe92a17ee59c240250b.tar.bz2 | |
Diffstat (limited to 'Master/Real-Time Systems/mki/src')
| -rw-r--r-- | Master/Real-Time Systems/mki/src/libcanio.cpp | 680 | ||||
| -rw-r--r-- | Master/Real-Time Systems/mki/src/libcanio.h | 81 | ||||
| -rw-r--r-- | Master/Real-Time Systems/mki/src/mki.cpp | 439 | ||||
| -rw-r--r-- | Master/Real-Time Systems/mki/src/mki.h | 86 |
4 files changed, 1286 insertions, 0 deletions
diff --git a/Master/Real-Time Systems/mki/src/libcanio.cpp b/Master/Real-Time Systems/mki/src/libcanio.cpp new file mode 100644 index 0000000..52cf12c --- /dev/null +++ b/Master/Real-Time Systems/mki/src/libcanio.cpp @@ -0,0 +1,680 @@ +//============================================================================ +// Name: +// libcanio.cpp +// +// Summary: +// A pretty simple library for the SocketCan layer, which trys to make +// the communication with the interfaces a bit easier, thus saving the +// tedious research time needed to get things up and running. +// +// Created on: +// Sep 24, 2010 +// +// Author: +// Christian Steiger +//============================================================================ + +// TODO CanIO interface - Read me first! +// As you can see there are a lot of "placeholder routine" TODOs in this file, +// normally filters can be set per setsocketopt, but not during runtime. +// Well, it was mentioned on the following page that this is possible... +// http://www.brownhat.org/docs/socketcan/llcf-api.html +// ...but i wasnt yet able to find the one command to do it, +// and my time for this project is rapidly running out. So the current +// filter implementation is a crude one in software that needs to be +// replaced with the real thing. Comments and function types already 'fit' +// more or less, so changes on the class interface shouldnt be neccesary. + +// Includes +#include "libcanio.h" + +// Constructor +CanIO::CanIO() +{ + // set default variables + m_socket = 0; + m_print_errors = 1; + m_filter = 0; + m_filter_size = 0; + m_filter_active = 0; +} + +// Destructor +CanIO::~CanIO() +{ + // properly close the socket + disconnect(); +} + +//============================================================================ +// 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 CanIO::connect(const char* const interface) +{ + // disconnect if theres already an socket present + if (m_socket) + disconnect(); + + // create needed variables + struct sockaddr_can addr; + struct ifreq ifr; + int ret; + + // create a socket handler + m_socket = socket(PF_CAN, SOCK_RAW, CAN_RAW); + + // invalid socket_handler? + if (m_socket < 0) + { + // print error message if wanted + if (m_print_errors) + perror("CanIO::connect, socket"); + + // return the result + return m_socket; + } + + // copy the name of the wanted interface into the ifreq struct + strcpy(ifr.ifr_name, interface); + + // and get the interface index via ioctl for further operations + ret = ioctl(m_socket, SIOCGIFINDEX, &ifr); + + // check for errors + if (ret < 0) + { + // prints errno message if wanted + if (m_print_errors) + perror("CanIO::connect, ioctl"); + + // close socket + disconnect(); + + // return the result + return ret; + } + + if (m_filter_active) + setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_FILTER, + m_filter, + m_filter_size * sizeof(can_filter) + ); + + // copy the info we got from the ioctl call + addr.can_ifindex = ifr.ifr_ifindex; + + // set the protocol/implementation we want to use + addr.can_family = AF_CAN; + + // bind the socket to the device + ret = bind(m_socket, (struct sockaddr *)&addr, sizeof(addr)); + + // check for errors and prints errno message if wanted + if (ret < 0) + { + // print errormessage if wanted + if (m_print_errors) + perror("CanIO::connect, bind"); + + // close socket + disconnect(); + } + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// Disconnects from a socket can interface +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::disconnect(void) +{ + // just abort if there isnt a socket + if (!m_socket) + return 0; + + // close socket connection + int ret = close(m_socket); + + // set m_socket to 0 + m_socket = 0; + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::disconnect, close"); + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// Reads a can message from the device. The read ist blocking, +// if there arent new messages it will wait until one is available! +// Parameters: +// [in] frame - pointer to a can_frame where the message data is stored. +// take a look in /usr/include/linux/can.h for more details. +// The message type is also in the can_id field, use the masks +// CAN_EFF_FLAG, CAN_RTR_FLAG and CAN_ERR_FLAG to determine it. +// [in] timestamp - a pointer to a timeval struct, contains sec and usec. +// [out] 0 on success, -1 on failure (sets errno), -2 on incomplete frames. +//============================================================================ +ssize_t CanIO::readMsg(can_frame* frame, timeval* timestamp) +{ + // detect nullpointer + if (!frame) + { + // set errno, invalid argument + errno = EINVAL; + + // print error message if wanted + if (m_print_errors) + perror("CanIO::readMsg"); + + // return the failure + return -1; + } + + // create temporary variables + ssize_t nbytes; + + // look at the placeholder comment below + readmsg_loop: + + // read a can message from the bus + nbytes = read(m_socket, frame, sizeof(can_frame)); + + // check for errors + if (nbytes < 0) + { + // print errno message if wanted + if (m_print_errors) + perror("CanIO::readMsg, read"); + + // return the result + return nbytes; + } + + // check for a complete frame + // note: we cant fetch missing bytes, each read, even with a byte length of 1, + // will get the starting bytes of a new message instead of the missing ones. + if (nbytes < (signed int)sizeof(can_frame)) + { + // print error message if wanted + if (m_print_errors) + fprintf(stderr, "CanIO::readMsg, read: incomplete CAN frame.\n"); + + // returns -2 for error indication + return -2; + } + + // check if a timestamp is wanted + if ( timestamp ) + { + // misuse the nbyte variable to get ioctls result + nbytes = ioctl(m_socket, SIOCGSTAMP, timestamp); + + // was there an error? + if (nbytes < 0) + { + // print error if wanted + if (m_print_errors) + perror("CanIO::readMsg, ioctl"); + + // returns the result + return nbytes; + } + } + + // TODO CanIO::ReadMsg - Placeholder, remove this part when you rewrite the filter functions. + // Its a simple goto command, ugly, but saves code. Dont forget to remove the mark above too. + if (m_filter_active > 0) + while(!isVisible(frame->can_id)) + goto readmsg_loop; + + // everything ok, return 0 + return 0; +} + + +//============================================================================ +// Summary: +// Trys to write a can message to the device. +// Parameters: +// [in] frame - pointer to a can_frame struct which contains the message_data. +// [in] frame - pointer to a can_frame struct where the message data is stored. +// take a look in /usr/include/linux/can.h for more details. +// The message type is also in the can_id field, use the flags +// CAN_EFF_FLAG, CAN_RTR_FLAG and CAN_ERR_FLAG to set it. +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +ssize_t CanIO::writeMsg(const can_frame* const frame) +{ + // detect nullpointer + if (!frame) + { + // set errno, invalid argument + errno = EINVAL; + + // print error message if wanted + if (m_print_errors) + perror("CanIO::writeMsg"); + + // return the failure + return -1; + } + + // try to write to the device and return the result + int ret = write(m_socket, frame, sizeof(struct can_frame)); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::writeMsg, write"); + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// Dont print error messages on stderr. +// Useful if you do want to to the errorhandling yourself. +// Parameters: +// none +//============================================================================ +void CanIO::hideErrors(void) +{ + m_print_errors = 0; +} + +//============================================================================ +// Summary: +// Print error messages on stderr. +// Useful for debugging purposes, enabled per default. +// Parameters: +// none +//============================================================================ +void CanIO::showErrors(void) +{ + m_print_errors = 1; +} + + +//============================================================================ +// Summary: +// The driver is able to generate error frames which can be passed to the +// application in the same way like other can messages, +// This command enables this feature. +// Parameters: +// [in] mask - The errors are divided in different error classes which +// can be filtered with the appropiate masks. +// To get every error just ignore this argument, otherwise +// set the masks for the errors you would like to see. +// Take a look at /usr/include/linux/can/error.h for masks. +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::showCanErrors(const can_err_mask_t err_mask) +{ + // create temporary variables + can_err_mask_t mask = err_mask; + + // check the mask value + if (!mask) + mask = CAN_ERR_MASK; + + // return the results of setsockopt + int ret = setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_ERR_FILTER, + &mask, + sizeof(mask) + ); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::showCanErrors, setsockopt"); + + // return the result + return ret; + +} + +//============================================================================ +// Summary: +// The driver can generate error frames which can be passed to the +// application in the same way like other can messages, +// this command disables this feature (default). +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::hideCanErrors(void) +{ + // set the mask to zero + can_err_mask_t mask = 0; + + // return the results of setsockopt + int ret = setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_ERR_FILTER, + &mask, + sizeof(mask) + ); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::hideCanErrors, setsockopt"); + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// TODO CanIO::enableLoopBack() - Describe me! +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::enableLoopBack(void) +{ + // create temporary variables + const int loopback = 1; + int ret; + + // set the loopback state + ret = setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_LOOPBACK, + &loopback, + sizeof(loopback) + ); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::enableLoopBack, setsockopt"); + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// TODO CanIO::disableLoopBack() - Describe me! +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::disableLoopBack(void) +{ + // create temporary variables + const int loopback = 0; + int ret; + + // set the loopback state + ret = setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_LOOPBACK, + &loopback, + sizeof(loopback) + ); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::disableLoopBack, setsockopt"); + + // return the result + return ret; +} + + +//============================================================================ +// Summary: +// TODO CanIO::enableRecvOwnMsgs() - Describe me! +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::enableRecvOwnMsgs(void) +{ + // create temporary variables + const int recv_own_msgs = 1; + int ret; + + // set the loopback state + ret = setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_RECV_OWN_MSGS, + &recv_own_msgs, + sizeof(recv_own_msgs) + ); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::enableRecvOwnMsgs, setsockopt"); + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// TODO CanIO::disableRecvOwnMsgs() - Describe me! +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +int CanIO::disableRecvOwnMsgs(void) +{ + // create temporary variables + const int recv_own_msgs = 0; + int ret; + + // set the loopback state + ret = setsockopt( + m_socket, + SOL_CAN_RAW, + CAN_RAW_RECV_OWN_MSGS, + &recv_own_msgs, + sizeof(recv_own_msgs) + ); + + // check for errors and prints errno message if wanted + if (ret < 0 && m_print_errors) + perror("CanIO::disableRecvOwnMsgs, setsockopt"); + + // return the result + return ret; +} + +//============================================================================ +// Summary: +// Adds a custom can id filter +// Parameters: +// [in] rfilter - Points to an can_filter struct which contains the filter. +// [in] size - The size of the rfilter. +// [out] 0 on success, -1 on failure, sets errno. +// +// Filter example: +// This shows messages with an id between 0x200 and 0x2FF: +// rfilter.can_id = 0x200; +// rfilter.can_mask = 0xF00; +// +// While this hides messages with in id between 0x200 and 0x2FF: +// rfilter.can_id = 0x200 | CAN_INV_FILTER; +// rfilter.can_mask = 0xF00; +// +// More filters can be combined like this: +// rfilter[0].can_id = 0x00001234; // exactly this EFF frame +// rfilter[0].can_mask = CAN_EFF_MASK; +// rfilter[1].can_id = 0x234; // exactly this SFF frame +// rfilter[1].can_mask = CAN_SFF_MASK; +//============================================================================ +// TODO CanIO::addFilter() - Placeholder routine, rewrite for setsockopt. +int CanIO::addFilter(const can_filter* const filter, const unsigned int size) +{ + // detect nullpointer and wrong size + if (!filter || size < sizeof(can_filter)) + { + // set errno, invalid argument + errno = EINVAL; + + // print error message if wanted + if (m_print_errors) + perror("CanIO::addFilter"); + + // return the failure + return -1; + } + + // calculate the arraysize + unsigned int arraysize = (size / sizeof(can_filter)); + + // if there arnt already rules defined + if (!m_filter) + { + // create a new array of pointers to can_filter + m_filter = new can_filter[arraysize]; + + // just copy the data + memcpy(m_filter, filter, size); + + // set the new arraysize + m_filter_size = arraysize; + } + + // if there are already rules, extend the set + else + { + // copy the pointer from the old array + can_filter *temp = m_filter; + + // create a new one, with the size of the two rulesets + m_filter = new can_filter[ arraysize + m_filter_size ]; + + // copy the old one + memcpy(m_filter, temp, m_filter_size * sizeof(can_filter)); + + // copy the new one after the end of the old one + memcpy(m_filter + m_filter_size, filter, size); + + // set the new filter size + m_filter_size += arraysize; + + // delete the content of the old pointer + delete temp; + } + + // enable the filter + if (!m_filter_active) + m_filter_active = 1; + + // everything okay + return 0; +} + +//============================================================================ +// Summary: +// Enables the filter, put already stored filter rules back to work. +// addFilter does this automatically, use disableFilter to prevent it. +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +// TODO CanIO:enableFilter() - Placeholder routine, rewrite for setsockopt. +int CanIO::enableFilter(void) +{ + // sets filter activity + m_filter_active = 1; + + // placeholder for setsockopt returns + return 0; +} + +//============================================================================ +// Summary: +// Disables the Filter, but keep the filter rules in the background. +// Stays disabled until you call enableFilter, regardless of addFilter calls. +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +// TODO CanIO:disableFilter() - Placeholder routine, rewrite for setsockopt. +int CanIO::disableFilter(void) +{ + // sets filter activity + m_filter_active = -1; + + // placeholder for setsockopt returns + return 0; +} + +//============================================================================ +// Summary: +// Simply resets the filter. +// Parameters: +// [out] 0 on success, -1 on failure, sets errno. +//============================================================================ +// TODO CanIO::clearFilter() - Placeholder routine, rewrite for setsockopt. +int CanIO::clearFilter(void) +{ + // reset filter size + m_filter_size = 0; + + // delete only when there is a pointer + if (m_filter) + delete m_filter; + + // Everything okay + return 0; +} + +//============================================================================ +// Summary: +// Checks if the given can id is visible or not. +// Dont use this function, it will be obsolete when +// the filter functions get a better implementation +// Parameters: +// [in] id - The can id +// [out] True or false, depending on visibility +//============================================================================ +// TODO CanIO::isVisible() - Placeholder help routine, remove it when you rewrite the filter functions. +char CanIO::isVisible(const unsigned int id) +{ + // declare variables + short unsigned int i; + char visible = 0; + + // go through the filter rules + for (i = 0; i < m_filter_size; i++) + { + // make things much easier to read, + // gcc -O2 will take hopefully care of it + const unsigned int rule = (m_filter + i)->can_mask & (m_filter + i)->can_id; + const unsigned int input = (m_filter + i)->can_mask & id; + + // inverted filter? + if ((m_filter + i)->can_id & CAN_INV_FILTER) + { + if (rule != input) + return 1; + } + else + { + if (rule == input) + return 1; + } + } + // Everything okay + return visible; +} + + diff --git a/Master/Real-Time Systems/mki/src/libcanio.h b/Master/Real-Time Systems/mki/src/libcanio.h new file mode 100644 index 0000000..8f57b14 --- /dev/null +++ b/Master/Real-Time Systems/mki/src/libcanio.h @@ -0,0 +1,81 @@ +//============================================================================ +// Name: +// libcanio.h +// +// Summary: +// A pretty simple interface to the SocketCan layer, +// which trys to make the communication with the can interfaces easier. +// +// Created on: +// Sep 24, 2010 +// +// Author: +// Christian Steiger +//============================================================================ + +#ifndef LIBCANIO_H_ +#define LIBCANIO_H_ + +#include <cstdio> +#include <cstdlib> +#include <cstring> +#include <cerrno> + +#include <unistd.h> +#include <net/if.h> +#include <sys/time.h> +#include <sys/ioctl.h> +#include <sys/socket.h> +#include <linux/can.h> +#include <linux/can/raw.h> +#include <linux/can/error.h> + +class CanIO +{ + public: + // constructor and destructor + CanIO(); + virtual ~CanIO(); + + // connect and disconnect + int connect(const char* const interface = "can0"); + int disconnect(void); + + // read and write messages + ssize_t readMsg(can_frame* frame, timeval* timestamp = 0); + ssize_t writeMsg(const can_frame* const frame); + + // socketcan options + int showCanErrors(const can_err_mask_t err_mask = 0); + int hideCanErrors(void); + int enableLoopBack(void); + int disableLoopBack(void); + int enableRecvOwnMsgs(void); + int disableRecvOwnMsgs(void); + + // filter functions + int addFilter(const can_filter* const filter, const unsigned int size); + int enableFilter(void); + int disableFilter(void); + int clearFilter(void); + + // debugging help + void hideErrors(void); + void showErrors(void); + + protected: + // class members + int m_socket; + char m_print_errors; + char m_filter_active; + can_filter* m_filter; + unsigned short int m_filter_size; + + private: + // dont use this function, it will be obsolete when + // the filter functions get a better implementation + char isVisible(const unsigned int id); + +}; + +#endif diff --git a/Master/Real-Time Systems/mki/src/mki.cpp b/Master/Real-Time Systems/mki/src/mki.cpp new file mode 100644 index 0000000..1438679 --- /dev/null +++ b/Master/Real-Time Systems/mki/src/mki.cpp @@ -0,0 +1,439 @@ +//============================================================================ +// 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; +} + + diff --git a/Master/Real-Time Systems/mki/src/mki.h b/Master/Real-Time Systems/mki/src/mki.h new file mode 100644 index 0000000..f2ef77b --- /dev/null +++ b/Master/Real-Time Systems/mki/src/mki.h @@ -0,0 +1,86 @@ +//============================================================================ +// Name: +// mki.h +// +// Summary: +// A pretty simple class for controlling the parts +// we can on the mercedes-combi-instrument +// +// Created on: +// Okt 1, 2010 +// +// Author: +// Christian Steiger +//============================================================================ + +// includes +#include "libcanio.h" + +// defines to make things easier, take a look at mkp.cpp +// to see what they are doing exactly. + +// lamps on the display (mki::setLamps()) +#define NONE 0x00 +#define MKI_ABS 0x01 +#define MKI_ESP 0x02 +#define MKI_HANDBRAKE 0x04 +#define MKI_ENGINE 0x08 +#define MKI_WARN 0x10 +#define MKI_WARN_BLINK 0x20 +#define MKI_FUEL_LOW 0x40 + +// lcd display options (mki::setDisplay()) +#define MKI_LIMIT 0x01 +#define MKI_LIMIT_TEXT 0x02 +#define MKI_PERMANENT 0x04 +#define MKI_EXCEED 0x08 +#define MKI_WINTER_TYRE 0x10 +#define MKI_MPH_BLINK 0x10 +#define MKI_NO_MPH 0x20 + +// warnings (mki::setAlert()) +#define MKI_OIL_LOW 0x01 +#define MKI_TIRE_PRESSURE 0x02 +#define MKI_TIRE_DEFECT 0x04 + + +// class definition +class mki +{ + public: + // constructor and destructor + mki(); + ~mki(); + + // various methods, see mki.cpp for descriptions + int connect( const char* const interface ); + void setLamps( const unsigned int lamps); + void setLampsOff(void); + void setRpm( const unsigned short rpm ); + void setMph( const unsigned char mph ); + void setCWTemp( const unsigned char temp ); + void setDisplayMph( const unsigned char mph ); + void setDisplay( const unsigned int flags ); + void setAlert( const unsigned int problem ); + + void sendData(void); + + void setKmh ( const unsigned char kmh ); + void setDisplayKmh ( const unsigned char kmh ); + + // dont rely to heavily on this, it should be removed asap. + CanIO* getInterface(void); + + protected: + // class members + CanIO m_can; + unsigned char m_alert; + + can_frame m_can_id_200; + can_frame m_can_id_208; + can_frame m_can_id_210; + can_frame m_can_id_308; + can_frame m_can_id_312; + can_frame m_can_id_550; + can_frame m_can_id_608; +}; |
