Отчитываюсь, допилил! Надеюсь кому-то , кроме меня, это будет полезно. Скетч:
#include <EEPROM.h>
#define RX 3 // пин ардуино, к которому подключать линию RX GSM (не менять!)
#define TX 2 // пин ардуино, к которому подключать линию TX GSM
#define DEBUG // раскомментировать, если нужна отладка в терминал. Закомментировать эту строку, когда вставляете эту городьбу в свой проект)
volatile byte dataRX[10] = {0}; // буфер приема данных от сигналки
enum statesRX {WAIT_FALL, WAITSTROB, CLOCKING_DETECTED}; // возможные состояния приемника
volatile byte stateRX = WAIT_FALL ; // переменная состояния приемника
volatile byte bitNumberRX = 0 ;
volatile byte byteNumberRX = 0 ;
volatile bool SLmessage_received = 0; // флаг что принято новое сообщение от сигналки
volatile byte dataTX[10]= {0}; // буфер передачи данных на сигналку (пакет байт команды)
enum statesTX {WAIT_CLOCKING, PROPUSK, TXbyCLOCK, TXtoIDLE}; //возможные состояния передатчика
volatile byte stateTX = WAIT_CLOCKING ; // переменная состояния передатчика
volatile byte bitNumberTX = 0 ;
volatile byte byteNumberTX = 0 ;
byte SL_key[2]={0}; // байты ключа сигнализации
// таймеры возврата в bus-Idle в случае неответов от сигналки
bool Timer_waitCLOCKING_from_Starline = 0;
uint32_t prev_waitCLOCKING_from_Starline = 0;
enum protectTimer_states {TIMER_OFF, TIMER_WAIT_RESPONSE, TIMER_PROTECT, TIMER_LASTSTATE};
byte Timer_waitRESPONSE_from_Starline = 0;
uint32_t prev_waitRESPONSE_from_Starline = 0;
byte Timer_needRepeat = 0;
uint32_t prev_timer_needRepeat = 0;
bool needPropusk = 0 ;
byte RepeatCommand = 0 ;
byte CountRepeat = 0 ;
#define CLOCK_ON TCCR2B=2
#define CLOCK_OFF TCCR2B=0
#define SEND_CLOCKING_AND_READ_BITS ISR(TIMER2_COMPA_vect)
const uint8_t ZAPROS = 0x42;
const uint8_t START_ENG = 0x21;
const uint8_t STOP_ENG = 0x20;
const uint8_t OHRANA_ON = 0x11;
const uint8_t OHRANA_OFF = 0x10;
bool Doors = 0 ;
bool Locks = 0 ;
bool Ohrana = 0 ;
bool Trunk = 0 ;
bool Hood = 0 ;
bool Ignition = 0 ;
bool Brake = 0 ;
bool Engine = 0 ;
bool Trevoga = 0 ;
bool Tiltsensor = 0 ;
bool Shocksensor = 0 ;
void setup() {
pinMode (TX, OUTPUT); // линию TX на выход
digitalWrite (TX, 1); // и ставим в busIdle
pinMode (RX, INPUT_PULLUP); // линию RX на вход с подтяжкой
#ifdef DEBUG
Serial.begin(115200); Serial.println(); Serial.println(F("Arduino Restart"));
Serial.print(F("Starline Key: "));
#endif
for (byte i=0; i<2; i++)
{
SL_key[i] = EEPROM.read(i+200);
#ifdef DEBUG
if (SL_key[i]<0xF){Serial.print("0");} Serial.print(SL_key[i], HEX); Serial.print(F(" "));
#endif
}
#ifdef DEBUG
Serial.println();
#endif
//---------настройка таймера2 для выполнения нами тактирования передачи от сигналки (обработчик выскочит раз в 100мкс).
TCCR2A = 2 ;
TCCR2B = 0;
OCR2A = 198; // установка регистра совпадения (100 мкс для прескалера 8)
TIMSK2 = 2; // разрешить прерывание по таймеру2 по сравнению A
//TCCR2B = 2; // включ таймер раз в 100мкс
}
void loop()
{
SL_Data(); // работа протокола SL_DATA
}
void SL_Data()
{
//таймеры сброса тактирования или сброса линии TX при передаче в случае неответов от оппонента
timers_to_protect_against_failures();
#ifdef DEBUG
//иницирование отправки команд на сигналку через терминал
Command_to_Starline_from_Terminal();
#endif
//обработка принятых сообщений от сигналки
processing_of_received_SLmessages();
//отправка сигнала тактирования на сигналку
send_CLOCKING_to_Starline();
}
void send_CLOCKING_to_Starline(){
if (Timer_waitRESPONSE_from_Starline!=TIMER_PROTECT){ // тактируем, если не включена защитная задержка глюков связи
bool curRX = digitalRead(RX);
static bool lastRX = curRX;
if (lastRX != curRX){ // если состояние линии RX изменилось
if (stateTX==WAIT_CLOCKING && stateRX == WAIT_FALL) // если статус приемника и передатчика "ждем спад"
{
if (lastRX && !curRX){ // если увидели спад на RX, значит сигналка хочет передавать, ниже отправляем ей тактирвание
stateRX = WAITSTROB;
delayMicroseconds (100);
if (bool((1 << 3) & PIND)) {stateRX = WAIT_FALL; return;} // если было ложное срабатывание RX пина, выходим.
//ниже включение таймера защиты от возможных глюков при неответах
if (Timer_waitRESPONSE_from_Starline==TIMER_OFF) {Timer_waitRESPONSE_from_Starline = TIMER_WAIT_RESPONSE; prev_waitRESPONSE_from_Starline = millis();}
digitalWrite (TX,0); // короткий строб в ноль, делаем всё по снифферской осциллограмме с ори обмена данными
delayMicroseconds (40); // длина строба
CLOCK_ON; // включаем тактирование для оппонента.
}
}
lastRX = curRX;
}
}
}
SEND_CLOCKING_AND_READ_BITS // обработчик вылазит раз в 100мкс, тактируем для сигналки и читаем очередной бит от неё
{
if (stateRX == WAITSTROB) {stateRX = CLOCKING_DETECTED; PORTD ^= (1 << 2);}
else if (stateRX == CLOCKING_DETECTED)
{
if (bool((1 << 3) & PIND)){dataRX[byteNumberRX]|= (1<<(bitNumberRX));}// читаем
else {dataRX[byteNumberRX]&=~(1<<(bitNumberRX));} // очередной бит
PORTD ^= (1 << 2); // тактируем, изменив состояние пина TX на противоположное
if (bitNumberRX==7 && byteNumberRX == 9) {endRX(); SLmessage_received = 1; return;} // сообщение полностью принято
bitNumberRX++; if (bitNumberRX==8){bitNumberRX=0; byteNumberRX++;} // рост счётчиков бит и байт
}
}
void endRX(){CLOCK_OFF; bitNumberRX=0; byteNumberRX=0; stateRX = WAIT_FALL;}
void processing_of_received_SLmessages()
{if (SLmessage_received){
#ifdef DEBUG
Serial.print ("Starline Response: ");
#endif
byte CS = 0 ;
for (int i=0; i<10; i++)
{
if (i<9)CS+=dataRX[i]; // подсчёт CS
#ifdef DEBUG
if (dataRX[i]<=0xF)Serial.print("0"); Serial.print(dataRX[i], HEX); Serial.print(" ");
#endif
if (i==9)
{
#ifdef DEBUG
Serial.print(" CS is ");
#endif
if (CS==dataRX[i]) // если получен валидный ответ от сигналки
{
Timer_waitCLOCKING_from_Starline = 0; // сбрасываем таймер ожидания тактирования от сигналки
Timer_waitRESPONSE_from_Starline = TIMER_OFF; // сбрасываем таймер ожидания ответа от сигналки
Timer_needRepeat = 0 ; CountRepeat = 0 ;
#ifdef DEBUG
Serial.println("OK! ");
#endif
if (dataRX[0]==0x0B && dataRX[4]==0x00) // принята процедура привязки GSM, запоминаем ключ Starline
{
Registration_SL_GSM();
#ifdef DEBUG
Serial.println(F("Registration GSM successfully completed!"));
#endif
}
else {
Doors = (bool((1 << 0) & dataRX[1]));
Trunk = (bool((1 << 2) & dataRX[1]));
Hood = (bool((1 << 3) & dataRX[1]));
Ignition = (bool((1 << 3) & dataRX[3]));
Brake = (bool((1 << 4) & dataRX[1]));
Locks = (bool((1 << 5) & dataRX[1]));
Ohrana = (bool((1 << 6) & dataRX[1]));
Trevoga = (bool((1 << 4) & dataRX[2]));
Shocksensor = (bool((1 << 1) & dataRX[5]));
Tiltsensor = (bool((1 << 0) & dataRX[6]));
#ifdef DEBUG
Serial.print (" Door: "); Serial.print (Doors); Serial.print (" Ign: "); Serial.print (Ignition);
Serial.print (" Brake: "); Serial.print (Brake); Serial.print (" Trunk: "); Serial.print (Trunk);
Serial.print (" Hood: "); Serial.print (Hood); Serial.print (" Locks: "); Serial.print (Locks);
Serial.print (" Ohrana: "); Serial.print (Ohrana); Serial.print (" Trevoga: "); Serial.print (Trevoga);
Serial.print (" Shock: "); Serial.print (Shocksensor); Serial.print (" Tilt: "); Serial.println (Tiltsensor);
#endif
}
}
else // Если CS неправильная
{
#ifdef DEBUG
Serial.println("Error!!!");
#endif
}
}
}
SLmessage_received = 0 ;
#ifdef DEBUG
Serial.println();
#endif
}
}
#ifdef DEBUG
void Command_to_Starline_from_Terminal() // инициирование отправки команд на сигналку с терминала
{
if (Serial.available())
{
Serial.println();
byte inbyte = Serial.read();
if (inbyte == 'z') {Serial.println (F(" Send SMS Zapros Sostoyanya: ")); Send_To_Starline (ZAPROS);}
else if (inbyte == '1') {Serial.println (F(" Send SMS Ohrana ON: ")); Send_To_Starline (OHRANA_ON);}
else if (inbyte == '0') {Serial.println (F(" Send SMS Ohrana OFF: ")); Send_To_Starline (OHRANA_OFF);}
else if (inbyte == 'r') {Serial.println (F(" GSM is reset! ")); Reset_SL_GSM(); }
else if (inbyte == 'p') {needPropusk=!needPropusk; Serial.print (F("Propusk ")); Serial.println (needPropusk);}
}
}
#endif
void Send_To_Starline(const byte &SLcommand) // процедура отправки команды на сигналку
{
if (stateRX > WAIT_FALL) {delay (200);}
RepeatCommand = SLcommand;
dataTX[0]=0x0A;
dataTX[1]=millis();
dataTX[2]=(dataTX[1]^SLcommand)^SL_key[0];
dataTX[3]=(dataTX[1]^SLcommand)^SL_key[1];
dataTX[4]=0xFF;
byte CS = 0 ;
for (byte i=0; i<5;i++) {CS+=dataTX[i];}
dataTX[9]=CS;
#ifdef DEBUG
Serial.print (" Send to Starline: ");
for (byte i=0; i<10;i++) {if (dataTX[i]<=0xF)Serial.print("0"); Serial.print(dataTX[i], HEX); Serial.print(" ");}
Serial.println();
#endif
PORTD &=~(1 << 2); // садим в 0 линию передачи , инициируя желание передавать данные
Timer_waitCLOCKING_from_Starline = 1; prev_waitCLOCKING_from_Starline = millis(); // включаем таймер защиты
Timer_needRepeat = 1; prev_timer_needRepeat = millis();
attachInterrupt(1, Accept_clocking_and_transmit_bits, FALLING); // и ждем тактирования от сигналки (принимать тактирование будет внеш прерывание)
}
void Accept_clocking_and_transmit_bits () //обработчик внешнего прерывания, выступает как приёмник тактирования от сигналки для выполнения нашей ей передачки.
{
if (stateTX==WAIT_CLOCKING){if (needPropusk) stateTX=PROPUSK; else stateTX=TXbyCLOCK; attachInterrupt(1, Accept_clocking_and_transmit_bits, CHANGE);return;}
//--------------ниже передача команды на шину по тактированию от сигналки-----------
else if (needPropusk && stateTX==PROPUSK){stateTX=TXbyCLOCK;}
else if (stateTX==TXbyCLOCK) // принимаем тактирование от сигналки и по нему отправляем побитно команду
{
if (bool((1 << (bitNumberTX)) & dataTX[byteNumberTX])) { PORTD |=(1 << 2); } // читаем очередной бит из команды
else {PORTD &=~(1 << 2); } // и выставляем его на пине TX
//----------------------------------------------------------------------------------
if (byteNumberTX==9 && bitNumberTX == 7) { endTX(); return;}// если все 80 бит переданы, выходим , сбросив переменные и откл внеш прерывание
bitNumberTX++; if (bitNumberTX == 8) {bitNumberTX = 0 ;byteNumberTX++;}
}
}
void endTX() {detachInterrupt(1); stateTX=TXtoIDLE; bitNumberTX=0; byteNumberTX=0;}
void timers_to_protect_against_failures()
{
if (stateTX==TXtoIDLE){delayMicroseconds(100); digitalWrite(TX,1);stateTX=WAIT_CLOCKING;}
if (Timer_waitCLOCKING_from_Starline && millis()- prev_waitCLOCKING_from_Starline>=200)
{
Timer_waitCLOCKING_from_Starline=0;
endTX();
}
if (Timer_needRepeat && millis() - prev_timer_needRepeat>=3500)
{
CountRepeat++; if (CountRepeat>=3) CountRepeat = 3 ;
Timer_needRepeat = 0 ;
needPropusk=!needPropusk;
if (CountRepeat<3){Send_To_Starline (RepeatCommand);}
}
if (Timer_waitRESPONSE_from_Starline>0 && millis() - prev_waitRESPONSE_from_Starline>=4000)
{
Timer_waitRESPONSE_from_Starline++;
if (Timer_waitRESPONSE_from_Starline==TIMER_PROTECT) {endRX(); digitalWrite(TX,1);}
else if (Timer_waitRESPONSE_from_Starline>=TIMER_LASTSTATE){Timer_waitRESPONSE_from_Starline = TIMER_OFF;}
prev_waitRESPONSE_from_Starline = millis();
}
}
void Reset_SL_GSM () {SL_key[0]=0xFF; SL_key[1]=0xFF; EEPROM.write(200,0xFF);EEPROM.write(201,0xFF);}
void Registration_SL_GSM () {SL_key[0]=dataRX[1]; SL_key[1]=dataRX[2]; EEPROM.write(200,dataRX[1]);EEPROM.write(201,dataRX[2]);}
ну и пример лога:
Arduino Restart
Starline Key: FF FF
отправляю запрос состояния с терминала
Send SMS Zapros Sostoyanya:
Send to Starline: 0A 91 2C 2C FF 00 00 00 00 F2
Send to Starline: 0A 3F 82 82 FF 00 00 00 00 4C
Send to Starline: 0A EC 51 51 FF 00 00 00 00 97
выше нет ответов от сигналки, т.к. GSM ещё не привязан .
Начинаю на сигналке процедуру привязки GSM (7 раз нажал кн валет и включил
зажигание)
Starline Response: 0A 00 00 08 FF 00 00 00 00 11 CS is OK!
Door: 0 Ign: 1 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
Starline Response: 0B 58 61 00 00 00 00 00 00 C4 CS is OK!
Registration GSM successfully completed!
Starline Response: 0A 80 00 08 FF 00 00 00 00 91 CS is OK!
Door: 0 Ign: 1 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
т.к. GSM успешно привязан , выключаю зажигание
Starline Response: 0A 80 00 00 FF 00 00 00 00 89 CS is OK!
Door: 0 Ign: 0 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
Starline Response: 0A 00 00 00 FF 00 00 00 00 09 CS is OK!
Door: 0 Ign: 0 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
Ставлю на охрану с терминала
Send SMS Ohrana ON:
Send to Starline: 0A 9D D4 ED FF 00 00 00 00 67
Starline Response: 0A 60 00 00 FF 00 00 00 00 69 CS is OK!
Door: 0 Ign: 0 Brake: 0 Trunk: 0 Hood: 0 Locks: 1 Ohrana: 1 Trevoga: 0 Shock: 0 Tilt: 0
Снимаю с охраны с терминала
Send SMS Ohrana OFF:
Send to Starline: 0A EA A2 9B FF 00 00 00 00 30
Starline Response: 0A 00 00 00 FF 00 00 00 00 09 CS is OK!
Door: 0 Ign: 0 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
тут я включил зажигание
Starline Response: 0A 00 00 08 FF 00 00 00 00 11 CS is OK!
Door: 0 Ign: 1 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
Starline Response: 0A 80 00 08 FF 00 00 00 00 91 CS is OK!
Door: 0 Ign: 1 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
тут я выключил зажигание
Starline Response: 0A 80 00 00 FF 00 00 00 00 89 CS is OK!
Door: 0 Ign: 0 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0
Starline Response: 0A 00 00 00 FF 00 00 00 00 09 CS is OK!
Door: 0 Ign: 0 Brake: 0 Trunk: 0 Hood: 0 Locks: 0 Ohrana: 0 Trevoga: 0 Shock: 0 Tilt: 0