Difference between revisions of "Raspberry PI"

From BITPlan can4eve Wiki
Jump to navigation Jump to search
 
(3 intermediate revisions by the same user not shown)
Line 48: Line 48:
 
Exec=/home/wf/source/java/can4eve/run
 
Exec=/home/wf/source/java/can4eve/run
 
</source>
 
</source>
= Bluetooth =
+
 
see https://www.raspberrypi.org/forums/viewtopic.php?t=214373
+
You can make the desktop shortcut available on your desktop by creating a symbolic link from your Desktop
== check connection ==
 
=== Bluetooth services ===
 
<source lang='bash'>
 
service bluetooth status
 
● bluetooth.service - Bluetooth service
 
  Loaded: loaded (/lib/systemd/system/bluetooth.service; enabled; vendor preset
 
  Active: active (running) since Thu 2019-01-24 08:51:05 CET; 3min 2s ago
 
    Docs: man:bluetoothd(8)
 
Main PID: 849 (bluetoothd)
 
  Status: "Running"
 
  CGroup: /system.slice/bluetooth.service
 
          └─849 /usr/lib/bluetooth/bluetoothd
 
</source>
 
=== Pairing ===
 
Pair the device using the Graphical User Interface Bluetooth button in the top right.
 
You will not be able to connect the message is "Connection failed - No usabel services on this device".
 
We'll work around this with some python helper software
 
Check result with commmand line:
 
 
<source lang='bash'>
 
<source lang='bash'>
bluetoothctl
+
cd $HOME/Desktop
[NEW] Controller B8:27:EB:2E:AB:2B pito [default]
+
ln -s /home/wf/.config/autostart/Can4Eve.desktop
[NEW] Device 00:04:3E:9F:A3:C0 OBDLink LX
 
quit
 
 
</source>
 
</source>
=== Python Helper Scripts ===
 
==== obdii_read.py ====
 
<source lang='python'>
 
# WF 2017-02-10
 
# Python access to OBD trial
 
import serial
 
import time
 
import logging
 
import string
 
import io
 
import os
 
import sys
 
  
#
+
= Bluetooth =
#
+
See description of the Bluetooth dongle {{Link|target=OBDLink_LX}}
# Elm327 helper class
 
#
 
class Elm327:
 
  # initialize the serial communication
 
  def __init__(self,port="/dev/rfcomm0",baud=115200,timeout=1):
 
    self.log = logging.getLogger(__name__)
 
    self.port=port
 
    self.baud=baud
 
    self.timeout=timeout
 
    self.ser = serial.Serial(port,baud)
 
    self.ser.timeout=timeout
 
 
 
  # send the given string
 
  def send(self,s):
 
    if (self.ser):
 
      self.ser.flushInput()
 
      self.ser.write(bytes(s + '\r\n', encoding = 'utf-8'))
 
      self.ser.flush()
 
      return self.read()
 
    else:
 
      raise RuntimeError('Serial port not initialized') from error
 
 
 
  # read data from the serial device
 
  # http://stackoverflow.com/a/13018267/1497139
 
  def read(self):
 
    if (not self.ser):
 
      raise RuntimeError('Serial port not initialized') from error
 
    buffer=bytearray()
 
    time.sleep(1)
 
    # get all available data
 
    waiting=self.ser.inWaiting()
 
    if (waiting>0):
 
      readbytes= self.ser.read(self.ser.inWaiting())
 
    else:
 
      readbytes=[]
 
    # check
 
    if not readbytes:
 
      self.log.warning("read from "+self.port+" failed")
 
 
 
    buffer.extend(readbytes)
 
 
 
    return buffer.decode()
 
 
 
  def close(self):
 
    if (not self.ser):
 
      raise RuntimeError('Serial port not initialized') from error
 
    self.ser.close()
 
 
 
  def dcmd(self,cmd):
 
    response=self.send(cmd)
 
    print(response)
 
 
 
#elm=Elm327("/dev/rfcomm0",115200)
 
elm=Elm327()
 
elm.dcmd("ATD")
 
elm.dcmd("ATZ")
 
elm.dcmd("ATE0") # switch off echo
 
elm.dcmd("ATL1") # switch on newlines
 
elm.dcmd("ATI")
 
elm.dcmd("ATSP6")
 
elm.dcmd("ATDP")
 
elm.dcmd("ATH1")
 
elm.dcmd("ATD1")
 
elm.dcmd("ATCAF0")
 
if (len(sys.argv) >1):
 
  pid=sys.argv[1]
 
  elm.dcmd("ATCRA "+pid)
 
  elm.dcmd("AT MA")
 
  while True:
 
    response=elm.read()
 
    print(response)
 
elm.close()
 
 
 
#s = input('Enter AT command --> ')
 
#print ('AT command = ' + s)
 
#ser.timeout = 1
 
#response = ser.read(999).decode('utf-8')
 
#print(response)
 
#ser.close() 
 
</source>
 
 
 
==== tcp_serial_redirect.py ====
 
<source lang='python'>
 
#!/usr/bin/env python
 
#
 
# Redirect data from a TCP/IP connection to a serial port and vice versa.
 
#
 
# (C) 2002-2016 Chris Liechti <cliechti@gmx.net>
 
#
 
# SPDX-License-Identifier:    BSD-3-Clause
 
 
 
import sys
 
import socket
 
import serial
 
import serial.threaded
 
import time
 
import datetime
 
 
 
 
 
class SerialToNet(serial.threaded.Protocol):
 
    """serial->socket"""
 
 
 
    def __init__(self):
 
        self.socket = None
 
 
 
    def __call__(self):
 
        return self
 
 
 
    # callback function
 
    # this is called by the ReaderThread on receiving data from
 
    # the serial device
 
    def data_received(self, data):
 
        if self.socket is not None:
 
            # first send data over network
 
            self.socket.sendall(data)
 
            # optionally show it for debug
 
            if (self.debug):
 
              print("r"+datetime.datetime.now().isoformat()+":"+data)
 
 
 
if __name__ == '__main__':  # noqa
 
    import argparse
 
 
 
    parser = argparse.ArgumentParser(
 
        description='Simple Serial to Network (TCP/IP) redirector.',
 
        epilog="""\
 
NOTE: no security measures are implemented. Anyone can remotely connect
 
to this service over the network.
 
 
 
Only one connection at once is supported. When the connection is terminated
 
it waits for the next connect.
 
""")
 
 
 
    parser.add_argument(
 
        'SERIALPORT',
 
        help="serial port name")
 
 
 
    parser.add_argument(
 
        'BAUDRATE',
 
        type=int,
 
        nargs='?',
 
        help='set baud rate, default: %(default)s',
 
        default=9600)
 
 
 
    parser.add_argument(
 
        '-d', '--debug',
 
        action='store_true',
 
        help='debug',
 
        default=False)
 
 
 
    parser.add_argument(
 
        '-q', '--quiet',
 
        action='store_true',
 
        help='suppress non error messages',
 
        default=False)
 
 
 
    parser.add_argument(
 
        '--develop',
 
        action='store_true',
 
        help='Development mode, prints Python internals on errors',
 
        default=False)
 
 
 
    group = parser.add_argument_group('serial port')
 
 
 
    group.add_argument(
 
        "--parity",
 
        choices=['N', 'E', 'O', 'S', 'M'],
 
        type=lambda c: c.upper(),
 
        help="set parity, one of {N E O S M}, default: N",
 
        default='N')
 
 
 
    group.add_argument(
 
        '--rtscts',
 
        action='store_true',
 
        help='enable RTS/CTS flow control (default off)',
 
        default=False)
 
 
 
    group.add_argument(
 
        '--xonxoff',
 
        action='store_true',
 
        help='enable software flow control (default off)',
 
        default=False)
 
 
 
    group.add_argument(
 
        '--rts',
 
        type=int,
 
        help='set initial RTS line state (possible values: 0, 1)',
 
        default=None)
 
 
 
    group.add_argument(
 
        '--dtr',
 
        type=int,
 
        help='set initial DTR line state (possible values: 0, 1)',
 
        default=None)
 
 
 
    group = parser.add_argument_group('network settings')
 
 
 
    exclusive_group = group.add_mutually_exclusive_group()
 
 
 
    exclusive_group.add_argument(
 
        '-P', '--localport',
 
        type=int,
 
        help='local TCP port',
 
        default=7777)
 
 
 
    exclusive_group.add_argument(
 
        '-c', '--client',
 
        metavar='HOST:PORT',
 
        help='make the connection as a client, instead of running a server',
 
        default=False)
 
 
 
    args = parser.parse_args()
 
 
 
    # connect to serial port
 
    ser = serial.serial_for_url(args.SERIALPORT, do_not_open=True)
 
    ser.baudrate = args.BAUDRATE
 
    ser.parity = args.parity
 
    ser.rtscts = args.rtscts
 
    ser.xonxoff = args.xonxoff
 
 
 
    if args.rts is not None:
 
        ser.rts = args.rts
 
 
 
    if args.dtr is not None:
 
        ser.dtr = args.dtr
 
 
 
    if not args.quiet:
 
        sys.stderr.write(
 
            '--- TCP/IP to Serial redirect on {p.name}  {p.baudrate},{p.bytesize},{p.parity},{p.stopbits} ---\n'
 
            '--- type Ctrl-C / BREAK to quit\n'.format(p=ser))
 
 
 
    try:
 
        ser.open()
 
    except serial.SerialException as e:
 
        sys.stderr.write('Could not open serial port {}: {}\n'.format(ser.name, e))
 
        sys.exit(1)
 
 
 
    ser_to_net = SerialToNet()
 
    ser_to_net.debug=args.debug
 
    serial_worker = serial.threaded.ReaderThread(ser, ser_to_net)
 
    serial_worker.start()
 
 
 
    if not args.client:
 
        # open the socket as a streaming socket
 
        srv = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
 
        srv.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
 
        srv.bind(('', args.localport))
 
        srv.listen(1)
 
    try:
 
        intentional_exit = False
 
        while True:
 
            if args.client:
 
                host, port = args.client.split(':')
 
                sys.stderr.write("Opening connection to {}:{}...\n".format(host, port))
 
                client_socket = socket.socket()
 
                try:
 
                    client_socket.connect((host, int(port)))
 
                except socket.error as msg:
 
                    sys.stderr.write('WARNING: {}\n'.format(msg))
 
                    time.sleep(5)  # intentional delay on reconnection as client
 
                    continue
 
                sys.stderr.write('Connected\n')
 
                client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
 
                #~ client_socket.settimeout(5)
 
            else:
 
                sys.stderr.write('Waiting for connection on {}...\n'.format(args.localport))
 
                client_socket, addr = srv.accept()
 
                sys.stderr.write('Connected by {}\n'.format(addr))
 
                # More quickly detect bad clients who quit without closing the
 
                # connection: After 1 second of idle, start sending TCP keep-alive
 
                # packets every 1 second. If 3 consecutive keep-alive packets
 
                # fail, assume the client is gone and close the connection.
 
                try:
 
                    client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPIDLE, 1)
 
                    client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPINTVL, 1)
 
                    client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_KEEPCNT, 3)
 
                    client_socket.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
 
                except AttributeError:
 
                    pass # XXX not available on windows
 
                client_socket.setsockopt(socket.IPPROTO_TCP, socket.TCP_NODELAY, 1)
 
            try:
 
                ser_to_net.socket = client_socket
 
                # enter network <-> serial loop
 
                while True:
 
                    try:
 
                        # read data from serial                   
 
                        data = client_socket.recv(2048)
 
                        if not data:
 
                            break
 
                        ser.write(data)                # get a bunch of bytes and send them
 
                        if (args.debug):
 
                          print("s"+datetime.datetime.now().isoformat()+":"+data)
 
                    except socket.error as msg:
 
                        if args.develop:
 
                            raise
 
                        sys.stderr.write('ERROR: {}\n'.format(msg))
 
                        # probably got disconnected
 
                        break
 
            except KeyboardInterrupt:
 
                intentional_exit = True
 
                raise
 
            except socket.error as msg:
 
                if args.develop:
 
                    raise
 
                sys.stderr.write('ERROR: {}\n'.format(msg))
 
            finally:
 
                ser_to_net.socket = None
 
                sys.stderr.write('Disconnected\n')
 
                client_socket.close()
 
                if args.client and not intentional_exit:
 
                    time.sleep(5)  # intentional delay on reconnection as client
 
    except KeyboardInterrupt:
 
        pass
 
 
 
    sys.stderr.write('\n--- exit ---\n')
 
    serial_worker.stop()
 
