# THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
# APPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
# HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
# OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
# THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
# PURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
# IS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
# ALL NECESSARY SERVICING, REPAIR OR CORRECTION.

# IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
# WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
# THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
# GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
# USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
# DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
# PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
# EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
# SUCH DAMAGES.

# Copyright (c) 2018 Dr. Oliver Barth <info@drb-electronic.de>
# spi driver for MCP2515

import time
from threading import Lock
import Queue

MCP2515_RESET = 0xC0
MCP2515_READ = 0x03
MCP2515_WRITE = 0x02
MCP2515_BIT_MODIFY = 0x05
MCP2515_LOAD_TXB0 = 0x40
MCP2515_LOAD_TXB1 = 0x42
MCP2515_LOAD_TXB2 = 0x44
MCP2515_READ_RXB0 = 0x90
MCP2515_READ_RXB1 = 0x94
MCP2515_REQUEST_TO_SEND_TXB0 = 0x81
MCP2515_REQUEST_TO_SEND_TXB1 = 0x82
MCP2515_REQUEST_TO_SEND_TXB2 = 0x84
MCP2515_READ_STATUS = 0xA0
MCP2515_RX_STATUS = 0xB0

MCP2515_OPMODE_NORM = 0x00
MCP2515_OPMODE_SLEEP = 0x01
MCP2515_OPMODE_LPBCK = 0x02
MCP2515_OPMODE_LSTONLY = 0x03
MCP2515_OPMODE_CONFIG = 0x04

MCP2515_SJW = 2 #synchronization jump width

# all calculated values -1 because MCP2515 registers use value + 1
MCP2515_BRP_1MBAUD = 0
MCP2515_BRP_500KBAUD = 0
MCP2515_BRP_250KBAUD = 1
MCP2515_BRP_125KBAUD = 3
MCP2515_PROPSEG_8TQ = 0
MCP2515_PS1_8TQ = 2
MCP2515_PS2_8TQ = 2
MCP2515_PROPSEG_16TQ = 1
MCP2515_PS1_16TQ = 6
MCP2515_PS2_16TQ = 5

MCP2515_regs = {
	'RXF0SIDH':0x00,
	 'RXF0SIDL':0x01,
	'BFPCTRL':0x0C,
	'TXRTSCTRL':0x0D,
	'CANSTAT':0x0E,
	'CANCTRL':0x0F,
	'TEC':0x1C,
	'REC':0x1D,
	'RXM0SIDH':0x20,
	'RXM0SIDL':0x21,
	'CNF3':0x28,
	'CNF2':0x29,
	'CNF1':0x2A,
	'CANINTE':0x2B,
	'CANINTF':0x2C,
	'EFLG':0x2D,
	'TXB0CTRL':0x30,
	'TXB0SIDH':0x31,
	'TXB0SIDL':0x32,
	'TXB0EID8':0x33,
	'TXB0EID0':0x34,
	'TXB0DLC':0x35,
	'TXB0D0':0x36,
	'TXB1CTRL':0x40,
	'TXB1SIDH':0x41,
	'TXB1SIDL':0x42,
	'TXB1EID8':0x43,
	'TXB1EID0':0x44,
	'TXB1DLC':0x45,
	'TXB2CTRL':0x50,
	'TXB2SIDH':0x51,
	'TXB2SIDL':0x52,
	'TXB2EID8':0x53,
	'TXB2EID0':0x54,
	'TXB2DLC':0x55,
	'RXB0CTRL':0x60,
	'RXB0SIDH':0x61,
	'RXB0SIDL':0x62,
	'RXB0EID8':0x63,
	'RXB0EID0':0x64,
	'RXB0DLC':0x65,
	'RXB0D0':0x66,
	'RXB1CTRL':0x70,
	'RXB1SIDH':0x71,
	'RXB1SIDL':0x72,
	'RXB1EID8':0x73,
	'RXB1EID0':0x74,
	'RXB1DLC':0x75,
	'RXB1D0':0x76 }
	
MCP2515_opmodes = [ "config", "normal", "sleep", "listen", "loopback" ]

MCP2515_canID = 0
MCP2515_baudrate = 500000

CAN_MCP2515_keywords = ['self.can.setBaudrate(baud)', 'self.can.transmitMsg(canid,dlc,msg)', 'self.can.readRXBuffer()']

