mirror of https://github.com/lumapu/ahoy.git
				
				
			
			You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							605 lines
						
					
					
						
							17 KiB
						
					
					
				
			
		
		
		
			
			
			
		
		
	
	
							605 lines
						
					
					
						
							17 KiB
						
					
					
				| #include <Arduino.h> | |
| #include <SPI.h> | |
| #include "CircularBuffer.h" | |
| #include <RF24.h> | |
| #include "printf.h" | |
| #include <RF24_config.h> | |
| #include "hm_crc.h" | |
| #include "hm_packets.h" | |
|  | |
| #include "Settings.h"     // Header für Einstellungen | |
| #include "Debug.h" | |
| #include "Inverters.h" | |
|  | |
| const char VERSION[] PROGMEM = "0.1.6"; | |
| 
 | |
| 
 | |
| #ifdef ESP8266 | |
|   #define DISABLE_EINT noInterrupts() | |
|   #define ENABLE_EINT  interrupts() | |
| #else     // für AVR z.B. ProMini oder Nano | |
|   #define DISABLE_EINT EIMSK = 0x00 | |
|   #define ENABLE_EINT EIMSK = 0x01 | |
| #endif | |
|  | |
| 
 | |
| #ifdef ESP8266 | |
| #define PACKET_BUFFER_SIZE      (30)  | |
| #else | |
| #define PACKET_BUFFER_SIZE      (20)  | |
| #endif | |
|  | |
| // Startup defaults until user reconfigures it | |
| //#define DEFAULT_RECV_CHANNEL    (3)             // 3 = Default channel for Hoymiles | |
| //#define DEFAULT_SEND_CHANNEL  (75)            // 40 = Default channel for Hoymiles, 61 | |
|  | |
| static HM_Packets     hmPackets; | |
| static uint32_t       tickMillis; | |
| 
 | |
| // Set up nRF24L01 radio on SPI bus plus CE/CS pins | |
| // If more than one RF24 unit is used the another CS pin than 10 must be used | |
| // This pin is used hard coded in SPI library | |
| static RF24 Radio (RF1_CE_PIN, RF1_CS_PIN); | |
| 
 | |
| static NRF24_packet_t bufferData[PACKET_BUFFER_SIZE]; | |
| 
 | |
| static CircularBuffer<NRF24_packet_t> packetBuffer(bufferData, sizeof(bufferData) / sizeof(bufferData[0])); | |
| 
 | |
| static Serial_header_t SerialHdr; | |
| 
 | |
| #define CHECKCRC  1 | |
| static uint16_t lastCRC; | |
| static uint16_t crc; | |
| 
 | |
| uint8_t         channels[]            = {3, 23, 40, 61, 75};   //{1, 3, 6, 9, 11, 23, 40, 61, 75} | |
| uint8_t         channelIdx            = 2;                         // fange mit 40 an | |
| uint8_t         DEFAULT_SEND_CHANNEL  = channels[channelIdx];      // = 40 | |
|  | |
| #if USE_POOR_MAN_CHANNEL_HOPPING_RCV | |
| uint8_t         rcvChannelIdx         = 0;  | |
| uint8_t         rcvChannels[]         = {3, 23, 40, 61, 75};   //{1, 3, 6, 9, 11, 23, 40, 61, 75} | |
| uint8_t         DEFAULT_RECV_CHANNEL  = rcvChannels[rcvChannelIdx];      //3; | |
| uint8_t         intvl = 4;          // Zeit für poor man hopping | |
| int             hophop; | |
| #else | |
| uint8_t         DEFAULT_RECV_CHANNEL  = 3; | |
| #endif | |
|  | |
| boolean         valueChanged          = false; | |
| 
 | |
| static unsigned long timeLastPacket = millis(); | |
| static unsigned long timeLastIstTagCheck =  millis(); | |
| static unsigned long timeLastRcvChannelSwitch = millis(); | |
| 
 | |
| // Function forward declaration | |
| static void SendPacket(uint64_t dest, uint8_t *buf, uint8_t len); | |
| 
 | |
