vad7 3 лет назад
Родитель
Сommit
962cc81f96
8 измененных файлов с 274 добавлено и 143 удалено
  1. BIN
      Nrf24_Scanner.fap
  2. 7 2
      README.md
  3. 0 4
      addr_sniff.txt
  4. 2 1
      addresses.txt
  5. 7 0
      lib/nrf24/nrf24.c
  6. 3 0
      lib/nrf24/nrf24.h
  7. 249 136
      nrf24scan.c
  8. 6 0
      sniff.txt

BIN
Nrf24_Scanner.fap


+ 7 - 2
README.md

@@ -10,7 +10,12 @@ ___________________________________________________________________________
 <b>Приложение для Flipper Zero, читающее эфир на радиомодулях nRF24L01.</b><br>
 Выбор пукта меню - стрелки вверх/вниз, стрелки влево/вправо либо изменют настройки либо управляют видом списка, кнопка ОК либо выбирает режим (короткое нажатие), либо выполняет дополнительное действие (длительное нажатие).<br><br>
 <img src="https://raw.githubusercontent.com/vad7/nrf24scan/master/Screenshot-1.png"><br>
-На начальном экране можно загрузить файл настроек (по умолчанию загружается settings.txt из папки nrf24_scanner на SD карте).<br>
+По умолчанию при запуске включается режим поиска (sniff) - ищутся все валидные пакеты с корректным CRC.<br>
+Размер CRC и тип пакета (Enhanced ShockBurst или нет) задается. CRC может быть или 1 или 2 байта.<br>
+Так как пакеты читаются в RAW формате, то длина полезной нагрузки не может быть больше 23 байт, пакеты с большей длинной не будут пойманы.<br>
+Изменение режима sniff/scan - стрелками на пункте Scan.<br><br>
+Режим сканирования (scan) - чтение пакетов по заданным в настройках мак адресам и настройкам.<br>
+На начальном экране в режиме чтения можно загрузить файл настроек (по умолчанию загружается settings.txt из папки nrf24_scanner на SD карте).<br>
 В файле настройке задаются адреса (максимум 6) в шестнадцатеричном виде (старший байт - первый), длина адреса вычисляется по P0.<br>
 Остальные настройки можно поменять интерактивно<br>
 Настройки сохраняются длительным нажатием на ОК.<br><br>
@@ -28,7 +33,7 @@ Payload - размер пакета в байтах<br>
 <b>Просмотр принятых пакетов</b><br><br>
 <img src="https://raw.githubusercontent.com/vad7/nrf24scan/master/Screenshot-2.png">
 <br>
-В пункте "Start scan" можно выбрать стрелками сканировать и смотреть или просто смотреть (view).<br>
+В пункте "Start scan/sniff" можно выбрать стрелками сканировать и смотреть или просто смотреть (view).<br>
 Если в файле настройки было несколько адресов, то первая цифра - номер канала (pipe) от 0 до 5.<br>
 Стрелки - перемещение по списку и горизонтальное скролирование<br>
 OK - отправка пакета<br>

+ 0 - 4
addr_sniff.txt

@@ -1,4 +0,0 @@
-Rate: 1
-Ch: 0
-P0: 0055
-P1: 00AA

+ 2 - 1
settings.txt → addresses.txt

@@ -6,4 +6,5 @@ CRC: 2
 P0: C8C8C0
 P1: C8C8C1
 P2: C2
-P2: C3
+P3: C3
+P4: E5

+ 7 - 0
lib/nrf24/nrf24.c

@@ -525,4 +525,11 @@ uint8_t nrf24_find_channel(
     }
 
     return ch;
+}
+
+uint8_t nrf24_set_mac(uint8_t mac_addr, uint8_t *mac, uint8_t mlen)
+{
+    uint8_t addr[5];
+	for(int i = 0; i < mlen; i++) addr[i] = mac[mlen - i - 1];
+	return nrf24_write_buf_reg(nrf24_HANDLE, mac_addr, addr, mlen);
 }

+ 3 - 0
lib/nrf24/nrf24.h

@@ -309,6 +309,9 @@ void nrf24_configure(
     bool noack,
     bool disable_aa);
 