</source>
 

Latest revision as of 10:27, 24 January 2019

To run on a Raspberry PI you need a properly configured device. See e.g. http://ion.bitplan.com/index.php/Ion2017-07-18#Raspberry_PI

Hardware

See e.g. 31jEGhZmPdL.jpg

91zSu44%2B34L._SL1500_.jpg

Raspberry Setup

You'll find setup guides all over the internet here are just two links:

Software configuration

cat /etc/os-release
PRETTY_NAME="Raspbian GNU/Linux 9 (stretch)"
NAME="Raspbian GNU/Linux"
VERSION_ID="9"
VERSION="9 (stretch)"
ID=raspbian
ID_LIKE=debian
HOME_URL="http://www.raspbian.org/"
SUPPORT_URL="http://www.raspbian.org/RaspbianForums"
BUG_REPORT_URL="http://www.raspbian.org/RaspbianBugs"

Java 8 installation

apt-get install oracle-java8-jdk

Run script

If you have an official touchscreen you can control the brightness of the screen with the darkmode button of can4eve.

You might want to make sure that you use the run script to start the app. The important lines are:

sudo chmod 0664 /sys/class/backlight/rpi_backlight/brightness
sudo chown root.pi /sys/class/backlight/rpi_backlight/brightness

Autostart

Example Can4Eve.desktop file to be placed in .config/autostart of your user. Please adapt the exec line to where you installed can4eve

[Desktop Entry]
Type=Application
Name=Can4Eve
Comment=Onboard Diagnostic software for Electric Vehicles
NoDisplay=false
Exec=/home/wf/source/java/can4eve/run

You can make the desktop shortcut available on your desktop by creating a symbolic link from your Desktop

cd $HOME/Desktop
ln -s /home/wf/.config/autostart/Can4Eve.desktop

Bluetooth

See description of the Bluetooth dongle OBDLink_LX