| 
 | |
| static const char BLANK = ' '; | |
| 
 | |
| static boolean istTag = true; | |
| 
 | |
| char CHANNELNAME_BUFFER[15]; | |
| 
 | |
| #ifdef ESP8266 | |
|   #include "wifi.h" | |
|   #include "ModWebserver.h" | |
|   #include "Sonne.h" | |
| #endif | |
|  | |
| 
 | |
| inline static void dumpData(uint8_t *p, int len) { | |
| //----------------------------------------------- | |
|   while (len > 0){ | |
|     if (*p < 16) | |
|       DEBUG_OUT.print(F("0")); | |
|     DEBUG_OUT.print(*p++, HEX); | |
|     len--; | |
|   } | |
|   DEBUG_OUT.print(BLANK); | |
| } | |
| 
 | |
| 
 | |
| float extractValue2 (uint8_t *p, int divisor) { | |
| //------------------------------------------- | |
|   uint16_t b1 = *p++; | |
|   return ((float) (b1 << 8) + *p) / (float) divisor; | |
| } | |
| 
 | |
| 
 | |
| float extractValue4 (uint8_t *p, int divisor) { | |
| //------------------------------------------- | |
|   uint32_t ret  = *p++; | |
|   for (uint8_t i = 1; i <= 3; i++) | |
|     ret = (ret << 8) + *p++; | |
|   return (ret / divisor); | |
| } | |
| 
 | |
| void outChannel (uint8_t wr, uint8_t i) { | |
| //------------------------------------ | |
|   DEBUG_OUT.print(getMeasureName(wr, i));  | |
|   DEBUG_OUT.print(F("\t:"));  | |
|   DEBUG_OUT.print(getMeasureValue(wr,i));  | |
|   DEBUG_OUT.println(BLANK);   | |
| } | |
| 
 | |
| 
 | |
| void analyseWords (uint8_t *p) {    // p zeigt auf 01 hinter 2. WR-Adr | |
| //---------------------------------- | |
|   //uint16_t val; | |
|   DEBUG_OUT.print (F("analyse words:")); | |
|   p++; | |
|   for (int i = 0; i <12;i++) { | |
|     DEBUG_OUT.print(extractValue2(p,1)); | |
|     DEBUG_OUT.print(BLANK); | |
|     p++; | |
|   } | |
|   DEBUG_OUT.println(); | |
| } | |
| 
 | |
| void analyseLongs (uint8_t *p) {    // p zeigt auf 01 hinter 2. WR-Adr | |
| //---------------------------------- | |
|   //uint16_t val; | |
|   DEBUG_OUT.print (F("analyse longs:")); | |
|   p++; | |
|   for (int i = 0; i <12;i++) { | |
|     DEBUG_OUT.print(extractValue4(p,1)); | |
|     DEBUG_OUT.print(BLANK); | |
|     p++; | |
|   } | |
|   DEBUG_OUT.println(); | |
| } | |
| 
 | |
| 
 | |