+// Set mac address (MSB first), Return: Status
+uint8_t  nrf24_set_mac(uint8_t mac_addr, uint8_t *mac, uint8_t mlen);
+
 /** Configures the radio for "promiscuous mode" and primes it for rx
  * This is not an actual mode of the nrf24, but this function exploits a few bugs in the chip that allows it to act as if it were.
  * See http://travisgoodspeed.blogspot.com/2011/02/promiscuity-is-nrf24l01s-duty.html for details.

+ 249 - 136
nrf24scan.c

@@ -14,12 +14,13 @@
 #include <u8g2.h>
 
 #define TAG 		"nrf24scan"
-#define VERSION		"1.6"
+#define VERSION		"1.7"
 #define MAX_CHANNEL	125
 #define MAX_ADDR	6
 
 #define SCAN_APP_PATH_FOLDER "/ext/nrf24scan"
-#define SETTINGS_FILENAME "settings.txt"// File format (1 parameter per line): 
+#define SETTINGS_FILENAME "addresses.txt"// Settings file format (1 parameter per line): 
+									// SNIFF - if present then sniff mode
 									// Rate: 0/1/2 - rate in Mbps (=0.25/1/2)
 									// Ch: 0..125 - default channel
 									// ESB: 0/1 (1 - Enhanced ShockBurst)
@@ -36,6 +37,7 @@
 									//		first byte = { RAW packet flag (0x80/0x00) } + { channel number }
 									//		second byte = { Payload len 5 bits, 0 = 32 } + {{ RAW packet: ESB flag 0x04/0x00 + address size-2 if RAW packet } or { pipe #(0..5) }}, 
 									// ... up to MAX_LOG_RECORDS-1
+#define SNIFF_FILENAME "sniff.txt"	// settings for sniff mode
 #define LOG_FILENAME 		"log"
 #define LOG_FILEEXT	 		".txt"
 #define MAX_LOG_RECORDS		100
@@ -49,6 +51,7 @@ const char SettingsFld_ESB[] = "ESB:";
 const char SettingsFld_DPL[] = "DPL:";
 const char SettingsFld_CRC[] = "CRC:";
 const char SettingsFld_Payload[] = "Payload:";
+const char SettingsFld_Sniff[] = "SNIFF";
 char SettingsFld_Addr = 'P';
 
 Nrf24Scan* APP;
@@ -63,7 +66,8 @@ uint8_t NRF_channel = 0;// 0..125
 uint8_t NRF_ESB = 1;	// 0 - ShockBurst, 1 - Enhanced ShockBurst
 uint8_t NRF_DPL = 0;	// 1 - Dynamic Payload Length
 uint8_t NRF_CRC = 2;	// 1 - No, 1 - CRC 1byte, 2 - CRC 2byte
-uint8_t NRF_Payload = 23;// len in bytes, max 32
+uint8_t NRF_Payload = 32;// len in bytes, max 32
+uint8_t NRF_Sniff_payload_max = 28;
 uint8_t NRF_AA_OFF = 0;	// Disable Auto Acknowledgement
 bool NRF_ERROR = 0;
 
@@ -209,7 +213,8 @@ void write_to_log_file(Storage* storage, bool f_settings)
 	if(fl) {
 		FURI_LOG_D(TAG, "Save to %s", furi_string_get_cstr(str));
 		if(save_to_new_log || f_settings) {
-			furi_string_printf(str, "%s %d\n%s %d\n%s %d\n", SettingsFld_Rate, NRF_rate, SettingsFld_Ch, NRF_channel, SettingsFld_ESB, NRF_ESB);
+			furi_string_set(str, what_to_do == 1 ? SettingsFld_Sniff : "");
+			furi_string_cat_printf(str, "%s %d\n%s %d\n%s %d\n", SettingsFld_Rate, NRF_rate, SettingsFld_Ch, NRF_channel, SettingsFld_ESB, NRF_ESB);
 			furi_string_cat_printf(str, "%s %d\n%s %d\n%s %d\n", SettingsFld_DPL, NRF_DPL, SettingsFld_CRC, NRF_CRC, SettingsFld_Payload, NRF_Payload);
 			furi_string_cat_printf(str, "P0: ");
 			add_to_furi_str_hex_bytes(str, (char*)addrs.addr_P0, addrs.addr_len); furi_string_cat(str, "\n");
@@ -304,6 +309,7 @@ static uint8_t load_settings_file(Stream* file_stream) {
 		char* line_ptr = file_buf;
 		int16_t line_num = 0;
 		memset((uint8_t*)&addrs, 0, sizeof(addrs));
+		what_to_do = 2;
 		bool log_loaded = false;
 		while(line_ptr && (size_t)(line_ptr - file_buf) < file_size) {
 			char* end_ptr = strstr((char*)line_ptr, "\n");
@@ -328,20 +334,23 @@ static uint8_t load_settings_file(Stream* file_stream) {
 				NRF_DPL = atoi(line_ptr + sizeof(SettingsFld_DPL));
 			} else if(strncmp(line_ptr, SettingsFld_CRC, sizeof(SettingsFld_CRC)-1) == 0) {
 				NRF_CRC = atoi(line_ptr + sizeof(SettingsFld_CRC));
+				if(what_to_do == 1) view_log_decode_CRC = NRF_CRC;
 			} else if(strncmp(line_ptr, SettingsFld_Payload, sizeof(SettingsFld_Payload)-1) == 0) {
 				NRF_Payload = atoi(line_ptr + sizeof(SettingsFld_Payload));
 				if(NRF_Payload == 0 || NRF_Payload > 32) NRF_Payload = 32;
+			} else if(strncmp(line_ptr, SettingsFld_Sniff, sizeof(SettingsFld_Sniff)-1) == 0) {
+				what_to_do = 1;
 			} else if(*line_ptr == SettingsFld_Addr) {
 				char a = *(++line_ptr);
 				line_ptr += 3;
 				switch(a) {
 					case '0':
-						addrs.addr_len = ConvertHexToArray(line_ptr, addrs.addr_P0, 5);
+						addrs.addr_len = ConvertHexToArray(line_ptr, addrs.addr_P0, what_to_do == 1 ? 3 : 5);
 						//FURI_LOG_D(TAG, " +Addr(%d): %02X%02X%02X...", addrs.addr_len, addrs.addr_P0[0], addrs.addr_P0[1], addrs.addr_P0[2]);
 						if(addrs.addr_len >= 2) err = 0;
 						break;
 					case '1':
-						ConvertHexToArray(line_ptr, addrs.addr_P1, 5);
+						ConvertHexToArray(line_ptr, addrs.addr_P1, what_to_do == 1 ? 3 : 5);
 						//FURI_LOG_D(TAG, " +Addr: %02X%02X%02X...", addrs.addr_P0[1], addrs.addr_P1[1], addrs.addr_P1[2]);
 						break;
 					case '2':
@@ -389,64 +398,78 @@ static void input_callback(InputEvent* input_event, FuriMessageQueue* event_queu
 	furi_message_queue_put(event_queue, &event, FuriWaitForever);
 }
 
-static void prepare_nrf24()
+static void prepare_nrf24(bool fsend_packet)
 {
-	uint8_t addr[5];
 	uint8_t erx_addr = (1<<0); // Enable RX_P0
-	if(addrs.addr_count == 0) return;
-	nrf24_write_reg(nrf24_HANDLE, REG_CONFIG, 0x70 | ((NRF_CRC == 1 ? 0b1000 : NRF_CRC == 2 ? 0b1100 : 0))); // Mask all interrupts
-	nrf24_write_reg(nrf24_HANDLE, REG_SETUP_RETR, NRF_ESB ? 0x11 : 0); // Automatic Retransmission
-	nrf24_write_reg(nrf24_HANDLE, REG_EN_AA, NRF_AA_OFF || !NRF_ESB ? 0 : 0x3F); // Auto acknowledgement
-	nrf24_write_reg(nrf24_HANDLE, REG_FEATURE, NRF_DPL ? 4+1 : 1); // Enables the W_TX_PAYLOAD_NOACK command, Disable Payload with ACK, set Dynamic Payload
-	nrf24_set_maclen(nrf24_HANDLE, addrs.addr_len);
-	for(int i = 0; i < addrs.addr_len; i++) addr[i] = addrs.addr_P0[addrs.addr_len - i - 1];
-	nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P0, addr, addrs.addr_len);
-	uint8_t tmp[5];
-	nrf24_read_reg(nrf24_HANDLE, REG_RX_ADDR_P0, tmp, addrs.addr_len);
-	NRF_ERROR = memcmp(addr, tmp, addrs.addr_len) != 0;
-	uint8_t payload = NRF_Payload;
-	if(what_to_do == 1) {
-		payload += 5 + NRF_CRC; // + addr_max + CRC
-		if(NRF_ESB)	payload += 2;
-		if(payload > 32) payload = 32;
+	if(!fsend_packet) {
+		if(addrs.addr_count == 0) return;
+		uint8_t payload = NRF_Payload;
+		if(what_to_do == 1) { // SNIFF
+			payload += 5 + NRF_CRC; // + addr_max + CRC
+			if(NRF_ESB)	payload += 2;
+			if(payload > 32) payload = 32;
+			nrf24_write_reg(nrf24_HANDLE, REG_CONFIG, 0x70); // Mask all interrupts
+			nrf24_write_reg(nrf24_HANDLE, REG_STATUS, 0x70); // clear interrupts
+			nrf24_write_reg(nrf24_HANDLE, REG_RF_SETUP, NRF_rate);
+			nrf24_write_reg(nrf24_HANDLE, REG_SETUP_RETR, 0); // Automatic Retransmission
+			nrf24_write_reg(nrf24_HANDLE, REG_EN_AA, 0); // Auto acknowledgement
+			nrf24_write_reg(nrf24_HANDLE, REG_FEATURE, 0); // Enables the W_TX_PAYLOAD_NOACK command, Disable Payload with ACK, set Dynamic Payload
+		} else {
+			nrf24_write_reg(nrf24_HANDLE, REG_CONFIG, 0x70 | ((NRF_CRC == 1 ? 0b1000 : NRF_CRC == 2 ? 0b1100 : 0))); // Mask all interrupts
+			nrf24_write_reg(nrf24_HANDLE, REG_STATUS, 0x70); // clear interrupts
+			nrf24_write_reg(nrf24_HANDLE, REG_RF_SETUP, NRF_rate);
+			nrf24_write_reg(nrf24_HANDLE, REG_SETUP_RETR, NRF_ESB ? 0x11 : 0); // Automatic Retransmission
+			nrf24_write_reg(nrf24_HANDLE, REG_EN_AA, NRF_AA_OFF || !NRF_ESB ? 0 : 0x3F); // Auto acknowledgement
+			nrf24_write_reg(nrf24_HANDLE, REG_FEATURE, NRF_DPL ? 4+1 : 1); // Enables the W_TX_PAYLOAD_NOACK command, Disable Payload with ACK, set Dynamic Payload
+		}
+		nrf24_set_maclen(nrf24_HANDLE, addrs.addr_len);
+		nrf24_set_mac(REG_RX_ADDR_P0, addrs.addr_P0, addrs.addr_len);
+		uint8_t tmp[5] = { 0 };
+		nrf24_read_reg(nrf24_HANDLE, REG_RX_ADDR_P0, tmp, addrs.addr_len);
+		for(uint8_t i = 0; i < addrs.addr_len / 2; i++) {
+			uint8_t tb = tmp[i];
+			tmp[i] = tmp[addrs.addr_len - i - 1];
+			tmp[addrs.addr_len - i - 1] = tb;
+		}
+		NRF_ERROR = memcmp(addrs.addr_P0, tmp, addrs.addr_len) != 0;
+		uint8_t dyn = 0;
+		if(addrs.addr_count > 0 && NRF_DPL) dyn |= (1<<0);
+		FURI_LOG_D(TAG, "Payload: %d", payload);
+		nrf24_write_reg(nrf24_HANDLE, RX_PW_P0, payload);
+		if(addrs.addr_count > 1) {
+			nrf24_set_mac(REG_RX_ADDR_P1, addrs.addr_P1, addrs.addr_len);
+			nrf24_write_reg(nrf24_HANDLE, RX_PW_P1, payload);
+			if(NRF_DPL) dyn |= (1<<1);
+			erx_addr |= (1<<1); // Enable RX_P1
+		} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P1, 0);
+		if(addrs.addr_count > 2) {
+			nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P2, &addrs.addr_P2, 1);
+			nrf24_write_reg(nrf24_HANDLE, RX_PW_P2, payload);
+			if(NRF_DPL) dyn |= (1<<2);
+			erx_addr |= (1<<2); // Enable RX_P2
+		} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P2, 0);
+		if(addrs.addr_count > 3) {
+			nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P3, &addrs.addr_P3, 1);
+			nrf24_write_reg(nrf24_HANDLE, RX_PW_P3, payload);
+			if(NRF_DPL) dyn |= (1<<3);
+			erx_addr |= (1<<3); // Enable RX_P3
+		} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P3, 0);
+		if(addrs.addr_count > 4) {
+			nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P4, &addrs.addr_P4, 1);
+			nrf24_write_reg(nrf24_HANDLE, RX_PW_P4, payload);
+			if(NRF_DPL) dyn |= (1<<4);
+			erx_addr |= (1<<4); // Enable RX_P4
+		} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P4, 0);
+		if(addrs.addr_count > 5) {
+			nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P5, &addrs.addr_P5, 1);
+			nrf24_write_reg(nrf24_HANDLE, RX_PW_P5, payload);
+			if(NRF_DPL) dyn |= (1<<5);
+			erx_addr |= (1<<5); // Enable RX_P5
+		} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P5, 0);
+		nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, dyn); // Enable dynamic payload reg
+		nrf24_write_reg(nrf24_HANDLE, REG_EN_RXADDR, erx_addr);
+		nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, NRF_channel);
 	}
-	nrf24_write_reg(nrf24_HANDLE, RX_PW_P0, payload);
-	if(addrs.addr_count > 0) nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, NRF_DPL ? (1<<0) : 0); // Enable dynamic payload reg
-	if(addrs.addr_count > 1) {
-		for(int i = 0; i < addrs.addr_len; i++) addr[i] = addrs.addr_P1[addrs.addr_len - i - 1];
-		nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P1, addr, addrs.addr_len);
-		nrf24_write_reg(nrf24_HANDLE, RX_PW_P1, payload);
-		nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, NRF_DPL ? (1<<1) : 0);
-		erx_addr |= (1<<1); // Enable RX_P1
-	} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P1, 0);
-	if(addrs.addr_count > 2) {
-		nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P2, &addrs.addr_P2, 1);
-		nrf24_write_reg(nrf24_HANDLE, RX_PW_P2, payload);
-		nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, NRF_DPL ? (1<<2) : 0);
-		erx_addr |= (1<<2); // Enable RX_P2
-	} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P2, 0);
-	if(addrs.addr_count > 3) {
-		nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P3, &addrs.addr_P3, 1);
-		nrf24_write_reg(nrf24_HANDLE, RX_PW_P3, payload);
-		nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, NRF_DPL ? (1<<3) : 0);
-		erx_addr |= (1<<3); // Enable RX_P3
-	} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P3, 0);
-	if(addrs.addr_count > 4) {
-		nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P4, &addrs.addr_P4, 1);
-		nrf24_write_reg(nrf24_HANDLE, RX_PW_P4, payload);
-		nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, NRF_DPL ? (1<<4) : 0);
-		erx_addr |= (1<<4); // Enable RX_P4
-	} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P4, 0);
-	if(addrs.addr_count > 5) {
-		nrf24_write_buf_reg(nrf24_HANDLE, REG_RX_ADDR_P5, &addrs.addr_P5, 1);
-		nrf24_write_reg(nrf24_HANDLE, RX_PW_P5, payload);
-		nrf24_write_reg(nrf24_HANDLE, REG_DYNPD, NRF_DPL ? (1<<5) : 0);
-		erx_addr |= (1<<5); // Enable RX_P5
-	} else nrf24_write_reg(nrf24_HANDLE, RX_PW_P5, 0);
-	nrf24_write_reg(nrf24_HANDLE, REG_STATUS, 0x70); // clear interrupts
-	nrf24_write_reg(nrf24_HANDLE, REG_EN_RXADDR, erx_addr);
-	nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, NRF_channel);
-	nrf24_write_reg(nrf24_HANDLE, REG_RF_SETUP, NRF_rate);
 	nrf24_flush_rx(nrf24_HANDLE);
 	nrf24_flush_tx(nrf24_HANDLE);
 	nrf24_set_idle(nrf24_HANDLE);
@@ -454,25 +477,19 @@ static void prepare_nrf24()
 
 static void start_scanning() 
 {
-	if(what_to_do == 1) { // sniff
-		addrs.addr_P0[0] = 0;
-		addrs.addr_P0[1] = 0x55;
-		addrs.addr_P1[0] = 0;
-		addrs.addr_P1[1] = 0xAA;
-		addrs.addr_len = 2;
-		addrs.addr_count = 2;
+	FURI_LOG_D(TAG, "Start proc-%d: Ch=%d Rate=%d", what_to_do, NRF_channel, NRF_rate);
+	if(what_to_do == 1) {
+		NRF_Sniff_payload_max = 32 - 3 - (NRF_ESB ? 2 : 0) - NRF_CRC + (addrs.addr_len - 2);
+		if(NRF_Payload > NRF_Sniff_payload_max) NRF_Payload = NRF_Sniff_payload_max;
 		view_log_decode_CRC = NRF_CRC;
-		uint8_t pmax = 32 - 5 - (NRF_ESB ? 2 : 0) - NRF_CRC;
-		if(NRF_Payload > pmax) NRF_Payload = pmax;
 	}
-	prepare_nrf24();
+	prepare_nrf24(false);
 	if(NRF_ERROR) {
 		FURI_LOG_E(TAG, "NRF R/W ERROR!");
 		return;
 	}
 	nrf24_set_rx_mode(nrf24_HANDLE);
 	start_time = furi_get_tick();
-	FURI_LOG_D(TAG, "Start scan: Ch=%d Rate=%d", NRF_channel, NRF_rate);
 }
 
 // start bitnum = 7
@@ -513,19 +530,30 @@ bool check_packet(uint8_t *pkt, uint8_t size)
 	for(uint8_t addr_size = 3; addr_size <= 5; addr_size++) {
 		if(NRF_ESB){
 			uint8_t b = *(pkt + addr_size) >> 2;
-			if((b > 32 && b != 0x33)) continue;
+			if((b > NRF_Sniff_payload_max && b != 0x33)) continue;
+			if(furi_log_get_level() == FuriLogLevelDebug && addr_size == 3) {
+				char dbuf[70];
+				dbuf[0] = 0;
+				add_to_str_hex_bytes(dbuf, (char*)pkt, size);
+				FURI_LOG_D(TAG, "PKT%d: %s (%d)", *(pkt - 1), dbuf, size);
+			}
 			if(b != 0x33) { // DPL
 				uint16_t crc = view_log_decode_CRC == 2 ? 0xFFFF : 0xFF;
-				if(calc_crc(crc, pkt, 7, 9 + b * 8) == get_shifted_crc(pkt + b + 1)) {
-					*(pkt - 1) = ((b & 0x1F) << 3) + 0b000 + (addr_size - 2);
+				crc = calc_crc(crc, pkt, 7, 9 + b * 8);
+				FURI_LOG_D(TAG, "DCRC: %X - %X", crc, get_shifted_crc(pkt + b + 1));
+				if(crc == get_shifted_crc(pkt + b + 1)) {
+					*(pkt - 1) = ((b & 0x1F) << 3) + 0b100 + (addr_size - 2);
+					FURI_LOG_D(TAG, "VALID: pl: %d, addr: %d", b, addr_size);
 					return true;
 				}
 			} else {
 				for(uint8_t i = 0; i < size - view_log_decode_CRC; i++) {
 					uint16_t crc = view_log_decode_CRC == 2 ? 0xFFFF : 0xFF;
 					crc = calc_crc(crc, pkt, 7, 9 + i * 8);
+					FURI_LOG_D(TAG, "CRC: %X - %X", crc, get_shifted_crc(pkt + i + 1));
 					if(crc == get_shifted_crc(pkt + i + 1)) {
 						*(pkt - 1) = ((i & 0x1F) << 3) + 0b100 + (addr_size - 2);
+						FURI_LOG_D(TAG, "VALID: pl: %d, addr: %d", i, addr_size);
 						return true;
 					} 
 				}
@@ -549,16 +577,31 @@ bool nrf24_read_newpacket() {
 	bool found = false;
 	uint8_t packetsize;
 	uint8_t *ptr = APP->log_arr + log_arr_idx * LOG_REC_SIZE;
-	uint8_t status = nrf24_rxpacket(nrf24_HANDLE, ptr + 2, &packetsize, !NRF_DPL);
-	if(status & RX_DR) {
+	uint8_t st = nrf24_rxpacket(nrf24_HANDLE, ptr + 2 + (what_to_do == 1 ? addrs.addr_len - 2 : 0), &packetsize, !NRF_DPL);
+	if(st & RX_DR) {
+		st = (st >> 1) & 7; // pipe #
 		if(what_to_do == 1) {
 			*ptr++ = NRF_channel | 0x80;
-			if(!check_packet(ptr + 2, packetsize)) return false;
+			*ptr++ = st;	// pipe #
+			if(addrs.addr_len > 2) {
+				*ptr = st == 0 ? addrs.addr_P0[2] : st == 1 ? addrs.addr_P1[2] : st == 2 ? addrs.addr_P2 : st == 3 ? addrs.addr_P3 : st == 4 ? addrs.addr_P4 : addrs.addr_P5;
+			}
+			if(!check_packet(ptr, packetsize)) {
+				if(addrs.addr_len > 2) return false; // skip if mac MSB added to preamble
+				if(addrs.addr_count == 1 && addrs.addr_P0[1] == 0xAA) { // Shift packet right by one bit if preamble = 0xAA
+					for(uint8_t i = packetsize - 1; i > 0; i--) { 
+						ptr[i] = ptr[i - 1] << 7 | ptr[i] >> 1;
+					}
+					*ptr >>= 1;
+					//if((st == 0 && (addrs.addr_P0[1] & 1)) || (st == 1 && (addrs.addr_P1[1] & 1))) *ptr |= 0x80;
+					if(!check_packet(ptr, packetsize)) return false;
+				} else return false;
+			}
 		} else {
 			*ptr++ = NRF_channel;
-			*ptr = ((packetsize & 0x1F) << 3) | ((status >> 1) & 7); // payload size + pipe #
+			*ptr++ = ((packetsize & 0x1F) << 3) | st; // payload size + pipe #
 		}
-		if(packetsize < 32) memset(ptr + packetsize + 1, 0, 32 - packetsize);
+		if(packetsize < 32) memset(ptr + packetsize, 0, 32 - packetsize);
 		if(log_arr_idx < MAX_LOG_RECORDS - 1) {
 			log_arr_idx++;
 		} else {
@@ -569,7 +612,7 @@ bool nrf24_read_newpacket() {
 				memmove(APP->log_arr, APP->log_arr + LOG_REC_SIZE, log_arr_idx * LOG_REC_SIZE);
 			}
 		}
-		FURI_LOG_D(TAG, "Found packet #%d pipe %d", log_arr_idx, (status >> 1) & 7);
+		FURI_LOG_D(TAG, "Found packet #%d pipe %d", log_arr_idx, st);
 		notification_message(APP->notification, &sequence_blink_white_100);
 		found = true;
 	}
@@ -579,10 +622,43 @@ bool nrf24_read_newpacket() {
 bool nrf24_send_packet()
 {
 	if(log_arr_idx == 0) return false;
-	if(!what_to_do) prepare_nrf24();
-	//nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, NRF_channel);
-	// todo: Ch + ESB
-	last_packet_send_st = nrf24_txpacket(nrf24_HANDLE, APP->log_arr + view_log_arr_idx * LOG_REC_SIZE + 2, 32, false);
+	prepare_nrf24(!what_to_do);
+	uint8_t *ptr = APP->log_arr + view_log_arr_idx * LOG_REC_SIZE;
+	nrf24_write_reg(nrf24_HANDLE, REG_RF_CH, *ptr & 0x7F);
+	if(*ptr & 0x80) { // RAW packet
+		//uint8_t pktinfo = *(ptr + 1);
+		//nrf24_set_maclen(nrf24_HANDLE, (pktinfo & 0b11) + 2);
+		nrf24_set_maclen(nrf24_HANDLE, 2);
+		//if(pktinfo & 0b100) { // ESB
+			nrf24_write_reg(nrf24_HANDLE, REG_SETUP_RETR, 0); // No Automatic Retransmission
+			nrf24_write_reg(nrf24_HANDLE, REG_EN_AA, 0); // No Auto acknowledgement
+		//}
+		//uint8_t alen = (*(ptr + 2) & 0b11) + 2;
+		uint8_t adr[2] = { 0x55, 0x55 }; 	// NOT TESTED!
+		if(*(ptr + 2) & 0x80) adr[0] = adr[1] = 0xAA;
+		nrf24_set_mac(REG_RX_ADDR_P0, adr, 2);
+		nrf24_set_mac(REG_TX_ADDR, adr, 2);
+		last_packet_send_st = nrf24_txpacket(nrf24_HANDLE, ptr + 2, 32, false);
+	} else {
+		nrf24_write_reg(nrf24_HANDLE, REG_SETUP_RETR, NRF_ESB ? 0x11 : 0); // Automatic Retransmission
+		nrf24_write_reg(nrf24_HANDLE, REG_EN_AA, NRF_AA_OFF || !NRF_ESB ? 0 : 0x3F); // Auto acknowledgement
+		uint8_t *adr;
+		uint8_t a = *(ptr + 1) & 0b111;
+		if(a < 2) {
+			if(a == 0) adr = addrs.addr_P0; else adr = addrs.addr_P1;
+			nrf24_set_mac(REG_RX_ADDR_P0, adr, addrs.addr_len);
+			nrf24_set_mac(REG_TX_ADDR, adr, addrs.addr_len);
+		} else {
+			uint8_t buf[5];
+			memcpy(buf, addrs.addr_P1, addrs.addr_len - 1);
+			buf[addrs.addr_len - 1] = a == 2 ? addrs.addr_P2 : a == 3 ? addrs.addr_P3 : a == 4 ? addrs.addr_P4 : addrs.addr_P5;
+			nrf24_set_mac(REG_RX_ADDR_P0, buf, addrs.addr_len);
+			nrf24_set_mac(REG_TX_ADDR, buf, addrs.addr_len);
+		}
+		a = *(ptr + 1) >> 3;
+		if(a == 0) a = 32;
+		last_packet_send_st = nrf24_txpacket(nrf24_HANDLE, ptr + 2, a, false);
+	}
 	last_packet_send = view_log_arr_idx;
 	notification_message(APP->notification, last_packet_send_st ? &sequence_blink_blue_100 : &sequence_blink_red_100);
 	if(what_to_do) start_scanning();
@@ -596,7 +672,7 @@ static void render_callback(Canvas* const canvas, void* ctx) {
 	if(what_doing == 0) {
 		canvas_set_font(canvas, FontSecondary); // 8x10 font
 		if(save_settings) snprintf(screen_buf, sizeof(screen_buf), "Save: %s", SETTINGS_FILENAME);						// menu_selected = 0
-		else snprintf(screen_buf, sizeof(screen_buf), "Load: %s", what_to_do == 1 ? "SNIFF" : addr_file_name);
+		else snprintf(screen_buf, sizeof(screen_buf), "Load: %s", addr_file_name);
 		canvas_draw_str(canvas, 10, 10, screen_buf);
 		snprintf(screen_buf, sizeof(screen_buf), "Ch: %d", NRF_channel); 												// menu_selected = 1
 		canvas_draw_str(canvas, 10, 20, screen_buf);
@@ -617,9 +693,12 @@ static void render_callback(Canvas* const canvas, void* ctx) {
 		else if(NRF_CRC == 2) canvas_draw_str(canvas, 99, 40, "CRC2");
 		snprintf(screen_buf, sizeof(screen_buf), "Log: %s", log_to_file == 0 ? "No" : log_to_file == 1 ? "Yes" : log_to_file == 2 ? "Append" : "Clear");// menu_selected = 4
 		canvas_draw_str(canvas, 10, 50, screen_buf);
-		if(what_to_do) {
+		if(what_to_do) {																								// menu_selected = 5
 			if(NRF_ERROR) snprintf(screen_buf, sizeof(screen_buf), "nRF24L01+ R/W ERROR!");
-			else snprintf(screen_buf, sizeof(screen_buf), "Start scan (pipes: %d)", addrs.addr_count);					// menu_selected = 5
+			else {
+				if(what_to_do == 1) snprintf(screen_buf, sizeof(screen_buf), "Start sniff");							
+				else snprintf(screen_buf, sizeof(screen_buf), "Start scan (pipes: %d)", addrs.addr_count);
+			}
 		} else snprintf(screen_buf, sizeof(screen_buf), "View log (pipes: %d)", addrs.addr_count);
 		canvas_draw_str(canvas, 10, 60,  screen_buf);				
 		canvas_draw_str(canvas, 0, menu_selected * 10 + 10, ">");
@@ -641,35 +720,64 @@ static void render_callback(Canvas* const canvas, void* ctx) {
 			for(uint8_t i = 0; i < 8 && page + i < log_arr_idx; i++) {
 				screen_buf[0] = (view_log_arr_idx & 7) != i ? ' ' : last_packet_send != view_log_arr_idx ? '>' : last_packet_send_st ? '*' : '!';
 				screen_buf[1] = '\0';
-				char *ptr = (char*)APP->log_arr + (page + i) * LOG_REC_SIZE;
+				uint8_t *ptr = APP->log_arr + (page + i) * LOG_REC_SIZE;
 				uint8_t channel = *ptr++; 
-				uint8_t dpl = *ptr++;
-				uint8_t pipe = dpl & 7;
-				dpl >>= 3;
-				if(dpl == 0) dpl = 32;
-				int count = dpl - view_log_arr_x;
-				if(view_log_decode_PCF) count--;
-				uint8_t max_width = VIEW_LOG_WIDTH_B;
-				if(view_log_arr_x == 0) {
-					if(channel & 0x80) { // RAW packet
-						max_width -= 5;
-					} else {
+				uint8_t *crcptr = NULL;
+				uint8_t pre = 0;
+				int count = 0;
+				if(channel & 0x80) { // RAW packet: nn:>{.address..}-xxxxxxxx
+					uint8_t pktinfo = *ptr++;
+					bool _PCF = pktinfo & 0b100;
+					uint8_t count = (pktinfo >> 3);
+					uint8_t adrsize = (pktinfo & 0b11) + 2;
+					uint8_t plen = adrsize + count;
+					count -= view_log_arr_x;
+					uint8_t max_width = VIEW_LOG_WIDTH_B;
+					if(view_log_arr_x == 0) max_width -= 5; 
+					if(count > max_width) count = max_width;
+					if(count > 0) {
+						uint8_t *pcrc = ptr;
+						uint16_t crc;
+						crc = view_log_decode_CRC == 2 ? 0xFFFF : 0xFF;
+						crc = calc_crc(crc, pcrc, 7, (_PCF? 9 : 0) + plen * 8);
+						pcrc += plen;
+						if(_PCF) { //ESB
+							pcrc++;
+							if(crc == get_shifted_crc(pcrc)) crcptr = pcrc;
+						} else {
+							if((view_log_decode_CRC == 1 && crc == *pcrc) || (view_log_decode_CRC == 2 && crc == ((*pcrc<<8) | *(pcrc+1)))) {
+								crcptr = pcrc;
+							}
+						}
+						if(view_log_arr_x == 0) {
+							add_to_str_hex_bytes(screen_buf, (char*)ptr, adrsize);
+							for(int8_t j = 5 - adrsize; j > 0; j--) strcat(screen_buf, "  ");
+							strcat(screen_buf, "-");
+							pre += 5 * 2 + 1;
+						} else {
+							ptr += view_log_arr_x - 1;
+						}
+						ptr += adrsize;
+						if(_PCF) add_to_str_hex_bytes_shift_9b(screen_buf, (char*)ptr, count); else add_to_str_hex_bytes(screen_buf, (char*)ptr, count);
+					}
+				} else {
+					uint8_t dpl = *ptr++;
+					uint8_t pipe = dpl & 0b111;
+					dpl >>= 3;
+					if(dpl == 0) dpl = 32;
+					count = dpl - view_log_arr_x;
+					if(view_log_decode_PCF) count--;
+					uint8_t max_width = VIEW_LOG_WIDTH_B;
+					if(view_log_arr_x == 0) {
 						if(addrs.addr_count > 1) max_width--;
 						if(view_log_decode_PCF) max_width -= 2; 
 					}
-				}
-				if(count > max_width) count = max_width;
-				ptr += view_log_arr_x;
-				uint8_t *crcptr = NULL;
-				uint8_t pre = 0;
-				if(count > 0) {
-					if(channel & 0x80) { // RAW packet
-							
-					} else {
+					if(count > max_width) count = max_width;
+					if(count > 0) {
 						if(view_log_decode_CRC) {
 							static uint16_t prev_addr_CRC;
 							static int8_t prev_pipe = -1;
-							uint8_t *pcrc = APP->log_arr + (page + i) * LOG_REC_SIZE + 1;
+							uint8_t *pcrc = APP->log_arr + (page + i) * LOG_REC_SIZE + 2;
 							uint16_t crc;
 							if(prev_pipe == pipe) { crc = prev_addr_CRC;
 							} else {
@@ -705,13 +813,14 @@ static void render_callback(Canvas* const canvas, void* ctx) {
 							}
 						}
 					}
+					ptr += view_log_arr_x;
 					if(max_width < VIEW_LOG_WIDTH_B) {
 						pre += snprintf(screen_buf + 1, 10, "%X-", pipe);
 						if(view_log_decode_PCF) {
 							pre += snprintf(screen_buf + strlen(screen_buf), 10, "%02X%01X-", *ptr >> 2, ((*ptr & 3) << 1) | (*(ptr+1) >> 7));
 						}
 					}
-					if(view_log_decode_PCF) add_to_str_hex_bytes_shift_9b(screen_buf, ptr, count); else add_to_str_hex_bytes(screen_buf, ptr, count);
+					if(view_log_decode_PCF) add_to_str_hex_bytes_shift_9b(screen_buf, (char*)ptr, count); else add_to_str_hex_bytes(screen_buf, (char*)ptr, count);
 				}
 				uint16_t y = 14 + i * 7;
 				canvas_draw_str(canvas, 3 * 5, y, screen_buf);
@@ -769,8 +878,9 @@ static void render_callback(Canvas* const canvas, void* ctx) {
 			snprintf(screen_buf, sizeof(screen_buf), "%02X", addrs.addr_P5); 
 			canvas_draw_str(canvas, (4 + (addrs.addr_len - 1) * 2) * 5, 6 * 7, screen_buf);
 		}
-		if(log_arr_idx && view_log_arr_idx) {
-			snprintf(screen_buf, sizeof(screen_buf), "Current Ch: %d", *(APP->log_arr + view_log_arr_idx * LOG_REC_SIZE) & 0x7F); 
+		if(log_arr_idx) {
+			uint8_t *ptr = APP->log_arr + view_log_arr_idx * LOG_REC_SIZE;
+			snprintf(screen_buf, sizeof(screen_buf), "Current Ch: %d, size: %d", *ptr & 0x7F, *(ptr + 1) >> 3); 
 			canvas_draw_str(canvas, 0, 7 * 7, screen_buf);
 		}
 		screen_buf[0] = 'v';
@@ -817,12 +927,20 @@ int32_t nrf24scan_app(void* p) {
 	FuriString* path = furi_string_alloc();
 	furi_string_set(path, SCAN_APP_PATH_FOLDER);
 	furi_string_cat(path, "/");
-	furi_string_cat(path, SETTINGS_FILENAME);
+	furi_string_cat(path, SNIFF_FILENAME);
 	if(file_stream_open(file_stream, furi_string_get_cstr(path), FSAM_READ, FSOM_OPEN_EXISTING)) {
 		uint8_t err = load_settings_file(file_stream);
-		if(!err) strcpy(addr_file_name, SETTINGS_FILENAME); else snprintf(addr_file_name, sizeof(addr_file_name), "LOAD ERROR#%d", err);
+		if(!err) strncpy(addr_file_name, furi_string_get_cstr(path) + sizeof(SCAN_APP_PATH_FOLDER), sizeof(addr_file_name)); 
+		else snprintf(addr_file_name, sizeof(addr_file_name), "LOAD ERROR#%d", err);
 	} else {
 		strcpy(addr_file_name, "NONE");
+		if(what_to_do == 1) {
+			addrs.addr_P0[0] = 0;
+			addrs.addr_P0[1] = 0xAA;
+			addrs.addr_len = 2;
+			addrs.addr_count = 1;
+			view_log_decode_CRC = NRF_CRC = 2;
+		}
 	}
 	file_stream_close(file_stream);
 	stream_free(file_stream);
@@ -840,7 +958,7 @@ int32_t nrf24scan_app(void* p) {
 				//FURI_LOG_D(TAG, "Key: %d Type: %d Sec: %u", event.input.key, event.input.type, event.input.sequence);
 				switch(event.input.key) {
 				case InputKeyUp:
-					if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
+					if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
 						if(what_doing == 0) {
 							if(menu_selected > 0) menu_selected--; else menu_selected = menu_selected_max;
 						} else if(what_doing == 1) {
@@ -850,7 +968,7 @@ int32_t nrf24scan_app(void* p) {
 					}
 					break;
 				case InputKeyDown:
-					if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
+					if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
 						if(what_doing == 0) {
 							if(menu_selected < menu_selected_max) menu_selected++; else menu_selected = 0;
 						} else if(what_doing == 1) {
@@ -860,7 +978,7 @@ int32_t nrf24scan_app(void* p) {
 					}
 					break;
 				case InputKeyLeft:
-					if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
+					if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
 						if(what_doing == 0) {
 							switch(menu_selected) {
 								case Menu_enter_channel:
@@ -891,7 +1009,7 @@ int32_t nrf24scan_app(void* p) {
 					}
 					break;
 				case InputKeyRight:
-					if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
+					if(event.input.type == InputTypeShort || event.input.type == InputTypeRepeat) {
 						if(what_doing == 0) {
 							switch(menu_selected) {
 								case Menu_open_file:
@@ -923,7 +1041,7 @@ int32_t nrf24scan_app(void* p) {
 					}
 					break;
 				case InputKeyOk:
-					if(event.input.type == InputTypePress) {
+					if(event.input.type == InputTypeShort) {
 						if(what_doing == 0) {
 							switch(menu_selected) {
 								case Menu_open_file:
@@ -939,6 +1057,12 @@ int32_t nrf24scan_app(void* p) {
 										stream_free(file_stream);
 									}
 									break;
+								case Menu_enter_channel:
+									if(NRF_ESB) {
+										if(NRF_DPL) NRF_DPL = NRF_ESB = 0; else NRF_DPL = 1;
+									} else NRF_ESB = 1;
+									//if(NRF_ESB) view_log_decode_PCF = 0;
+									break;
 								case Menu_enter_rate:
 									NRF_rate++;
 									if(NRF_rate > 2) NRF_rate = 0;
@@ -948,8 +1072,9 @@ int32_t nrf24scan_app(void* p) {
 									break;
 								case Menu_ok:
 									if(what_to_do) {
-										if(addrs.addr_count) {
+										if(addrs.addr_count || what_to_do == 1) {
 											if(log_to_file == -1) {
+												log_to_file = 0;
 												clear_log();
 												save_to_new_log = true;
 											} else if(log_to_file == 1) save_to_new_log = true;
@@ -960,6 +1085,8 @@ int32_t nrf24scan_app(void* p) {
 									key_press_seq_ok = event.input.sequence; 
 									break;
 							}
+						} else if(what_doing == 1) {
+							nrf24_send_packet();
 						}
 					} else if(event.input.type == InputTypeLong) {
 						if(what_doing == 0) {
@@ -975,25 +1102,11 @@ int32_t nrf24scan_app(void* p) {
 						} else if(what_doing == 1) {
 							what_doing = 2;
 						}
-					} else if(event.input.type == InputTypeRelease) {
-						if(key_press_seq_ok != event.input.sequence) {
-							if(what_doing == 0) {
-								if(menu_selected == Menu_enter_channel) {
-									if(NRF_ESB) {
-										if(NRF_DPL) NRF_DPL = NRF_ESB = 0; else NRF_DPL = 1;
-									} else NRF_ESB = 1;
-									//if(NRF_ESB) view_log_decode_PCF = 0;
-								}
-							} else if(what_doing == 1) { // Send
-								nrf24_send_packet();
-							}
-						}
-						key_press_seq_ok--;
 					}
 					break;
 				case InputKeyBack:
 					if(event.input.type == InputTypeLong) processing = false; 
-					else if(event.input.type == InputTypeRelease) {
+					else if(event.input.type == InputTypeShort) {
 						if(what_doing) what_doing--;
 						if(what_doing == 0) nrf24_set_idle(nrf24_HANDLE);;
 					}

+ 6 - 0
sniff.txt

@@ -0,0 +1,6 @@
+SNIFF
+Rate: 1
+Ch: 2
+ESB: 1
+CRC: 2
+P0: 00AA