#
class CAN_MCP2515():
	def __init__(self, active):
		self.active = active
	#
	def init(self, spi, baud, loopback):
		if (self.active == 1):
			self.spi = spi
			self.spi.xfer2([MCP2515_RESET])
			time.sleep(0.01)
			self.setBaudrate(baud)
			# receive buffer full interrupt enable
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CANINTE'], 0x03])
			# receive any message, rollover enabled 
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['RXB0CTRL'], 0x64])
			#receive any message
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['RXB1CTRL'], 0x60])
			# filter 0 standard identifier high
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['RXF0SIDH'], 0x00])
			# filter 0 standard identifier low
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['RXF0SIDL'], 0x00])
			# mask 0 standard identifer high
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['RXM0SIDH'], 0x00])
			# mask 0 standard identifer low
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['RXM0SIDL'], 0x00])
			
			if (loopback == 1):
				print "CAN MCP2515 in loopback mode"
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CANCTRL'], (MCP2515_OPMODE_LPBCK << 5) | 0x04])
			else:
				print "CAN MCP2515 in loopback mode"
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CANCTRL'], (MCP2515_OPMODE_NORM << 5) | 0x04])

			self.listeners = []
			self.actRxState = 0
			self.prevRxState = 0
			self.txQueue = Queue.Queue()
			self.mutex = Lock()

	#
	def setOpmode(self, opmode):
		if (self.active == 1):
			self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CANCTRL'], (opmode << 5) | 0x04])

	#
	def setReg(self, reg, val):
		if (self.active == 1):
			self.spi.xfer2([MCP2515_WRITE, reg, val])

	#
	def getReg(self, reg):
		if (self.active == 1):
			b = self.spi.xfer2([MCP2515_READ, reg, 0x00])
		return b[2]

	#
	def setBaudrate(self, canbaud):
		if (self.active == 1):
			MCP2515_baudrate = canbaud
			
			if(canbaud == 1000000):
				# SJW1 | SJW0 | BRP5 | BRP4 | BRP3 | BRP2 | BRP1 | BRP0
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF1'], (MCP2515_SJW  << 6) | MCP2515_BRP_1MBAUD])
				# BTLMODE length of PS2 determined by CNF3 | SAM | PHSEG12 | PHSEG11 | PHSEG10 | PRSEG2 | PRSEG1 | PRSEG0
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF2'], 0x80 | (MCP2515_PS1_8TQ << 3) | MCP2515_PROPSEG_8TQ])
				# PHSEG22 | PHSEG21 | PHSEG20
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF3'], MCP2515_PS2_8TQ])
			elif(canbaud == 500000):
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF1'], (MCP2515_SJW  << 6) | MCP2515_BRP_500KBAUD])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF2'], 0x80 | (MCP2515_PS1_16TQ << 3) | MCP2515_PROPSEG_16TQ])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF3'], MCP2515_PS2_16TQ])
			elif(canbaud == 250000):
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF1'], (MCP2515_SJW  << 6) | MCP2515_BRP_250KBAUD])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF2'], 0x80 | (MCP2515_PS1_16TQ << 3) | MCP2515_PROPSEG_16TQ])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF3'], MCP2515_PS2_16TQ])
			elif(canbaud == 125000):
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF1'], (MCP2515_SJW  << 6) | MCP2515_BRP_125KBAUD])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF2'], 0x80 | (MCP2515_PS1_16TQ << 3) | MCP2515_PROPSEG_16TQ])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['CNF3'], MCP2515_PS2_16TQ])

	# load MCP2515 tx buffer with id, dlc and data bytes
	def addToTransmitQueue(self, canid, dlc, msg):
		if (self.active == 1):
			#self.mutex.acquire()
			self.txQueue.put([canid, dlc, msg])
			#self.mutex.release()

	#
	def bitModify(self, reg, mask, data):
		if (self.active == 1):
			self.spi.xfer2([MCP2515_BIT_MODIFY, reg, mask, data])

	#
	def rxStatus(self):
		if (self.active == 1):
			stat = self.spi.xfer2([MCP2515_RX_STATUS, 0x00, 0x00])
		return stat[1]

	#
	def readRXBuffer(self):
		if (self.active == 1):
			rxmsg = self.spi.xfer2([MCP2515_READ_RXB0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00])
		return rxmsg

	#
	def addListener(self, l):
		if (self.active == 1):
			self.listeners.append(l)

	#
	def update(self):
		if (self.active == 1):
			#self.mutex.acquire()

			# transmit
			if not self.txQueue.empty():
				txmsg = self.txQueue.get()
				canid = txmsg[0]
				dlc = txmsg[1]
				msg = txmsg[2]
				if(dlc == 0):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc])
				elif (dlc == 1):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0]])
				elif (dlc == 2):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1]])
				elif (dlc == 3):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1], msg[2]])
				elif (dlc == 4):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1], msg[2], msg[3]])
				elif (dlc == 5):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1], msg[2], msg[3], msg[4]])
				elif (dlc == 6):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1], msg[2], msg[3], msg[4], msg[5]])
				elif (dlc == 7):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6]])
				elif (dlc == 8):
					self.spi.xfer2([MCP2515_LOAD_TXB0, canid >> 3, canid << 5, 0x00, 0x00, dlc, msg[0], msg[1], msg[2], msg[3], msg[4], msg[5], msg[6], msg[7]])
				self.spi.xfer2([MCP2515_WRITE, MCP2515_regs['TXB0CTRL'], 0x08])

			# receive
			self.actRxState = self.rxStatus()
			if(self.actRxState != self.prevRxState):
				self.prevRxState = self.actRxState
				if(self.actRxState != 0):
					rxmsg = self.readRXBuffer()
					rxcanid = (rxmsg[1] << 3) + (rxmsg[2] >> 5)
					rxdlc = rxmsg[5]
					for l in self.listeners:
						l.canMsgReceived([rxcanid, rxdlc, rxmsg[6], rxmsg[7], rxmsg[8], rxmsg[9], rxmsg[10], rxmsg[11], rxmsg[12], rxmsg[13]])

			#self.mutex.release()