| void analyse (NRF24_packet_t *p) { | |
| //------------------------------ | |
|   uint8_t wrIdx = findInverter (&p->packet[3]); | |
|   //DEBUG_OUT.print ("wrIdx="); DEBUG_OUT.println (wrIdx); | |
|   if (wrIdx == 0xFF) return; | |
|   uint8_t cmd = p->packet[11]; | |
|   float val = 0; | |
|   if (cmd == 0x01 || cmd == 0x02 || cmd == 0x83) { | |
|     const measureDef_t *defs = inverters[wrIdx].measureDef; | |
| 
 | |
|     for (uint8_t i = 0; i < inverters[wrIdx].anzMeasures; i++) { | |
|       if (defs[i].teleId == cmd) { | |
|         uint8_t pos = defs[i].pos; | |
|         if (defs[i].bytes == 2)   | |
|           val = extractValue2 (&p->packet[pos], getDivisor(wrIdx, i) ); | |
|         else if (defs[i].bytes == 4) | |
|           val = extractValue4 (&p->packet[pos], getDivisor(wrIdx, i) ); | |
|         valueChanged = valueChanged ||(val != inverters[wrIdx].values[i]); | |
|         inverters[wrIdx].values[i] = val; | |
|       }       | |
|     } | |
|     // calculated funstions | |
|     for (uint8_t i = 0; i < inverters[wrIdx].anzMeasureCalculated; i++) { | |
|       val = inverters[wrIdx].measureCalculated[i].f (inverters[wrIdx].values); | |
|       int idx = inverters[wrIdx].anzMeasures + i; | |
|       valueChanged = valueChanged ||(val != inverters[wrIdx].values[idx]); | |
|       inverters[wrIdx].values[idx] = val; | |
|     } | |
|   } | |
|   else if (cmd == 0x81) { | |
|     ; | |
|   } | |
|   else { | |
|     DEBUG_OUT.print (F("---- neues cmd=")); DEBUG_OUT.println(cmd, HEX); | |
|     analyseWords (&p->packet[11]); | |
|     analyseLongs (&p->packet[11]); | |
|     DEBUG_OUT.println(); | |
|   } | |
|   if (p->packetsLost > 0) { | |
|     DEBUG_OUT.print(F(" Lost: ")); | |
|     DEBUG_OUT.println(p->packetsLost); | |
|   } | |
| } | |
| 
 | |
| #ifdef ESP8266 | |
| IRAM_ATTR | |
| #endif | |
| void handleNrf1Irq() { | |
| //------------------------- | |
|   static uint8_t lostPacketCount = 0; | |
|   uint8_t pipe; | |
| 
 | |
|   DISABLE_EINT; | |
|    | |
|   // Loop until RX buffer(s) contain no more packets. | |
|   while (Radio.available(&pipe)) { | |
|     if (!packetBuffer.full()) { | |
|       NRF24_packet_t *p = packetBuffer.getFront(); | |
|       p->timestamp = micros(); // Micros does not increase in interrupt, but it can be used. | |
|       p->packetsLost = lostPacketCount; | |
|       p->rcvChannel  = DEFAULT_RECV_CHANNEL; | |
|       uint8_t packetLen = Radio.getPayloadSize(); | |
|       if (packetLen > MAX_RF_PAYLOAD_SIZE) | |
|         packetLen = MAX_RF_PAYLOAD_SIZE; | |
| 
 | |
|       Radio.read(p->packet, packetLen); | |
|       packetBuffer.pushFront(p); | |
|       lostPacketCount = 0; | |
|     } | |
|     else { | |
|       // Buffer full. Increase lost packet counter. | |
|       bool tx_ok, tx_fail, rx_ready; | |
|       if (lostPacketCount < 255) | |
|         lostPacketCount++; | |
|       // Call 'whatHappened' to reset interrupt status. | |
|       Radio.whatHappened(tx_ok, tx_fail, rx_ready); | |
|       // Flush buffer to drop the packet. | |
|       Radio.flush_rx(); | |
|     } | |
|   } | |
|   ENABLE_EINT; | |
| } | |
| 
 | |
| 
 | |
