|
|
|
@ -6,30 +6,183 @@
@@ -6,30 +6,183 @@
|
|
|
|
|
#include "Arduino.h" |
|
|
|
|
#include "SoftRS485.h" |
|
|
|
|
|
|
|
|
|
SoftRS485 SoftRS485::instance; |
|
|
|
|
//#define DEBUG
|
|
|
|
|
#define IDLE -1 |
|
|
|
|
#define START -2 |
|
|
|
|
#define MSG_LEN 64 |
|
|
|
|
|
|
|
|
|
int _RO, _RE, _DE, _DI; |
|
|
|
|
|
|
|
|
|
/* INCOMING */ |
|
|
|
|
byte _recv_byte = 0x0; |
|
|
|
|
boolean _recv_bit = false; |
|
|
|
|
char _recv_message[MSG_LEN]; |
|
|
|
|
int _recv_idx = 0; // used as bit-index for _recv_byte
|
|
|
|
|
int _recv_pos = IDLE; // used as char-index for _recv_message
|
|
|
|
|
|
|
|
|
|
/* OUTGOING */ |
|
|
|
|
char _message_out[MSG_LEN]; |
|
|
|
|
int _send_pos = IDLE; |
|
|
|
|
int _send_idx = 0; |
|
|
|
|
|
|
|
|
|
ISR(TIMER1_COMPA_vect){ |
|
|
|
|
OCR1A += 62500; // Advance The COMPA Register
|
|
|
|
|
|
|
|
|
|
_recv_bit = !digitalRead(_RO); // input line is HIGH by default
|
|
|
|
|
if (_recv_pos == IDLE){ |
|
|
|
|
if (_recv_bit) { // first 1 indicates incoming message
|
|
|
|
|
_recv_pos = 0; |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.println(F("start of message reception")); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
} else { // we are reading!
|
|
|
|
|
_recv_byte |= _recv_bit << _recv_idx; |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print(F("received bit #")); |
|
|
|
|
Serial.print(_recv_idx); |
|
|
|
|
Serial.print(": "); |
|
|
|
|
Serial.println(_recv_bit); |
|
|
|
|
Serial.print(F("byte is now ")); |
|
|
|
|
Serial.println(_recv_byte,BIN); |
|
|
|
|
#endif |
|
|
|
|
if (_recv_idx == 7){ // byte complete
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print(F("byte complete: ")); |
|
|
|
|
Serial.println(_recv_byte); |
|
|
|
|
#endif |
|
|
|
|
_recv_idx = 0; |
|
|
|
|
_recv_message[_recv_pos] = _recv_byte; |
|
|
|
|
if (_recv_byte == 0x00){ // we encountered a 0-byte! End of message!
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print(F("got 0-byte!\nmessage reception complete: ")); |
|
|
|
|
Serial.println(_recv_message); |
|
|
|
|
#endif |
|
|
|
|
_recv_idx = 0; |
|
|
|
|
_recv_pos = IDLE; |
|
|
|
|
} else { |
|
|
|
|
_recv_byte = 0x00; |
|
|
|
|
if (_recv_pos<MSG_LEN-1) { |
|
|
|
|
_recv_pos++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} else _recv_idx++; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
boolean bit = LOW; |
|
|
|
|
|
|
|
|
|
if (_send_pos >= 0){ |
|
|
|
|
char c = _message_out[_send_pos]; |
|
|
|
|
if (c == 0x00) { // end of message
|
|
|
|
|
digitalWrite(_DI,HIGH); |
|
|
|
|
digitalWrite(_DE,LOW); |
|
|
|
|
_send_pos = IDLE; |
|
|
|
|
_send_idx = 0; |
|
|
|
|
_message_out[0] = 0x00; |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.println("Message transmission completed!"); |
|
|
|
|
#endif |
|
|
|
|
} else { |
|
|
|
|
bit = !(c & 1<<_send_idx); |
|
|
|
|
digitalWrite(_DI,bit); |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print("Sending bit #"); |
|
|
|
|
Serial.print(_send_idx); |
|
|
|
|
Serial.print(" ("); |
|
|
|
|
Serial.print(bit); |
|
|
|
|
Serial.print(") of "); |
|
|
|
|
Serial.print(c); |
|
|
|
|
Serial.print(" ("); |
|
|
|
|
Serial.print(c,BIN); |
|
|
|
|
Serial.println(")"); |
|
|
|
|
#endif |
|
|
|
|
_send_idx++; |
|
|
|
|
if (_send_idx>7){ |
|
|
|
|
_send_idx =0; |
|
|
|
|
_send_pos++; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (_send_pos == START && _recv_pos == IDLE && _message_out[0] != 0x00) { // outgoig message awaits, line is idle
|
|
|
|
|
digitalWrite(_DE,HIGH); // enable driver
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.println(F("starting transmission")); |
|
|
|
|
#endif |
|
|
|
|
digitalWrite(_DI,bit); // send start bit
|
|
|
|
|
_send_pos = 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
if (_send_pos != IDLE && digitalRead(_RO) != bit){ // driver output state mismatch!
|
|
|
|
|
digitalWrite(_DE,LOW); // disable driver
|
|
|
|
|
_send_pos = START; |
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.println(F("collision!")); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
SoftRS485 SoftRS485::singleton(){ |
|
|
|
|
return instance; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SoftRS485::isr(){ |
|
|
|
|
instance.bam(); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SoftRS485::begin(int RO, int nRE, int DE, int DI){ |
|
|
|
|
_RO = RO; |
|
|
|
|
_RE = nRE; |
|
|
|
|
_DE = DE; |
|
|
|
|
_DI = DI; |
|
|
|
|
void init485(int RO, int nRE, int DE, int DI){ |
|
|
|
|
_RO=RO; |
|
|
|
|
_RE=nRE; |
|
|
|
|
_DE=DE; |
|
|
|
|
_DI=DI; |
|
|
|
|
_recv_message[0] = 0x00; // empty
|
|
|
|
|
_message_out[0] = 0x00; // empty
|
|
|
|
|
pinMode(_RO,INPUT); |
|
|
|
|
|
|
|
|
|
pinMode(_RE,OUTPUT); |
|
|
|
|
digitalWrite(_RE,LOW); // enable reading
|
|
|
|
|
|
|
|
|
|
pinMode(_DE,OUTPUT); |
|
|
|
|
digitalWrite(_DE,LOW); // disable writing
|
|
|
|
|
|
|
|
|
|
pinMode(_DI,OUTPUT); |
|
|
|
|
digitalWrite(_DI,LOW); // output line = LOW
|
|
|
|
|
|
|
|
|
|
TCCR1A = 0; // Init Timer1A
|
|
|
|
|
TCCR1B = 0; // Init Timer1B
|
|
|
|
|
TCCR1B |= B00000001; // Prescaler = 512
|
|
|
|
|
OCR1A = 500; // Timer Compare1A Register
|
|
|
|
|
TIMSK1 |= B00000010; // Enable Timer COMPA Interrupt
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.begin(115200); |
|
|
|
|
pinMode(_RE, OUTPUT); |
|
|
|
|
pinMode(_DE, OUTPUT); |
|
|
|
|
pinMode(_DI, OUTPUT); |
|
|
|
|
pinMode(_RO, INPUT); |
|
|
|
|
attachInterrupt(digitalPinToInterrupt(_RO),isr,CHANGE); |
|
|
|
|
Serial.println("attached to interrupt!"); |
|
|
|
|
Serial.println("Started timer!"); |
|
|
|
|
Serial.print("RO = "); |
|
|
|
|
Serial.println(_RO); |
|
|
|
|
Serial.print("^RE = "); |
|
|
|
|
Serial.println(_RE); |
|
|
|
|
Serial.print("DE = "); |
|
|
|
|
Serial.println(_DE); |
|
|
|
|
Serial.print("DI = "); |
|
|
|
|
Serial.println(_DI); |
|
|
|
|
#endif |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
void SoftRS485::bam(){ |
|
|
|
|
Serial.println("bam!"); |
|
|
|
|
boolean available485(){ |
|
|
|
|
return _recv_pos == IDLE && _recv_message[0] != 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
String get485Message(){ |
|
|
|
|
String res = String(_recv_message); |
|
|
|
|
_recv_message[0] = 0; |
|
|
|
|
return res; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
boolean send485(char message[]){ |
|
|
|
|
if (_message_out[0] != 0x00) return false; // we already have a queued message, abort!
|
|
|
|
|
for (int idx = 0; idx<MSG_LEN; idx++){ |
|
|
|
|
_message_out[idx] = message[idx]; // copy message
|
|
|
|
|
if (message[idx] == 0x00) break; |
|
|
|
|
} |
|
|
|
|
if (_message_out[0] == 0x00) return false; // message is empty! abort
|
|
|
|
|
_send_pos = START; |
|
|
|
|
|
|
|
|
|
#ifdef DEBUG |
|
|
|
|
Serial.print("sending "); |
|
|
|
|
Serial.println(_message_out); |
|
|
|
|
#endif |
|
|
|
|
return true; |
|
|
|
|
} |
|
|
|
|