Code:
#include <FlexCAN.h>
#include <kinetis_flexcan.h>
#include <SPI.h>
#include "SdFat.h"
#include <Servo.h>
#include <FreqMeasureMulti.h> // Used to measure input pulses from the ECU for tach signal RPM.
#include <EEPROM.h>
elapsedMillis duration;
Servo ThrottleServo;
IntervalTimer Halfsec;
IntervalTimer Tenthsec;
IntervalTimer Tenhz;
FreqMeasureMulti RPMin;
FreqMeasureMulti CH3in;
///////////////pin assignment////////////////////////////////////////////////
//0- RX1 to RS232 IC
//1- TX1 to RS232 IC
//2- unused
//3- CAN tx
//4- CAN rx
//5- Ch3 input
int EnableIN = 6; // from 14pin input harness
//7- RX3 to uSquirt Mod
//8- TX3 to uSquirt Mod
//9- Servo Out
//10- CS to uSD Card-2
//11- DOUT to uSD Card-3
//12- DIN to uSD Card-7
//13- SCK/LED to uSD Card-5
int EnableOUT = 14;// to HT0440 for 12/5v power enable
int FPsignal = 15; // from uSquirt FP output
int BatVolt = A2; //pin 16
int FPaIN = A3; //pin 17 from JST14-2
int PM5 = 18; // I2C SDA
int PM4 = 19; // I2C SCL
//20- Measure RPM from uSquirt
int IgnPwr = A7; // 21
int Fault = 22; // fault light
int FPOUT = 23; // PWM or digital on for fuelpump relay
//ThrottleA = DAC; // analog TPS signal, representive of PWM input.
float SdValue[32]; // holds data to write to SD card.
uint8_t serbuff[113]; // holds serial data from MS2
uint8_t setbuff[2]; // settings buffer for changing EEPROM settings.
uint16_t value[5]; //place to hold HOBS values, time and file number
uint8_t serialBlast[32]; // place to hold for serial blast to AP.
String hobs = ""; // a way to receive ascii characters from the text doc.
//int baudr = 1000000; //1Mb rate
FlexCAN CANbus(1000000);
static CAN_message_t txmsg,rxmsg;
#define ECUOUT 0x8
#define ECUIN 0x9
#define CANFAST 0x00
#define CANSLOW0 0x01
#define CANSLOW1 0x02
#define CANSLOW2 0x03
#define THROTTLECAL 0x05
#define THROTTLECMD 0x06
#define HARDCONFIG 0x0A
#define TOTALENGINETIME 0x13
#define POWERCYCLES 0x10
#define SWVERSION 0x0B
#define USERSETTING 0x14
#define USERDATA 0x60
uint8_t serial = 0;
uint8_t k = 0;
uint8_t SdGood, seconds, CAN_seconds, i, fault, TPS8, ServoOUT_H, ServoOUT_L, Input_type, IGN8, flow;
uint8_t counter1, counter2, counter3, count, CANinput, CHT8c, BATV8, baroH, baroL, SDfull;
uint32_t Eminutes, engineRev, EngineTime, steps; // engine minutes
int inChar, inchar, number;
int b = 1; // sets fuel pump on during power up.
int location = 0;
uint16_t fuelUsed, RPM, ServoIN, ServoOUT, powercycles, firstFile, PWraw;
uint16_t ECUID, CAN_Throttle, TPSadc;
uint8_t ENABLE, CANBUS, TPSINPUT, FUELPUMP, MAP8;
uint32_t CANinputMessage;
uint8_t Status, ChargTemp, InjDutyH, InjDutyL; // ECU condition enable and serial mode.
int8_t MAT8c;
uint8_t EngineTime0, EngineTime1, EngineTime2, syscmd,g_hrH,g_hrL;
uint16_t FuelUsedDiv,ThrottleClosed, ThrottleOpen;
float slope, yint, g_hr;
uint8_t gramsL, gramsML, gramsMH, gramsH;
uint16_t deadtime, grams;
//File object
//SD chip select pin.
const uint8_t chipSelect = SS;
SdFat sd;
SdFile file; // for test.txt file
SdFile logfile; // for .csv file
//char newfile[13] = "D0000.csv"; // base name for .csv file. updat positions 1,2,3,4 from .txt file
char newfile[13]; // base name for .csv file. updat positions 1,2,3,4 from .txt file
char firstfile[13]; // array for the first file to be deleted.
/////////////////////////////////////////////Set Up///////////////////////////////////////////////////
void setup() {
pinMode(EnableIN, INPUT); // read input state for Enable
pinMode(EnableOUT, OUTPUT); // drive the HT0440 to power Inj and Ign.
pinMode(FPsignal, INPUT); // read state of FP drive pin from uSquirt Module
pinMode(BatVolt, INPUT); // measure battery voltage level
pinMode(FPaIN, INPUT); // measure fuel pressure
pinMode(PM5, INPUT); // read state of ECU pin
pinMode(PM4, INPUT); // read state of ECU pin
pinMode(IgnPwr, INPUT); // measure 5v reg voltage level
pinMode(Fault, OUTPUT); // drive fualt lamp
pinMode(FPOUT, OUTPUT); // drive fuel pump relay
digitalWrite(FPOUT,b); // on power up turn on Fuel Pump relay.
SDfull = EEPROM.read(12); // check for prior SD car volume with less than 750MiB
IntSdCard(); // start SD card.
if(SdGood){ //if sd card good then open some files
OpenHobs(); // open test.txt and get engine run time and current file name for logging
NewFile(); // create new .csv file for logging
writeHeader(); // write header info
}
Read_Eeprom();// Grab setting values from EEPROM.
Do_Math();
Halfsec.begin(HalfSec, 500000);
RPMin.begin(20,FREQMEASUREMULTI_RAISING);// capture RPM input signal
CH3in.begin(5, FREQMEASUREMULTI_MARK_ONLY);// capture incoming throttle command.
Tenthsec.begin(TenthSec, 100000);// Serial3 output to AP.
delay(50);
Tenhz.begin(TwentyHZ, 50000); // 20 hz CAN fast out and ECU data request
Serial1.begin(115200); // to RS232 then to JST14 connector for external tuning
Serial.begin(115200); // for COM cummunication to laptop for setting EEPROM values
Serial3.begin(115200); // UART lines to uSquirt module
CANbus.begin();
}
////////////////////////////////////////Main Loop/////////////////////////////////////////////////////
void loop() {
checkSerial();
readRPM();
Channel3();
GetCAN();
////////////Read FP signal from uSquirtModule/////////
if (!FUELPUMP){
int c = digitalRead(FPsignal);
digitalWrite(FPOUT,c);
}else{
//Insert PWM code or subroutines here//////////
}
uint16_t w = analogRead(BatVolt); // 47k to 6.8k zero to 26.1 volts
float batteryVolt = w * 0.0255; // convert ADC to volts. ie. 512 adc X 0.0255 is 13.05V
SdValue[29] = batteryVolt;
uint16_t z = analogRead(FPaIN); //1k to 1k v-divid 6.6v max.
SdValue[22] = z;
uint16_t d = analogRead(IgnPwr); //1k to 1k v-divid. 6.6V max input.
SdValue[25] = d;
if (d <= 690){
fault = fault | 2; ;
}
}
////////////////////////////////Read EEPROM settings/////////////////////////////////////////////////
void Read_Eeprom(){// read eeprom data for settings options
ECUID = (EEPROM.read(0)<<8) | EEPROM.read(1); // get stored ECU ID/address
ENABLE = EEPROM.read(2); // 0= TPSenable, 1= Digital Enable, 2, TPS_CAN, 3= CAN/Digital Enable
CANBUS = EEPROM.read(3); // 0= off, 1=on(fast,slow0,slow1,slow2)
TPSINPUT = EEPROM.read(4); // 0=PWM(50hz), 1=CAN, 2=CAN/PWM
FUELPUMP = EEPROM.read(5); // 0= on/off, 1= PWM w/CL pressure feedback
FuelUsedDiv = (EEPROM.read(6)<<8) | EEPROM.read(7); // need to sort this out. Call out injector, 50, 150, 250, 450.
ThrottleClosed = (EEPROM.read(8)<<8) | EEPROM.read(9); // Throttle Closed pulse 800 to 1100. (3,132)=900
ThrottleOpen = (EEPROM.read(10)<<8) | EEPROM.read(11); // Throttle Open Pulse 1800 to 2200. (8,52)= 2100
//CANinputMessage = 0x906 << 16 | ECUID; // From AP for throttle command Group 9, FrameID 6, ECUID.
ThrottleServo.attach(9, ThrottleClosed, ThrottleOpen); // set min to 900us and max to 2100us SERVO out
}
///////////////////////////////Do Math for pulsein to analog out./////////////////////////////////////
void Do_Math(){
uint16_t delta = ThrottleOpen - ThrottleClosed;
slope = 1000/(float)delta;
yint = ThrottleClosed * slope;
// y = mx+b
//throttle% = inputpulse(slope) + yint.
//outputpulse = inputpulse.
}
/////////////////////////////////Record input pulse from AP or RX//////////////////////////////////////
void Channel3(){
if (CH3in.available()){
unsigned long a = CH3in.read();
ServoIN = a/24 - 10; // commanded throttle
counter2 = 0;
}
if(!TPSINPUT){ // PWM in only
if (counter2 >= 5){
fault = fault | 16;
ServoIN = 0;
Input_type = 0x00;
}
SdValue[21] = ServoIN;
ServoOUT = ServoIN;
Input_type = 0x20;
}else if(TPSINPUT == 1){// CAN only
SdValue[21] = CAN_Throttle; // zero to 255. 0.39% per step
float candelta = ThrottleOpen-ThrottleClosed;
ServoOUT = ((candelta/256) * CAN_Throttle)+ ThrottleClosed;
Input_type = 0x80;
}else if(TPSINPUT == 2){// CAN with backup PWM
}
if(ServoOUT >= ThrottleOpen){
ServoOUT = ThrottleOpen;
}else if(ServoOUT <= ThrottleClosed){
ServoOUT = ThrottleClosed;
}else {
//SerovOUT = ServoIN;
}
uint16_t throttle = ((float)ServoOUT * slope) - yint; // y=mx-b
TPSadc = throttle * 4; // convert xx.x to 0to4000.
analogWriteResolution(12); // zero to 4095
analogWrite(A14, TPSadc); // send new DAC value
ThrottleServo.writeMicroseconds(ServoOUT); //Update the servo position
ServoOUT_L = ServoOUT & 0xFF;// just grab and keep the low byte
ServoOUT_H = (ServoOUT >> 8 | Input_type); // just keep the high byte and or in "Input_type"
if(!ENABLE){
if(ServoIN >= (ThrottleClosed + 50)){
digitalWrite(EnableOUT, HIGH);
Status = 0x01;
}else{
digitalWrite(EnableOUT, LOW);
Status = 0x00;
}
}else if (ENABLE == 1){// Digital in ENABLE here/////////////
int h = digitalRead(EnableIN);
if(h){
digitalWrite(EnableOUT,HIGH);
Status = 0x01;
}else{
digitalWrite(EnableOUT, LOW);
Status = 0x00;
}
}else if(ENABLE == 2){// Digital and/or CAN input here////////
if(ServoOUT >= (ThrottleClosed + 50)){
digitalWrite(EnableOUT, HIGH);
Status = 0x01;
}else{
digitalWrite(EnableOUT, LOW);
Status = 0x00;
}
}
}
////////////////////Get RPM if present/////////////////////////////////////
void readRPM (){//Set up for 24Mhz
int batcor;
if (RPMin.available()){
unsigned long a = RPMin.read();// have to read the captured measement.
counter1 = 0;
engineRev++;
//Read PW.. find fuel amount for single pulse at that PW.. Maybe assign a value 0 to 1023 for the pulse. 9.77us per step.
//add the value to itself, then divide by a diviser to get true fuel used.
//
if(SdValue[8] >= 8.0){
batcor = (13.2 - SdValue[8]) * 100; // solve deatime of injector.
deadtime = 700 + batcor;
steps += (PWraw - deadtime); // keep adding PWraw minus deatime value to steps
uint16_t math2 = PWraw - deadtime;
}
float flowrate = (PWraw-deadtime) / (float)FuelUsedDiv; // instant flow of fuel in g/min...
g_hr = flowrate * 30; // go from g/min to g/hr
SdValue[28] = g_hr;
g_hrH = (uint16_t)g_hr >> 8; // grab high byte
g_hrL = (uint16_t)g_hr & 0xFF; // grab low byte
if(steps >= (FuelUsedDiv * 6000)){
grams++; // add one more gram used once steps adds up to more than fuelused(us) * 6000. 1 mintes worth of PW.
steps = 0;
SdValue[19] = grams;
}
gramsL = (uint16_t)grams & 0xFF; //grab the low byte
gramsML = (uint16_t)grams>>8 ; // grab the 2nd byte good to 144lbs of fuel
gramsMH = 0;
gramsH = 0;
if (counter1 >= 10){
RPM = 0;
}
if(SdValue[0] == 0){
SdValue[28] = 0;
SdValue[23] = 0;
//SdValue[] = 0;
}
}
}
//////////////////////////get serial data/////////////////////////////////////
void checkSerial(){
if (counter3 >= 100){ // check if JST14 COM port has been inactive for 5 sec
serial = 0; // resume data request from MS2
}
///////////////////USB serial input for changing settings////////////////////////////
if(Serial.available() > 0){ // setting input from teensy COM port.
inChar = Serial.read(); // only used to write new values into eeprom
setbuff[i] = inChar;
i++;
}
if(i >= 2){
if(setbuff[1] == 255){
for (int y=0; y<20; y++){
int val = EEPROM.read(y);
Serial.print(y);
Serial.print("\t");
Serial.println(val);
}
}else{
EEPROM.write(setbuff[0], setbuff[1]); //address then value to write to that address.
}
setbuff[0] = 0;
setbuff[1] = 0;
i = 0;
}
///////////////////End of USB serial checking/////////////////////////////////////////
//////////////////JST14 pin Serial input check///////////////////////////////////////
if(Serial1.available() > 0){ // check for data being used from JST14 COM port
serial = 1; // stops teensy from requesting data from MS2
counter3 = 0; // keep track of when data is nolonger being sent from and to JST14 COM port
}
///////////////////Receive data from MS2//////////////////////////////////////////
if(!serial){ // receive data from MS2
// if (Serial3.available() >0){
// inChar = Serial3.read(); // read data into array serbuff
// serbuff[k] = inChar;
// k++; // keep track of number fo bytes received.
// }
while(Serial3.available() && k <= 112){
inChar = Serial3.read(); // read data into array serbuff
serbuff[k] = inChar;
k++; // keep track of number fo bytes received.
}
}else{ // used for passing data in and out of JST14 COM port.
if (Serial3.available() >0 ){ // read from MS2
inChar = Serial3.read();
Serial1.write(inChar); // to JST14
}
if (Serial1.available() > 0){ // read from JST14
inChar = Serial1.read();
Serial3.write(inChar); // to MS2
}
}
if(!serial){
if (k >= 112){
Serial3.clear(); // serial3 buffer, clear buffer
pickdata();
storeData();
k = 0;
}else{
//Serial.println("K not counting");
}
} else{
//Serial.println("Serial = 1");
}
}
///////////////////////////pick out data from serial buffer/////////////////////////////////////
void pickdata(){
SdValue[0] = (serbuff[6]<<8) | (serbuff[7]); //rpm
serialBlast[0] = serbuff[6]; //rpm high
serialBlast[1] = serbuff[7]; //rpm low
short tps = ((serbuff[24]<<8) | serbuff[25]); //tps
serialBlast[2] = serbuff[24]; //tps high
serialBlast[3] = serbuff[25]; //tps low
TPS8 = tps / 3.921; // converts float to 8bit 0-255 value for CAN bus.
SdValue[1] = (float) tps / 10.0;
SdValue[2] = (((serbuff[18]<<8) | serbuff[19]) / 10.0); //map
serialBlast[8] = serbuff[18]; // map high
serialBlast[9] = serbuff[19]; // map low
MAP8 = SdValue[2]/SdValue[3] * 100; // MAP/BARO x 100. give ratio zer to 100%
SdValue[3] = (((serbuff[16]<<8) | serbuff[17]) / 10.0); // baro
serialBlast[10] = serbuff[16]; //baro high
serialBlast[11] = serbuff[17]; //baro low
uint16_t baro = ((serbuff[16]<<8) | serbuff[17])* 50;
baroH = baro >>8;
baroL = baro & 0xFF;
short cht = ((serbuff[22]<<8) | serbuff[23]); // CHT
//short CHT8 = cht / 10;
CHT8c = (((cht - 320) * 5/90)+10); // converts F to C and in 8-bit scale -10C to 245C.
SdValue[4] = (float) cht / 10.0;
short mat = ((serbuff[20]<<8) | serbuff[21]); // mat
short MAT = mat / 10;
MAT8c = (MAT - 32) *5/9; //int8-t value for -128 to 127C for IAT
ChargTemp = ((MAT8c + 128)*2/3);// weird charge temp math here...
SdValue[5] = (float) mat / 10.0;
SdValue[6] = (((serbuff[2]<<8) | serbuff[3]) / 1000.0); // PW
PWraw = ((serbuff[2]<<8) | serbuff[3]); // PW raw uint16_t value
serialBlast[15] = serbuff[2]; // PW high
serialBlast[16] = serbuff[3]; // PW low
SdValue[7] = (((serbuff[8]<<8) | serbuff[9]) / 10.0); // ign advance
serialBlast[13] = serbuff[8]; // ign advance high
serialBlast[14] = serbuff[9]; // ign advance low
IGN8 = ((serbuff[8]<<8) | serbuff[9])/5;// work this, output on CAN wrong.
SdValue[8] = (((serbuff[26]<<8) | serbuff[27]) / 10.0);//batv
BATV8 = serbuff[27];
serialBlast[17] = serbuff[27]; // bat volt 255 is 25.5 volts
SdValue[9] = (((serbuff[38]<<8) | serbuff[39]) / 10.0); // air correction
SdValue[10] = ((serbuff[40]<<8) | serbuff[41]) ; // warmup correction
SdValue[11] = (((serbuff[46]<<8) | serbuff[47]) / 10.0); // baro correction
short tpsdot = ((serbuff[58]<<8) | serbuff[59]); // TPSdot
SdValue[12] = (float) tpsdot / 10.0;
short mapdot = ((serbuff[60]<<8) | serbuff[61]); //MAPdot
SdValue[13] = (float) mapdot / 10.0;
SdValue[14] = (((serbuff[50]<<8) | serbuff[51]) / 10.0); // VE1
SdValue[15] = (((serbuff[28]<<8) | serbuff[29]) / 10.0); //AFR
serialBlast[12] = serbuff[29]; // AFR in 8 bit form. 10 to 20 AFR 100 to 200..
SdValue[16] = (((serbuff[34]<<8) | serbuff[35]) / 10.0); //EGO correction
SdValue[17] = (((serbuff[74]<<8) | serbuff[75]) / 10.0); // egoV
SdValue[18] = ((serbuff[48]<<8) | serbuff[49]); // gammeEnrich
//SdValue[19] = fuelUsed; // grams total
SdValue[20] = Eminutes; //
serialBlast[25] = Eminutes >> 8; // Engine run time High byte
serialBlast[26] = Eminutes | 0xFF; // Engine run time Low byte
// EngineTime2 = Eminutes >> 16;
// EngineTime1 = (Eminutes >> 8) & 0xFF;
// EngineTime0 = Eminutes & 0xFF;
//SdValue[21] = ServoIN; // uS 900 to 2100
//SdValue[22] = Fuelpressure; // 0 to 100... maybe.. //SdValue[22] = c; // 0 to 100... maybe.. 0 - 1023
//SdValue[23] = Flowrate; //lbs_hr..
// int c = analogRead(FPaIN);
SdValue[24] = engineRev;
//SdValue[25] = ignition voltage;
SdValue[26] = Status;
//long InjDuty = (((serbuff[2]<<8) | serbuff[3]) * SdValue[0]) / 60000; //PW x Rpm / 600.
SdValue[27] = SdValue[6] * SdValue[0] / 600; // solves injector duty cycle.//
uint16_t InjDuty = SdValue[27] * 10;
InjDutyH = InjDuty >> 8;
InjDutyL = InjDuty & 0xFF;
//SdValue[28] = grams/hr;
//SdValue[29] = batteryVolts;
//SdValue[30] = freeSpace;
}
///////////////////////////////////Receive CAN///////////////////////////////////////////////
void GetCAN(){
while ( CANbus.read(rxmsg) ) {
//when message available
if(rxmsg.id == (ECUIN<<24 | THROTTLECMD<<16 | ECUID)){
CAN_Throttle = rxmsg.buf[0]; // need to sort this to servo limits...
CANinput = 1;
}
else if(rxmsg.id == (ECUIN<<24 | HARDCONFIG<<16 | ECUID)) { //Request ECU ID and fuel divisor value
if (rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | HARDCONFIG<<16 | ECUID);
txmsg.buf[0] = EEPROM.read(0); // ECU Id high
txmsg.buf[1] = EEPROM.read(1); // ECU low
txmsg.buf[2] = EEPROM.read(6);
txmsg.buf[3] = EEPROM.read(7); //Fuel used H work on this later. Maybe have the 4 injector flow rates sorted 1-4 in EEPROM
txmsg.buf[4] = 0; //
txmsg.buf[5] = 0; //
txmsg.buf[6] = 0; //
txmsg.buf[7] = 0; //
CANbus.write(txmsg); //SEND IT!
}
}
else if (rxmsg.id == (ECUIN<<24 | THROTTLECAL<<16 | ECUID)){ // throttle calibration stuff.
if (rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | THROTTLECAL<<16 | ECUID);
txmsg.buf[0] = EEPROM.read(8);
txmsg.buf[1] = EEPROM.read(9);
txmsg.buf[2] = EEPROM.read(10);
txmsg.buf[3] = EEPROM.read(11);
txmsg.buf[4] = 0; //
txmsg.buf[5] = 0; //
CANbus.write(txmsg); //SEND IT!
}
else if(rxmsg.len >= 4){
uint8_t closedH = rxmsg.buf[0];
uint8_t closedL = rxmsg.buf[1];
uint8_t openH = rxmsg.buf[2];
uint8_t openL = rxmsg.buf[3];
EEPROM.write(8,closedH);
EEPROM.write(9,closedL);
EEPROM.write(10,openH);
EEPROM.write(11,openL);
Read_Eeprom();
Do_Math();
}
}
else if (rxmsg.id == (ECUIN<<24 | TOTALENGINETIME<<16 | ECUID)){ // totlat engine time in seconds
if(rxmsg.len == 0){
uint32_t engineseconds = Eminutes * 60;
txmsg.len = 3;
txmsg.id = (ECUOUT<<24 | TOTALENGINETIME<<16 | ECUID);// 90
txmsg.buf[0] = engineseconds >> 16; // seconds for the high byte
txmsg.buf[1] = (engineseconds >> 8 ) & 0x00FF; // seconds for mid byte
txmsg.buf[2] = engineseconds & 0x0000FF; // seconds for low byte.
CANbus.write(txmsg); // SEND IT!
}
}else if(rxmsg.id == (ECUIN<<24 | POWERCYCLES<<16 | ECUID)){ // power cycle count, pull from SD file number
if(rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | POWERCYCLES<<16 | ECUID);
txmsg.buf[0] = powercycles >> 8; // grab high byte
txmsg.buf[1] = powercycles & 0xFF; // grab low byte
txmsg.buf[2] = 0;
txmsg.buf[3] = 0;
txmsg.buf[4] = 0;
txmsg.buf[5] = 0;
txmsg.buf[6] = 0;
txmsg.buf[7] = 0;
CANbus.write(txmsg); // SEND IT!
}
}else if(rxmsg.id == (ECUIN<<24 | SWVERSION<<16 | ECUID)){ // Firmware version request and replay
if(rxmsg.len == 0){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | SWVERSION<<16 | ECUID);
txmsg.buf[0] = 1; // major firmware version
txmsg.buf[1] = 12; // minor firmware version
txmsg.buf[2] = 4; // month
txmsg.buf[3] = 19; // day
txmsg.buf[4] = 0x07; // year high byte
txmsg.buf[5] = 0xE2; // year low byte
txmsg.buf[6] = 0xAA; //check sum high
txmsg.buf[7] = 0x55; // check sum low
CANbus.write(txmsg); // SEND IT!
}
}else if(rxmsg.id == (ECUIN<<24 | USERSETTING<<16 | ECUID)){
uint8_t highB;
uint8_t lowB;
syscmd = rxmsg.buf[0];
if(syscmd == 0x11){ // fuel divisor setting
highB = rxmsg.buf[1];
lowB = rxmsg.buf[2];
EEPROM.write(6,highB) ; //Fuel divisor high
EEPROM.write(7,lowB) ; //Fuel divisor low
}else if (syscmd == 0x10){
grams = 0;
}else if(syscmd == 0x50){ // ECU address.
highB = rxmsg.buf[1];
lowB = rxmsg.buf[2];
EEPROM.write(0,highB) ; //ECU ID high
EEPROM.write(1,lowB) ; //ECU ID low
Read_Eeprom();
}else if (syscmd == 0x60){
uint8_t data1 = rxmsg.buf[1]; // address
uint8_t data2 = rxmsg.buf[2]; // data to place into address
EEPROM.write(data1, data2);
}
Read_Eeprom();
}
}
}
///////////////////////////////////////CAN FAST Messages///////////////////////////////////////
void FastCan(){
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANFAST<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Fast CAN
txmsg.buf[0] = TPS8;
txmsg.buf[1] = serbuff[6]; //rpm H
txmsg.buf[2] = serbuff[7]; //rpm L
txmsg.buf[3] = gramsH; //Fuel used H work on this later. Maybe have the 4 injector flow rates sorted 1-4 in EEPROM
txmsg.buf[4] = gramsMH; //Fuel used MH
txmsg.buf[5] = gramsML; // fuel used ML
txmsg.buf[6] = gramsL; // fuel used L
txmsg.buf[7] = Status; // status 0x01 when enabled,
CANbus.write(txmsg); //SEND IT!
}
///////////////////////////////////////CAN SLOW_0 Messages///////////////////////////////////////
void Slow0Can(){
txmsg.ext = 1;
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANSLOW0<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Slow0 CAN
txmsg.buf[0] = 0; //commanded RPM 50 rpm count
txmsg.buf[1] = ServoOUT_H; //8-bit TPS 0-100%
txmsg.buf[2] = ServoOUT_L; // 12-bit count of uS pulse to servo
txmsg.buf[3] = CHT8c; // CHT 8-bit -10 to 245 *C
txmsg.buf[4] = 0; // none
txmsg.buf[5] = baroH; // baro H
txmsg.buf[6] = baroL; // baro L unit of 2 pascals
txmsg.buf[7] = MAP8; // MAP ratio 0 - 100% or MAP kpa
CANbus.write(txmsg); //SEND IT!
}
///////////////////////////////////////CAN SLOW_1 Messages///////////////////////////////////////
void Slow1Can(){
txmsg.ext = 1;
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANSLOW1<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Slow1 CAN
uint16_t pressure = SdValue[22] * 6;
txmsg.buf[0] = MAT8c; // IAT *C -128 to 127
txmsg.buf[1] = pressure >> 8; //Fuel Pressure H
txmsg.buf[2] = pressure & 0xFF; //Fuel Pressure L
txmsg.buf[3] = EngineTime2; //Engine Time_2
txmsg.buf[4] = EngineTime1; //Engine Time_1
txmsg.buf[5] = EngineTime0; //Engine Time_0
txmsg.buf[6] = BATV8; //Batv 8-bit xx.x
txmsg.buf[7] = 0; //Status for RPM control, zero = off.
CANbus.write(txmsg); //SEND IT!
}
///////////////////////////////////////CAN SLOW_2 Messages///////////////////////////////////////
void Slow2Can(){
txmsg.ext = 1;
txmsg.len = 8;
txmsg.id = (ECUOUT<<24 | CANSLOW2<<16 | ECUID);
//txmsg.id = 0x08xxxx; //Slow2 CAN
txmsg.buf[0] = 25; //CPU load
txmsg.buf[1] = ChargTemp; //Charge Temp
txmsg.buf[2] = InjDutyH; //Injector duty H
txmsg.buf[3] = InjDutyL; //Injector duty L
txmsg.buf[4] = IGN8; // Ign Angle1
txmsg.buf[5] = 0; // Ign Angle2
txmsg.buf[6] = g_hrH; //Flow Rate H g/hr>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
txmsg.buf[7] = g_hrL; //Flow Rate L g/hr>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
CANbus.write(txmsg); //SEND IT!
}
/////////////////////////////////////open engine run time//////////////////////////////////
void OpenHobs(){
file.open("test.txt", O_RDWR); // open test.txt for reading and writing. O_READ
while (file.available()){
inchar = file.read();
if (inchar != '\n'){
hobs += (char)inchar;
}else{
value[location] = hobs.toInt(); // convert read values into int.
location++;
hobs = ""; //clear hobs array.
}
}
Eminutes = value[0]; // pull int value from array Engine time
number = value[1]; // pull int value from array new file name
firstFile = value[2];
powercycles = number;
if(SDfull == 1){ // if less than 750MB left on the card start erase the oldest files.
firstfile[0] = 'D'; // place the 'D' to the beginning.
itoa(firstFile, firstfile+1, 10);
if(firstFile / 10000 >= 1){ // test the value of number and load newfile array in the proper spots.
firstfile[6] = '.';
firstfile[7] = 'c';
firstfile[8] = 's';
firstfile[9] = 'v';
}else if(firstFile / 1000 >= 1){ // if greater than 1000 add .csv
firstfile[5] = '.';
firstfile[6] = 'c';
firstfile[7] = 's';
firstfile[8] = 'v';
}else if(firstFile / 100 >=1){
firstfile[4] = '.';
firstfile[5] = 'c';
firstfile[6] = 's';
firstfile[7] = 'v';
}else if(firstFile / 10 >=1){
firstfile[3] = '.';
firstfile[4] = 'c';
firstfile[5] = 's';
firstfile[6] = 'v';
}else {
firstfile[2] = '.';
firstfile[3] = 'c';
firstfile[4] = 's';
firstfile[5] = 'v';
}
firstFile++;
}
////////////convert int back to array ascii values. not working quite right.
//File name will grow over time and has a fluid length.
newfile[0] = 'D'; // place the 'D' to the beginning.
itoa(number, newfile+1, 10); //converts int to array base 10 after the D..
if(number / 10000 >= 1){ // test the value of number and load newfile array in the proper spots.
newfile[6] = '.';
newfile[7] = 'c';
newfile[8] = 's';
newfile[9] = 'v';
}else if(number / 1000 >= 1){ // if greater than 1000 add .csv
newfile[5] = '.';
newfile[6] = 'c';
newfile[7] = 's';
newfile[8] = 'v';
}else if(number / 100 >=1){
newfile[4] = '.';
newfile[5] = 'c';
newfile[6] = 's';
newfile[7] = 'v';
}else if(number / 10 >=1){
newfile[3] = '.';
newfile[4] = 'c';
newfile[5] = 's';
newfile[6] = 'v';
}else {
newfile[2] = '.';
newfile[3] = 'c';
newfile[4] = 's';
newfile[5] = 'v';
}
number++; // add 1 to make new number name for next power cycle.
file.rewind(); // start at begining of file
file.println(Eminutes); // write engine run time
file.println(number); // write new file name for next power cycle.
file.println(firstFile); // write first file number here.
file.close(); // close file
if(SDfull == 1){
sd.remove(firstfile);// remove
}
}
//////////////////////////////////////////SD card Int/////////////////////////////////////////////////////
void IntSdCard(){
if(!sd.begin(chipSelect, SPI_FULL_SPEED)){
sd.initErrorHalt();
SdGood= 0;
}else{
SdGood = 1;
uint32_t volFree = sd.vol()->freeClusterCount();
SdValue[30] = 0.000512*volFree*sd.vol()->blocksPerCluster(); // find the remaining data left in the sd card. x.xx GB.
if((SDfull == 0) && (SdValue[30] < 2850)){ // check if we have set full bit once we are below 750MB remaining
EEPROM.write(12,1); // write to location 12 a 1.
}else if((SDfull == 1) && (SdValue[30] > 2900)){ // check if full bit is still set and there is more than 1GB free space.
EEPROM.write(12,0); // write zer0 to location 12.
}
}
}
/////////////////////////////////////// Write data header///////////////////////////////////////////////
void writeHeader() {
logfile.println("Engine, Log");
logfile.println("TIME,RPM,TPS,MAP,BARO,CHT,IAT,PW,IgnAdv,BATV,AirCorr,WUE,BaroCor,TPSdot,MAPdot,VE1,AFR,EGOCor,egoV,gaErich,FuelUsed,EngineTime,ServoIN,FuelPressure,LbsHr,CrankRev,IgPwr,Status,InjDuty,g_hr,batV,SDvol");
logfile.close();
}
//////////////////////////////////New File/////////////////////////////////////////////////
void NewFile(){
if(!logfile.open(newfile, O_CREAT | O_WRITE | O_EXCL)){
}
}
//////////////////////////////////////Write to SD card///////////////////////////////////////
void storeData(){
float tenthSec = duration / 1000.00;
if(!logfile.open(newfile, O_WRITE | O_AT_END)){
logfile.print(tenthSec,3);
logfile.print(",");
for(int x = 0; x < 31; x++){
logfile.print(SdValue[x]);
logfile.print(",");
}
logfile.println();
count++;
}
if (count >= 250){ // close reopen every 5 sec.
logfile.close();
count = 0;
}
}
///////////////////////////////////////update minutes of run time//////////////////////////
void WriteNewHOBS(){
logfile.close(); //if log file open then close it before opening the HOBS.csv file
file.open("test.txt", O_WRITE);// Open HOBS.csv
file.rewind();// move to beginning of the file to over write the last minute.
file.print(Eminutes);
file.close();
}
/////////////////////////20hz data request/////////////////////////////////////////////////////
void TwentyHZ(){
if(!serial){
Serial3.write(97);// request/pole data from MS2, send a06.
Serial3.write(0);
Serial3.write(6);
i = 0;
}else{
counter3++;
if(counter3 >= 110)
counter3 = 105;
}
if(CANBUS){
FastCan();
}
}
/////////////////////////////////Serial Blast to AP//////////////////////////////
void BlastSerial(){
int z;
for(z = 0; z < 27; z++){ // write 27 bytes to JST serial out.
Serial1.write(serialBlast[z]);
}
}
////////////////////////request next engine data sample//////////////////////////////////////
void TenthSec(){
counter1++;
counter2++;
if(!serial){
BlastSerial();
}
}
////////////////////////place in side 0.5 sec interval timer/////////////////////////////
void HalfSec (){
if(SdValue[0] >= 500){
seconds++;
CAN_seconds++;
}else{
seconds = 0;
CAN_seconds = 0;
}
if(CANBUS){ // if CAN messages are enabled send them
Slow0Can();
Slow1Can();
Slow2Can();
}
if (seconds >= 119){
seconds = 0;
Eminutes++;
WriteNewHOBS();
//SdValue[20] = Eminutes;
}
if(CAN_seconds >= 2){
EngineTime++; //engine time is seconds for CANSlow1
CAN_seconds = 0;
}
EngineTime2 = EngineTime >> 16;
EngineTime1 = (EngineTime >> 8) & 0xFF;
EngineTime0 = EngineTime & 0xFF;
}