| static void activateConf(void) { | |
| //----------------------------- | |
|   Radio.begin(); | |
|   // Disable shockburst for receiving and decode payload manually | |
|   Radio.setAutoAck(false); | |
|   Radio.setRetries(0, 0); | |
|   Radio.setChannel(DEFAULT_RECV_CHANNEL); | |
|   Radio.setDataRate(DEFAULT_RF_DATARATE); | |
|   Radio.disableCRC(); | |
|   Radio.setAutoAck(0x00); | |
|   Radio.setPayloadSize(MAX_RF_PAYLOAD_SIZE); | |
|   Radio.setAddressWidth(5); | |
|   Radio.openReadingPipe(1, DTU_RADIO_ID); | |
| 
 | |
|   // We want only RX irqs | |
|   Radio.maskIRQ(true, true, false); | |
| 
 | |
|   // Use lo PA level, as a higher level will disturb CH340 DEBUG_OUT usb adapter | |
|   Radio.setPALevel(RF24_PA_MAX); | |
|   Radio.startListening(); | |
| 
 | |
|   // Attach interrupt handler to NRF IRQ output. Overwrites any earlier handler. | |
|   attachInterrupt(digitalPinToInterrupt(RF1_IRQ_PIN), handleNrf1Irq, FALLING); // NRF24 Irq pin is active low. | |
|  | |
|   // Initialize SerialHdr header's address member to promiscuous address. | |
|   uint64_t addr = DTU_RADIO_ID; | |
|   for (int8_t i = sizeof(SerialHdr.address) - 1; i >= 0; --i) { | |
|     SerialHdr.address[i] = addr; | |
|     addr >>= 8; | |
|   } | |
| 
 | |
|   //Radio.printDetails(); | |
|   //DEBUG_OUT.println(); | |
|   tickMillis = millis() + 200; | |
| } | |
| 
 | |
| #define resetRF24() activateConf() | |
|  | |
| 
 | |
| void setup(void) { | |
| //-------------- | |
|   #ifndef DEBUG | |
|   #ifndef ESP8266 | |
|   Serial.begin(SER_BAUDRATE); | |
|   #endif | |
|   #endif | |
|   printf_begin(); | |
|   DEBUG_OUT.begin(SER_BAUDRATE); | |
|   DEBUG_OUT.flush(); | |
| 
 | |
|   DEBUG_OUT.println(F("-- Hoymiles DTU Simulation --")); | |
| 
 | |
|   // Configure nRF IRQ input | |
|   pinMode(RF1_IRQ_PIN, INPUT); | |
| 
 | |
|   activateConf(); | |
| 
 | |
| #ifdef ESP8266 | |
|   setupWifi(); | |
|   setupClock(); | |
|   setupWebServer(); | |
|   setupUpdateByOTA(); | |
|   calcSunUpDown (getNow()); | |
|   istTag = isDayTime(); | |
|   DEBUG_OUT.print (F("Es ist ")); DEBUG_OUT.println (istTag?F("Tag"):F("Nacht")); | |
|   hmPackets.SetUnixTimeStamp (getNow()); | |
| #else | |
|   hmPackets.SetUnixTimeStamp(0x62456430); | |
| #endif | |
|  | |
|   setupInverts(); | |
| } | |
| 
 | |
|  uint8_t sendBuf[MAX_RF_PAYLOAD_SIZE]; | |
| 
 | |
| void isTime2Send () { | |
| //----------------- | |
|   // Second timer | |
|   static const uint8_t warteZeit = 1; | |
|   static uint8_t tickSec = 0; | |
|   if (millis() >= tickMillis) { | |
|     static uint8_t tel = 0; | |
|     tickMillis += warteZeit*1000;    //200; | |
|     tickSec++;  | |
|     | |
|     if (++tickSec >= 1) {   // 5 | |
|       for (uint8_t c=0; c < warteZeit; c++) hmPackets.UnixTimeStampTick(); | |
|       tickSec = 0; | |
|     }  | |
| 
 | |
|     int32_t size = 0; | |
|     uint64_t dest =  0; | |
|     for (uint8_t wr = 0; wr < anzInv; wr++) { | |
|       dest = inverters[wr].RadioId; | |
| 
 | |
|       if (tel > 1) | |
|         tel = 0; | |
|        | |
|       if (tel == 0) { | |
|         #ifdef ESP8266 | |
|         hmPackets.SetUnixTimeStamp (getNow()); | |
|         #endif | |
|         size = hmPackets.GetTimePacket((uint8_t *)&sendBuf, dest >> 8, DTU_RADIO_ID >> 8); | |
|         //DEBUG_OUT.print ("Timepacket mit cid="); DEBUG_OUT.println(sendBuf[10], HEX); | |
|       } | |
|       else if (tel <= 1)  | |
|         size = hmPackets.GetCmdPacket((uint8_t *)&sendBuf, dest >> 8, DTU_RADIO_ID >> 8, 0x15,  0x80 + tel - 1); | |
| 
 | |
|       SendPacket (dest, (uint8_t *)&sendBuf, size); | |
|     }  // for wr | |
|  | |
|     tel++; | |
|      | |
| /*    for (uint8_t warte = 0; warte < 2; warte++) { | |
|       delay(1000); | |
|       hmPackets.UnixTimeStampTick(); | |
|     }*/  | |
|   } | |
| } | |
| 
 | |
| 
 | |
| void outputPacket(NRF24_packet_t *p, uint8_t payloadLen) { | |
| //----------------------------------------------------- | |
|  | |
|     // Write timestamp, packets lost, address and payload length | |
|     //printf(" %09lu ", SerialHdr.timestamp); | |
|     char _buf[20]; | |
|     sprintf_P(_buf, PSTR("rcv CH:%d "), p->rcvChannel); | |
|     DEBUG_OUT.print (_buf); | |
|     dumpData((uint8_t *)&SerialHdr.packetsLost, sizeof(SerialHdr.packetsLost)); | |
|     dumpData((uint8_t *)&SerialHdr.address, sizeof(SerialHdr.address)); | |
| 
 | |
|     // Trailing bit?!? | |
|     dumpData(&p->packet[0], 2); | |
| 
 | |
|     // Payload length from PCF | |
|     dumpData(&payloadLen, sizeof(payloadLen)); | |
| 
 | |
|     // Packet control field - PID Packet identification | |
|     uint8_t val = (p->packet[1] >> 1) & 0x03; | |
|     DEBUG_OUT.print(val); | |
|     DEBUG_OUT.print(F("  ")); | |
| 
 | |
|     if (payloadLen > 9) { | |
|       dumpData(&p->packet[2], 1); | |
|       dumpData(&p->packet[3], 4); | |
|       dumpData(&p->packet[7], 4); | |
|        | |
|       uint16_t remain = payloadLen - 2 - 1 - 4 - 4 + 4; | |
| 
 | |
|       if (remain < 32) { | |
|         dumpData(&p->packet[11], remain); | |
|         printf_P(PSTR("%04X "), crc); | |
| 
 | |
|         if (((crc >> 8) != p->packet[payloadLen + 2]) || ((crc & 0xFF) != p->packet[payloadLen + 3])) | |
|           DEBUG_OUT.print(0); | |
|         else | |
|           DEBUG_OUT.print(1); | |
|       } | |
|       else { | |
|         DEBUG_OUT.print(F("Ill remain ")); | |
|         DEBUG_OUT.print(remain); | |
|       } | |
|     } | |
|     else { | |
|       dumpData(&p->packet[2], payloadLen + 2); | |
|       printf_P(PSTR("%04X "), crc); | |
|     } | |
|     DEBUG_OUT.println();  | |
|     DEBUG_OUT.flush(); | |
| } | |
| 
 | |
| void writeArduinoInterface() { | |
| //-------------------------- | |
|   if (valueChanged) { | |
|     for (uint8_t wr = 0; wr < anzInv; wr++) { | |
|       if (anzInv > 1) { | |
|         Serial.print(wr); Serial.print('.'); | |
|       } | |
|       for (uint8_t i = 0; i < inverters[wr].anzTotalMeasures; i++) { | |
|         Serial.print(getMeasureName(wr,i));    // Schnittstelle bei Arduino | |
|         Serial.print('=');  | |
|         Serial.print(getMeasureValue(wr,i), getDigits(wr,i));   // Schnittstelle bei Arduino | |
|         Serial.print (BLANK); | |
|         Serial.println (getUnit(wr, i)); | |
|       }  // for i | |
|        | |
|     }  // for wr | |
|     Serial.println(F("-----------------------")); | |
|     valueChanged = false; | |
|   } | |
| } | |
| 
 | |
| boolean doCheckCrc (NRF24_packet_t *p, uint8_t payloadLen) { | |
| //-------------------------------------------------------- | |
|   crc = 0xFFFF; | |
|   crc = crc16((uint8_t *)&SerialHdr.address, sizeof(SerialHdr.address), crc, 0, BYTES_TO_BITS(sizeof(SerialHdr.address))); | |
|   // Payload length | |
|   // Add one byte and one bit for 9-bit packet control field | |
|   crc = crc16((uint8_t *)&p->packet[0], sizeof(p->packet), crc, 7, BYTES_TO_BITS(payloadLen + 1) + 1); | |
|    | |
|   if (CHECKCRC) { | |
|     // If CRC is invalid only show lost packets | |
|     if (((crc >> 8) != p->packet[payloadLen + 2]) || ((crc & 0xFF) != p->packet[payloadLen + 3])) { | |
|       if (p->packetsLost > 0) { | |
|         DEBUG_OUT.print(F(" Lost: ")); | |
|         DEBUG_OUT.println(p->packetsLost); | |
|       } | |
|       packetBuffer.popBack(); | |
|       return false; | |
|     } | |
|    | |
|     // Dump a decoded packet only once | |
|     if (lastCRC == crc) { | |
|       packetBuffer.popBack(); | |
|       return false; | |
|     } | |
|     lastCRC = crc; | |
|   } | |
|    | |
|   // Don't dump mysterious ack packages | |
|   if (payloadLen == 0) { | |
|       packetBuffer.popBack(); | |
|       return false; | |
|   } | |
|   return true; | |
| } | |
| 
 | |
| void poorManChannelHopping() { | |
| //-------------------------- | |
|   if (hophop <= 0) return; | |
|   if (millis() >= timeLastRcvChannelSwitch + intvl) { | |
|     rcvChannelIdx++; | |
|     if (rcvChannelIdx >= sizeof(rcvChannels)) | |
|       rcvChannelIdx = 0; | |
|     DEFAULT_RECV_CHANNEL  = rcvChannels[rcvChannelIdx];  | |
|     DISABLE_EINT; | |
|     Radio.stopListening(); | |
|     Radio.setChannel (DEFAULT_RECV_CHANNEL); | |
|     Radio.startListening(); | |
|     ENABLE_EINT;       | |
|     timeLastRcvChannelSwitch = millis(); | |
|     hophop--; | |
|   } | |
|    | |
| } | |
| void loop(void) { | |
| //============= | |
|   // poor man channel hopping on receive | |
| #if USE_POOR_MAN_CHANNEL_HOPPING_RCV | |
|   poorManChannelHopping(); | |
| #endif | |
|  | |
|   if (millis()  > timeLastPacket + 50000UL) { | |
|     DEBUG_OUT.println (F("Reset RF24")); | |
|     resetRF24(); | |
|     timeLastPacket = millis();  | |
|   } | |
|    | |
|   while (!packetBuffer.empty()) { | |
|     timeLastPacket = millis(); | |
|     // One or more records present | |
|     NRF24_packet_t *p = packetBuffer.getBack(); | |
| 
 | |
|     // Shift payload data due to 9-bit packet control field | |
|     for (int16_t j = sizeof(p->packet) - 1; j >= 0; j--) { | |
|       if (j > 0) | |
|         p->packet[j] = (byte)(p->packet[j] >> 7) | (byte)(p->packet[j - 1] << 1); | |
|       else | |
|         p->packet[j] = (byte)(p->packet[j] >> 7); | |
|     } | |
| 
 | |
|     SerialHdr.timestamp   = p->timestamp; | |
|     SerialHdr.packetsLost = p->packetsLost; | |
| 
 | |
|     uint8_t payloadLen = ((p->packet[0] & 0x01) << 5) | (p->packet[1] >> 3); | |
|     // Check CRC | |
|     if (! doCheckCrc(p, payloadLen) ) | |
|       continue; | |
| 
 | |
|     #ifdef DEBUG | |
|     uint8_t cmd = p->packet[11]; | |
|     //if (cmd != 0x01 && cmd != 0x02 && cmd != 0x83 && cmd != 0x81) | |
|       outputPacket (p, payloadLen); | |
|     #endif | |
|  | |
|     analyse (p); | |
| 
 | |
|     #ifndef ESP8266 | |
|     writeArduinoInterface(); | |
|     #endif | |
|      | |
|     // Remove record as we're done with it. | |
|     packetBuffer.popBack(); | |
|   } | |
| 
 | |
|   if (istTag)  | |
|     isTime2Send(); | |
| 
 | |
|   #ifdef ESP8266 | |
|   checkWifi(); | |
|   webserverHandle();        | |
|   checkUpdateByOTA(); | |
|   if (hour() == 0 && minute() == 0) { | |
|     calcSunUpDown(getNow());   | |
|     delay (60*1000); | |
|   } | |
| 
 | |
|   if (millis() > timeLastIstTagCheck + 15UL * 60UL * 1000UL) {   // alle 15 Minuten neu berechnen ob noch hell | |
|     istTag = isDayTime(); | |
|     DEBUG_OUT.print (F("Es ist ")); DEBUG_OUT.println (istTag?F("Tag"):F("Nacht")); | |
|     timeLastIstTagCheck = millis(); | |
|   } | |
|   #endif | |
| /* | |
|   if (millis() > timeLastPacket + 60UL*SECOND) {  // 60 Sekunden | |
|     channelIdx++; | |
|     if (channelIdx >= sizeof(channels)) channelIdx = 0; | |
|     DEFAULT_SEND_CHANNEL = channels[channelIdx]; | |
|     DEBUG_OUT.print (F("\nneuer DEFAULT_SEND_CHANNEL: ")); DEBUG_OUT.println(DEFAULT_SEND_CHANNEL); | |
|     timeLastPacket = millis(); | |
|   } | |
| */ | |
| } | |
| 
 | |
| 
 | |
| static void SendPacket(uint64_t dest, uint8_t *buf, uint8_t len) { | |
| //-------------------------------------------------------------- | |
|   //DEBUG_OUT.print (F("Sende: ")); DEBUG_OUT.println (buf[9],  HEX); | |
|   //dumpData (buf, len); DEBUG_OUT.println(); | |
|   DISABLE_EINT; | |
|   Radio.stopListening(); | |
| 
 | |
| #ifdef CHANNEL_HOP | |
|   static uint8_t hop = 0; | |
|   #if DEBUG_SEND     | |
|   DEBUG_OUT.print(F("Send... CH")); | |
|   DEBUG_OUT.println(channels[hop]); | |
|   #endif   | |
|   Radio.setChannel(channels[hop++]); | |
|   if (hop >= sizeof(channels) / sizeof(channels[0])) | |
|     hop = 0; | |
| #else | |
|   Radio.setChannel(DEFAULT_SEND_CHANNEL); | |
| #endif | |
|  | |
|   Radio.openWritingPipe(dest); | |
|   Radio.setCRCLength(RF24_CRC_16); | |
|   Radio.enableDynamicPayloads(); | |
|   Radio.setAutoAck(true); | |
|   Radio.setRetries(3, 15); | |
| 
 | |
|   bool res = Radio.write(buf, len); | |
|   // Try to avoid zero payload acks (has no effect) | |
|   Radio.openWritingPipe(DUMMY_RADIO_ID); | |
| 
 | |
|   Radio.setAutoAck(false); | |
|   Radio.setRetries(0, 0); | |
|   Radio.disableDynamicPayloads(); | |
|   Radio.setCRCLength(RF24_CRC_DISABLED); | |
| 
 | |
|   Radio.setChannel(DEFAULT_RECV_CHANNEL); | |
|   Radio.startListening(); | |
|   ENABLE_EINT; | |
| #if USE_POOR_MAN_CHANNEL_HOPPING_RCV | |
|   hophop = 5 * sizeof(rcvChannels); | |
| #endif | |
| }
 | |
| 
 |