diff --git a/ReadMe.md b/ReadMe.md
index 068fe3559..085afa3be 100644
--- a/ReadMe.md
+++ b/ReadMe.md
@@ -32,8 +32,8 @@ Thank you to all the supporters!
- Renamed some FAPs to fix ordering in Applications, delete your `/ext/apps` folder to get rid of duplicates
- Removed: [VB Lab Migration Assistant (By GMMan)](https://github.com/GMMan/flipperzero-vb-migrate) `Req: Vital Bracelet` (due to fap error)
- Updated: [Dice (By Ka3u6y6a)](https://github.com/Ka3u6y6a/flipper-zero-dice)
-- Updated: [NRF24 Scanner (By vad7)](https://github.com/vad7/nrf24scan)
- Updated: [Wii EC Analyser (By csBlueChip)](https://github.com/csBlueChip/FlipperZero_WiiEC)
+- Updated: [NRF24 Scanner v1.5 (By vad7)](https://github.com/vad7/nrf24scan)
## Install from Release
FLASH STOCK FIRST BEFORE UPDATING TO CUSTOM FIRMWARE!
@@ -225,7 +225,7 @@ $ ./fbt resources icons dolphin_ext
- [Music Player (By DrZlo13)-OFW](https://github.com/flipperdevices/flipperzero-firmware/pull/1189)
- [NFC Magic (By gornekich)](https://github.com/flipperdevices/flipperzero-firmware/pull/1966)
- [NRF Sniff (By mothball187)](https://github.com/mothball187/flipperzero-nrf24/tree/main/nrfsniff) ([Pin Out](https://github.com/RogueMaster/flipperzero-firmware-wPlugins/tree/420/applications/nrfsniff) from nocomp/Frog/UberGuidoZ) `Req: NRF24`
-- [NRF24 Scanner (By vad7)](https://github.com/vad7/nrf24scan)
+- [NRF24 Scanner v1.5 (By vad7)](https://github.com/vad7/nrf24scan)
- [Ocarina (By invalidna-me)](https://github.com/invalidna-me/flipperzero-ocarina) [Here are the LOTZ Songs](https://www.zeldadungeon.net/wiki/Ocarina_of_Time_Songs)
- [Paint (By n-o-T-I-n-s-a-n-e)](https://github.com/n-o-T-I-n-s-a-n-e)
- [Password Generator (By anakod)](https://github.com/anakod/flipper_passgen)
diff --git a/applications/plugins/nrf24scan/README.md b/applications/plugins/nrf24scan/README.md
index d47c97a6f..6c4d91a4e 100644
--- a/applications/plugins/nrf24scan/README.md
+++ b/applications/plugins/nrf24scan/README.md
@@ -1,7 +1,10 @@
# NRF24 scanner with logging and resend ability for Flipper Zero
-An [NRF24](https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf) driver for the [Flipper Zero](https://flipperzero.one/) device. The NRF24 is a popular line of 2.4GHz radio transceivers from Nordic Semiconductors. This library is not currently complete, but functional.
-
+An [NRF24](https://www.sparkfun.com/datasheets/Components/SMD/nRF24L01Pluss_Preliminary_Product_Specification_v1_0.pdf) driver for the [Flipper Zero](https://flipperzero.one/) device. The NRF24 is a popular line of 2.4GHz radio transceivers from Nordic Semiconductors.
+NRF24L01+ Enhanced ShockBurst packet decoder example using Python: [nrf24_packet_decoder.py](https://raw.githubusercontent.com/vad7/nrf24scan/master/nrf24_packet_decoder.py)
+
+Flipper Zero FAP file: [Nrf24_Scanner.fap](https://raw.githubusercontent.com/vad7/nrf24scan/master/Nrf24_Scanner.fap)
+
Settings file (default addr.txt) format:
Rate: 0/1/2 - rate in Mbps (=0.25/1/2)
@@ -31,15 +34,16 @@ Long press OK - view addresses.
-Decode the Packet Control Field (long press OK in the list and then press '>').
+Decode the Packet Control Field and check CRC (long press OK in the list and then press '<' / '>').
ESB (Enhanced Shockburst) option must be turned off.
+Press '>' to decode CRC.
1 - pipe #
-2 - Payload length (for valide packet must be 1..20 hex, or 0x33 if not DPL)
+2 - Payload length (for valide packet must be 1..20 or 33 hex)
3 - PID (2 bit) + NO_ACK (1 bit)
diff --git a/applications/plugins/nrf24scan/Screenshot-1.png b/applications/plugins/nrf24scan/Screenshot-1.png
index 082e7d5af..61ca892d8 100644
Binary files a/applications/plugins/nrf24scan/Screenshot-1.png and b/applications/plugins/nrf24scan/Screenshot-1.png differ
diff --git a/applications/plugins/nrf24scan/Screenshot-4.png b/applications/plugins/nrf24scan/Screenshot-4.png
index 375f7b777..6351cdd3f 100644
Binary files a/applications/plugins/nrf24scan/Screenshot-4.png and b/applications/plugins/nrf24scan/Screenshot-4.png differ
diff --git a/applications/plugins/nrf24scan/Screenshot-5.png b/applications/plugins/nrf24scan/Screenshot-5.png
index 0b4a59dd1..d9e3173a2 100644
Binary files a/applications/plugins/nrf24scan/Screenshot-5.png and b/applications/plugins/nrf24scan/Screenshot-5.png differ
diff --git a/applications/plugins/nrf24scan/addr.txt b/applications/plugins/nrf24scan/addr.txt
deleted file mode 100644
index a79064baf..000000000
--- a/applications/plugins/nrf24scan/addr.txt
+++ /dev/null
@@ -1,5 +0,0 @@
-Rate: 1
-Ch: 120
-P0: C8C801
-P1: C8C802
-P2: 03
diff --git a/applications/plugins/nrf24scan/addr1.txt b/applications/plugins/nrf24scan/addr1.txt
deleted file mode 100644
index 5a10c4298..000000000
--- a/applications/plugins/nrf24scan/addr1.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-Rate: 1
-Ch: 120
-P0: C8C8E5
diff --git a/applications/plugins/nrf24scan/nrf24_packet_decoder.py b/applications/plugins/nrf24scan/nrf24_packet_decoder.py
new file mode 100644
index 000000000..9e1a42a18
--- /dev/null
+++ b/applications/plugins/nrf24scan/nrf24_packet_decoder.py
@@ -0,0 +1,99 @@
+#
+# NRF24L01+ Enhanced ShockBurst packets decoder
+#
+payload_len_default = 4
+packets = \
+(
+ '10101010 11101110 00000011 00001000 00001011 01000111 000100 10 0 10101010 10101010 10101010 10101010 00011101',
+ '10101010 11001000 11001000 11000011 110011 10 0 00001011 00000011 00000101 00000000 0010001100100000',
+)
+
+def bin2hex(x):
+ def bin2hex_helper(r):
+ while r:
+ yield r[0:2].upper()
+ r = r[2:]
+
+ fmt = "{0:0" + str(int(len(x) / 8 * 2)) + "X}"
+ hex_data = fmt.format(int(x, 2))
+ return list(bin2hex_helper(hex_data))
+
+
+def split_packet(packet, parts):
+ """Split a string of 1s and 0s into multiple substrings as specified by parts.
+ Example: "111000011000", (3, 4, 2) -> ["111", "0000", "11", "000"]
+ :param packet: String of 1s and 0s
+ :param parts: Tuple of length of substrings
+ :return: list of substrings
+ """
+ out = []
+ packet = packet.replace(' ', '')
+ for part_length in parts:
+ out.append(packet[0:part_length])
+ packet = packet[part_length:]
+ out.append(packet)
+ return out
+
+
+def parse_packet(packet, address_length):
+ """Split a packet into its fields and return them as tuple."""
+ preamble, address, payload_length, pid, no_ack, rest = split_packet(packet=packet,
+ parts=(8, 8 * address_length, 6, 2, 1))
+ payload, crc = split_packet(packet=rest, parts=((payload_len_default if int(payload_length, 2) > 32 else int(payload_length, 2)) * 8,))
+
+ assert preamble in ('10101010', '01010101')
+ assert len(crc) in (8, 16)
+
+ return preamble, address, payload_length, pid, no_ack, payload, crc
+
+
+def crc(bits, size=8):
+ """Calculate the crc value for the polynomial initialized with 0xFF/0xFFFF)
+ :param size: 8 or 16 bit crc
+ :param bits: String of 1s and 0s
+ :return:
+ :polynomial: 1 byte CRC - standard is 0x107 = 0b100000111 = x^8+x^2+x^1+1, result the same for 0x07
+ :polynomial: 2 byte CRC - standard is 0x11021 = X^16+X^12+X^5+1, result the same for 0x1021
+ """
+ if size == 8:
+ polynomial = 0x107
+ crc = 0xFF
+ else:
+ polynomial = 0x11021
+ crc = 0xFFFF
+ max_crc_value = (1 << size) - 1 # e.g. 0xFF for mode 8bit-crc
+ for bit in bits:
+ bit = int(bit, 2)
+ crc <<= 1
+ if (crc >> size) ^ bit: # top most lfsr bit xor current data bit
+ crc ^= polynomial
+ crc &= max_crc_value # trim the crc to reject carry over bits
+ return crc
+
+
+if __name__ == '__main__':
+ for packet in packets:
+ fld = packet.split(' ');
+ address_length = -1
+ for f in fld:
+ if len(f) == 6: break
+ address_length += 1
+ preamble, address, payload_length, pid, no_ack, payload, crc_received = \
+ parse_packet(packet=packet, address_length=address_length)
+ crc_size = len(crc_received)
+ crc_received = hex(int(crc_received, 2))
+ print(f"Packet: {packet}")
+ print('\n'.join((
+ f'Preamble: {preamble}',
+ f'Address: {address_length} bytes - {bin2hex(address)}',
+ f'Payload length in packet: {int(payload_length, 2)}, used: {(payload_len_default if int(payload_length, 2) > 32 else int(payload_length, 2))}',
+ f'Pid: {int(pid, 2)}',
+ f'No_ack: {int(no_ack, 2) == 1}',
+ f'Payload: {bin2hex(payload)}',
+ f'CRC{crc_size}: {crc_received}')))
+ crc_calculated = hex(crc(address + payload_length + pid + no_ack + payload, size=crc_size))
+ if crc_received == crc_calculated:
+ print('CRC is valid!')
+ else:
+ print(f'CRC mismatch! Calculated CRC is f{crc_calculated}.')
+ print('-------------')
diff --git a/applications/plugins/nrf24scan/nrf24scan.c b/applications/plugins/nrf24scan/nrf24scan.c
index 49aa7976d..9a62af271 100644
--- a/applications/plugins/nrf24scan/nrf24scan.c
+++ b/applications/plugins/nrf24scan/nrf24scan.c
@@ -11,9 +11,10 @@
#include
#include
#include
+#include
#define TAG "nrf24scan"
-#define VERSION "1.4"
+#define VERSION "1.5"
#define MAX_CHANNEL 125
#define MAX_ADDR 6
@@ -61,6 +62,7 @@ uint8_t NRF_ESB = 0; // 0 - ShockBurst, 1 - Enhanced ShockBurst
uint8_t NRF_DPL = 0; // 1 - Dynamic Payload Length
uint8_t NRF_CRC = 0; // 1 - No, 1 - CRC 1byte, 2 - CRC 2byte
uint8_t NRF_Payload = 32; // len in bytes, max 32
+uint8_t NRF_AA_OFF = 0; // Disable Auto Acknowledgement
bool NRF_ERROR = 0;
struct {
@@ -86,6 +88,7 @@ uint8_t menu_selected = 0;
uint32_t start_time;
uint8_t view_log_decode_PCF =
0; // view log: 1 - decode packet control field (9b) when ESB off. After pipe # (hex):
+uint8_t view_log_decode_CRC = 0; // CRC bytes - 1/2, 0 - none
#define menu_selected_max 5
enum {
@@ -138,7 +141,7 @@ static void add_to_str_hex_bytes_shift_9b(char* out, char* arr, int bytes) {
out += strlen(out);
arr++; // +8b
do {
- snprintf(out, 4, "%02X", (((*arr) & 0x7F) << 1) | (*(arr + 1) >> 7));
+ snprintf(out, 4, "%02X", ((uint8_t)(*arr << 1)) | (*(arr + 1) >> 7));
arr++;
out += 2;
} while(--bytes);
@@ -325,7 +328,7 @@ static uint8_t load_settings_file(Stream* file_stream) {
FURI_LOG_D(TAG, "load failed. file_size: %d", file_size);
return 1;
}
- file_size = MIN(file_size, LOG_REC_SIZE * MAX_LOG_RECORDS * 2 + 100);
+ file_size = MIN(file_size, (size_t)LOG_REC_SIZE * MAX_LOG_RECORDS * 2 + 100);
file_buf = malloc(file_size + 1);
if(file_buf == NULL) {
FURI_LOG_D(TAG, "Memory low, need: %d", file_size);
@@ -338,7 +341,7 @@ static uint8_t load_settings_file(Stream* file_stream) {
int16_t line_num = 0;
memset((uint8_t*)&addrs, 0, sizeof(addrs));
bool log_loaded = false;
- while(line_ptr && line_ptr - file_buf < file_size) {
+ while(line_ptr && (size_t)(line_ptr - file_buf) < file_size) {
char* end_ptr = strstr((char*)line_ptr, "\n");
if(end_ptr == NULL)
end_ptr = file_buf + file_size;
@@ -353,7 +356,7 @@ static uint8_t load_settings_file(Stream* file_stream) {
*(end_ptr - 1) = '\0';
line_len--;
}
- FURI_LOG_D(TAG, " L#%d: [%d]%s", line_num, line_len, line_ptr);
+ //FURI_LOG_D(TAG, " L#%d: [%d]%s", line_num, line_len, line_ptr);
if(strncmp(line_ptr, SettingsFld_Rate, sizeof(SettingsFld_Rate) - 1) == 0) {
NRF_rate = atoi(line_ptr + sizeof(SettingsFld_Rate));
} else if(strncmp(line_ptr, SettingsFld_Ch, sizeof(SettingsFld_Ch) - 1) == 0) {
@@ -373,23 +376,12 @@ static uint8_t load_settings_file(Stream* file_stream) {
switch(a) {
case '0':
addrs.addr_len = ConvertHexToArray(line_ptr, addrs.addr_P0, 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]);
+ //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);
- FURI_LOG_D(
- TAG,
- " +Addr: %02X%02X%02X...",
- addrs.addr_P0[1],
- addrs.addr_P1[1],
- addrs.addr_P1[2]);
+ //FURI_LOG_D(TAG, " +Addr: %02X%02X%02X...", addrs.addr_P0[1], addrs.addr_P1[1], addrs.addr_P1[2]);
break;
case '2':
ConvertHexToArray(line_ptr, &addrs.addr_P2, 1);
@@ -416,7 +408,9 @@ static uint8_t load_settings_file(Stream* file_stream) {
}
if(log_arr_idx < MAX_LOG_RECORDS - 1) {
ConvertHexToArray(
- line_ptr, APP->log_arr + log_arr_idx * LOG_REC_SIZE, MIN(NRF_Payload, 32));
+ line_ptr,
+ APP->log_arr + log_arr_idx * LOG_REC_SIZE,
+ MIN(NRF_Payload + 1, LOG_REC_SIZE));
log_arr_idx++;
}
}
@@ -447,14 +441,15 @@ static void prepare_nrf24() {
0x70 | ((NRF_CRC == 1 ? 0b1000 :
NRF_CRC == 2 ? 0b1100 :
0))); // Mask all interrupts
- nrf24_write_reg(nrf24_HANDLE, REG_SETUP_RETR, NRF_ESB ? 1 : 0); // Automatic Retransmission
- nrf24_write_reg(nrf24_HANDLE, REG_EN_AA, 0); // Disable auto acknowledgement
+ 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,
- 1 + (NRF_DPL ?
- 4 :
- 1)); // Enables the W_TX_PAYLOAD_NOACK command, Disable Payload with ACK, set Dynamic Payload
+ 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);
@@ -525,7 +520,6 @@ bool nrf24_read_newpacket() {
if(APP->log_arr == NULL) return false;
bool found = false;
uint8_t packetsize;
- uint8_t packet[32] = {0};
uint8_t* ptr = APP->log_arr + log_arr_idx * LOG_REC_SIZE;
uint8_t status = nrf24_rxpacket(nrf24_HANDLE, ptr + 1, &packetsize, !NRF_DPL);
if(status & RX_DR) {
@@ -561,6 +555,37 @@ bool nrf24_send_packet() {
return last_packet_send_st;
}
+uint16_t calc_crc(uint32_t crc, uint8_t* ptr, uint8_t bitnum, uint16_t bits) {
+ //uint8_t bitnum = 7;
+ uint32_t crc_high, polynom;
+ if(view_log_decode_CRC == 2) {
+ crc_high = (1 << 16);
+ polynom = 0x11021; // X^16+X^12+X^5+1
+ } else {
+ crc_high = (1 << 8);
+ polynom = 0x107; // x^8+x^2+x^1+1
+ }
+ while(bits--) {
+ crc <<= 1;
+ if(((crc & crc_high) != 0) ^ ((*ptr >> bitnum) & 1)) crc ^= polynom;
+ if(bitnum == 0) {
+ ptr++;
+ bitnum = 7;
+ } else
+ bitnum--;
+ }
+ return crc & (view_log_decode_CRC == 2 ? 0xFFFF : 0xFF);
+}
+
+// shifted 1 bit right
+uint16_t get_shifted_crc(uint8_t* pcrc) {
+ uint16_t crc = ((uint8_t)(*pcrc << 1)) | (*(pcrc + 1) >> 7);
+ if(view_log_decode_CRC == 2) {
+ crc = (crc << 8) | (((uint8_t)(*(pcrc + 1) << 1))) | (*(pcrc + 2) >> 7);
+ }
+ return crc;
+}
+
static void render_callback(Canvas* const canvas, void* ctx) {
const PluginState* plugin_state = acquire_mutex((ValueMutex*)ctx, 25);
if(plugin_state == NULL) return;
@@ -580,6 +605,10 @@ static void render_callback(Canvas* const canvas, void* ctx) {
if(NRF_DPL) strcat(screen_buf, " DPL");
canvas_draw_str(canvas, 80, 20, screen_buf);
}
+ if(NRF_AA_OFF) {
+ canvas_draw_str(canvas, 61, 20, "AA");
+ canvas_draw_line(canvas, 60, 21, 72, 12);
+ }
snprintf(
screen_buf,
sizeof(screen_buf),
@@ -588,21 +617,19 @@ static void render_callback(Canvas* const canvas, void* ctx) {
NRF_rate == 1 ? "1M" :
"250K"); // menu_selected = 2
canvas_draw_str(canvas, 10, 30, screen_buf);
- canvas_set_font(canvas, FontBatteryPercent);
- snprintf(screen_buf, sizeof(screen_buf), "R:%d", NRF_Payload);
+ snprintf(screen_buf, sizeof(screen_buf), "Payload: %d", NRF_Payload);
canvas_draw_str(canvas, 80, 30, screen_buf);
- if(NRF_CRC == 1)
- canvas_draw_str(canvas, 105, 30, "CRC1");
- else if(NRF_CRC == 2)
- canvas_draw_str(canvas, 105, 30, "CRC2");
- canvas_set_font(canvas, FontSecondary);
- strcpy(screen_buf, "Find channel period: "); // menu_selected = 3
+ strcpy(screen_buf, "Next Ch time: "); // menu_selected = 3
if(find_channel_period == 0)
strcat(screen_buf, "off");
else
snprintf(
screen_buf + strlen(screen_buf), sizeof(screen_buf), "%d s", find_channel_period);
canvas_draw_str(canvas, 10, 40, screen_buf);
+ if(NRF_CRC == 1)
+ canvas_draw_str(canvas, 99, 40, "CRC1");
+ else if(NRF_CRC == 2)
+ canvas_draw_str(canvas, 99, 40, "CRC2");
snprintf(
screen_buf,
sizeof(screen_buf),
@@ -649,8 +676,6 @@ static void render_callback(Canvas* const canvas, void* ctx) {
if(view_log_arr_idx >= log_arr_idx) view_log_arr_idx = log_arr_idx - 1;
uint16_t page = view_log_arr_idx & ~7;
for(uint8_t i = 0; i < 8 && page + i < log_arr_idx; i++) {
- snprintf(screen_buf, sizeof(screen_buf), "%d:", page + i + 1);
- canvas_draw_str(canvas, 0, 14 + i * 7, screen_buf);
screen_buf[0] = (view_log_arr_idx & 7) != i ? ' ' :
last_packet_send != view_log_arr_idx ? '>' :
last_packet_send_st ? '*' :
@@ -661,31 +686,110 @@ static void render_callback(Canvas* const canvas, void* ctx) {
uint8_t pipe = dpl & 7;
dpl >>= 3;
if(dpl == 0) dpl = 32;
- if(view_log_decode_PCF && dpl == 32) dpl -= 2;
int count = dpl - view_log_arr_x;
- uint8_t max_width = view_log_arr_x == 0 && addrs.addr_count > 1 ?
- view_log_decode_PCF ? VIEW_LOG_WIDTH_B - 3 :
- VIEW_LOG_WIDTH_B - 1 :
- VIEW_LOG_WIDTH_B;
+ 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(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;
+ uint16_t crc;
+ if(prev_pipe == pipe) {
+ crc = prev_addr_CRC;
+ } else {
+ crc = view_log_decode_CRC == 2 ? 0xFFFF : 0xFF;
+ if(pipe <= 1) {
+ crc = calc_crc(
+ crc,
+ pipe == 0 ? addrs.addr_P0 : addrs.addr_P1,
+ 7,
+ addrs.addr_len * 8);
+ } else {
+ crc = calc_crc(crc, addrs.addr_P1, 7, (addrs.addr_len - 1) * 8);
+ crc = calc_crc(
+ crc,
+ pipe == 2 ? &addrs.addr_P2 :
+ pipe == 3 ? &addrs.addr_P3 :
+ pipe == 4 ? &addrs.addr_P4 :
+ &addrs.addr_P5,
+ 7,
+ 8);
+ }
+ prev_addr_CRC = crc;
+ prev_pipe = pipe;
+ }
+ if(view_log_decode_PCF) {
+ crc = calc_crc(crc, pcrc++, 7, 9);
+ if(crc == get_shifted_crc(pcrc)) crcptr = pcrc;
+ if(crcptr == NULL) {
+ for(int8_t j = 0; j < (int8_t)dpl - view_log_decode_CRC - 1; j++) {
+ crc = calc_crc(crc, pcrc++, 6, 8);
+ if(crc == get_shifted_crc(pcrc)) {
+ crcptr = pcrc;
+ break;
+ }
+ }
+ }
+ } else {
+ for(int8_t j = 0; j < (int8_t)dpl - view_log_decode_CRC; j++) {
+ crc = calc_crc(crc, pcrc++, 7, 8);
+ if((view_log_decode_CRC == 1 && crc == *pcrc) ||
+ (view_log_decode_CRC == 2 &&
+ crc == ((*pcrc << 8) | *(pcrc + 1)))) {
+ crcptr = pcrc;
+ break;
+ }
+ }
+ }
+ }
if(max_width < VIEW_LOG_WIDTH_B) {
- snprintf(screen_buf + 1, 10, "%X-", pipe);
- if(view_log_decode_PCF)
- snprintf(
+ 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);
}
- canvas_draw_str(canvas, 3 * 5, 14 + i * 7, screen_buf);
+ uint16_t y = 14 + i * 7;
+ canvas_draw_str(canvas, 3 * 5, y, screen_buf);
+ uint16_t x = snprintf(screen_buf, sizeof(screen_buf), "%d", page + i + 1);
+ canvas_draw_str(canvas, 0, y, screen_buf);
+ if(crcptr) { // 5x7 font, 9 lines
+ canvas_draw_str(canvas, x * 5, y, "=");
+ int n = crcptr - (uint8_t*)ptr - 1;
+ if(n > -view_log_decode_CRC && n < count) {
+ int len;
+ x = (4 + pre) * 5;
+ if(n < 0) {
+ len = view_log_decode_CRC + n;
+ n = 0;
+ } else {
+ len = MIN(view_log_decode_CRC, count - n);
+ x += n * 2 * 5;
+ canvas_draw_line(canvas, x - 1, y, x - 1, y - 1);
+ }
+ canvas_draw_line(canvas, x - 1, y, n = x + len * 2 * 5 - 1, y);
+ canvas_draw_line(canvas, n, y, n, y - 1);
+ }
+ } else
+ canvas_draw_str(canvas, x * 5, y, ":");
}
}
} else {
@@ -723,7 +827,15 @@ static void render_callback(Canvas* const canvas, void* ctx) {
screen_buf[0] = 'v';
strcpy(screen_buf + 1, VERSION);
canvas_draw_str(canvas, 108, 7, screen_buf);
- if(view_log_decode_PCF) canvas_draw_str(canvas, 78, 64, "Decode PCF");
+ if(view_log_decode_PCF || view_log_decode_CRC) {
+ strcpy(screen_buf, "Decode: ");
+ if(view_log_decode_PCF) strcat(screen_buf, "PCF ");
+ if(view_log_decode_CRC == 1)
+ strcat(screen_buf, "CRC1");
+ else if(view_log_decode_CRC == 2)
+ strcat(screen_buf, "CRC2");
+ canvas_draw_str(canvas, 0, 64, screen_buf);
+ }
}
release_mutex((ValueMutex*)ctx, plugin_state);
}
@@ -809,39 +921,6 @@ int32_t nrf24scan_app(void* p) {
}
}
break;
- case InputKeyRight:
- if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
- if(what_doing == 0) {
- switch(menu_selected) {
- case Menu_open_file:
- save_settings ^= 1;
- break;
- case Menu_enter_channel:
- NRF_channel += event.input.type == InputTypeRepeat ? 10 : 1;
- if(NRF_channel > MAX_CHANNEL) NRF_channel = 0;
- break;
- case Menu_enter_rate:
- NRF_rate++;
- if(NRF_rate > 2) NRF_rate = 0;
- break;
- case Menu_enter_scan_period:
- find_channel_period += event.input.type == InputTypeRepeat ? 10 :
- 1;
- break;
- case Menu_log:
- if(++log_to_file > 2) log_to_file = -1;
- break;
- case Menu_ok:
- what_to_do = !what_to_do;
- break;
- }
- } else if(what_doing == 1) {
- if(view_log_arr_x < VIEW_LOG_MAX_X) view_log_arr_x++;
- } else if(what_doing == 2) {
- if(NRF_ESB == 0) view_log_decode_PCF ^= 1;
- }
- }
- break;
case InputKeyLeft:
if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
if(what_doing == 0) {
@@ -852,7 +931,7 @@ int32_t nrf24scan_app(void* p) {
break;
case Menu_enter_rate:
NRF_Payload -= event.input.type == InputTypeRepeat ? 10 : 1;
- if(NRF_Payload == 0 || NRF_Payload > 32) NRF_Payload = 32;
+ if(NRF_Payload == 0 || NRF_Payload > 32) NRF_Payload = 1;
break;
case Menu_enter_scan_period:
find_channel_period -= event.input.type == InputTypeRepeat ? 10 :
@@ -868,6 +947,42 @@ int32_t nrf24scan_app(void* p) {
}
} else if(what_doing == 1) {
if(view_log_arr_x > 0) view_log_arr_x--;
+ } else if(what_doing == 2) {
+ //if(NRF_ESB == 0)
+ view_log_decode_PCF ^= 1;
+ }
+ }
+ break;
+ case InputKeyRight:
+ if(event.input.type == InputTypePress || event.input.type == InputTypeRepeat) {
+ if(what_doing == 0) {
+ switch(menu_selected) {
+ case Menu_open_file:
+ save_settings ^= 1;
+ break;
+ case Menu_enter_channel:
+ NRF_channel += event.input.type == InputTypeRepeat ? 10 : 1;
+ if(NRF_channel > MAX_CHANNEL) NRF_channel = 0;
+ break;
+ case Menu_enter_rate:
+ NRF_Payload += event.input.type == InputTypeRepeat ? 10 : 1;
+ if(NRF_Payload == 0 || NRF_Payload > 32) NRF_Payload = 32;
+ break;
+ case Menu_enter_scan_period:
+ find_channel_period += event.input.type == InputTypeRepeat ? 10 :
+ 1;
+ break;
+ case Menu_log:
+ if(++log_to_file > 2) log_to_file = -1;
+ break;
+ case Menu_ok:
+ what_to_do = !what_to_do;
+ break;
+ }
+ } else if(what_doing == 1) {
+ if(view_log_arr_x < VIEW_LOG_MAX_X) view_log_arr_x++;
+ } else if(what_doing == 2) {
+ if(++view_log_decode_CRC > 2) view_log_decode_CRC = 0;
}
}
break;
@@ -895,29 +1010,23 @@ 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;
+ break;
+ case Menu_enter_scan_period:
if(++NRF_CRC > 2) NRF_CRC = 0;
break;
case Menu_ok:
if(what_to_do) {
if(addrs.addr_count) {
- what_doing = 1;
if(log_to_file == -1) {
clear_log();
save_to_new_log = true;
} else if(log_to_file == 1)
save_to_new_log = true;
start_scanning();
+ if(!NRF_ERROR) what_doing = 1;
}
} else
what_doing = 1;
@@ -927,19 +1036,34 @@ int32_t nrf24scan_app(void* p) {
}
} else if(event.input.type == InputTypeLong) {
if(what_doing == 0) {
- if(menu_selected == Menu_log) { // Log
+ if(menu_selected == Menu_enter_channel) {
+ NRF_AA_OFF ^= 1;
+ key_press_seq_ok = event.input.sequence;
+ } else if(menu_selected == Menu_log) { // Log
if(log_arr_idx && (log_to_file == 1 || log_to_file == 2)) {
write_to_log_file(APP->storage, false);
clear_log();
}
}
- nrf24_set_idle(nrf24_HANDLE);
} else if(what_doing == 1) {
what_doing = 2;
}
} else if(event.input.type == InputTypeRelease) {
- if(what_doing == 1 && key_press_seq_ok != event.input.sequence) { // Send
- nrf24_send_packet();
+ 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--;
}
diff --git a/assets/resources/dolphin/Kuronons_RMCFW_128x64/meta.txt b/assets/resources/dolphin/Kuronons_RMCFW_128x64/meta.txt
index aa9584f03..3154d0aef 100644
--- a/assets/resources/dolphin/Kuronons_RMCFW_128x64/meta.txt
+++ b/assets/resources/dolphin/Kuronons_RMCFW_128x64/meta.txt
@@ -3,12 +3,12 @@ Version: 1
Width: 128
Height: 64
-Passive frames: 10
-Active frames: 42
-Frames order: 11 11 12 13 14 15 14 13 12 11 0 1 1 1 2 2 3 4 4 5 6 7 7 8 8 9 10 10 10 11 11 11 11 11 11 12 12 13 13 14 14 15 15 15 15 15 16 16 17 18 18 18
-Active cycles: 1
+Passive frames: 54
+Active frames: 0
+Frames order: 0 0 0 0 1 1 1 2 2 3 4 4 5 6 7 7 8 8 9 10 10 10 11 11 11 11 11 11 12 12 13 13 14 14 15 15 15 15 15 16 16 17 18 18 18 18 18 18 18 18 18 18 18 18
+Active cycles: 0
Frame rate: 6
Duration: 3600
-Active cooldown: 4
+Active cooldown: 0
Bubble slots: 0
diff --git a/assets/resources/dolphin/L1_New_year_128x64/frame_0.bm b/assets/resources/dolphin/L1_New_year_128x64/frame_0.bm
new file mode 100644
index 000000000..17f53095e
Binary files /dev/null and b/assets/resources/dolphin/L1_New_year_128x64/frame_0.bm differ
diff --git a/assets/resources/dolphin/L1_New_year_128x64/frame_1.bm b/assets/resources/dolphin/L1_New_year_128x64/frame_1.bm
new file mode 100644
index 000000000..a8c1277fe
Binary files /dev/null and b/assets/resources/dolphin/L1_New_year_128x64/frame_1.bm differ
diff --git a/assets/resources/dolphin/L1_New_year_128x64/frame_2.bm b/assets/resources/dolphin/L1_New_year_128x64/frame_2.bm
new file mode 100644
index 000000000..ca1fa852a
Binary files /dev/null and b/assets/resources/dolphin/L1_New_year_128x64/frame_2.bm differ
diff --git a/assets/resources/dolphin/L1_New_year_128x64/frame_3.bm b/assets/resources/dolphin/L1_New_year_128x64/frame_3.bm
new file mode 100644
index 000000000..4b89c67a6
Binary files /dev/null and b/assets/resources/dolphin/L1_New_year_128x64/frame_3.bm differ
diff --git a/assets/resources/dolphin/L1_New_year_128x64/meta.txt b/assets/resources/dolphin/L1_New_year_128x64/meta.txt
new file mode 100644
index 000000000..542392c19
--- /dev/null
+++ b/assets/resources/dolphin/L1_New_year_128x64/meta.txt
@@ -0,0 +1,14 @@
+Filetype: Flipper Animation
+Version: 1
+
+Width: 128
+Height: 64
+Passive frames: 4
+Active frames: 0
+Frames order: 0 1 2 3
+Active cycles: 0
+Frame rate: 2
+Duration: 3600
+Active cooldown: 0
+
+Bubble slots: 0
diff --git a/assets/resources/dolphin/Sasquach_Blaster_128x64/meta.txt b/assets/resources/dolphin/Sasquach_Blaster_128x64/meta.txt
index 63d6e4750..4d5cb4433 100644
--- a/assets/resources/dolphin/Sasquach_Blaster_128x64/meta.txt
+++ b/assets/resources/dolphin/Sasquach_Blaster_128x64/meta.txt
@@ -3,12 +3,12 @@ Version: 1
Width: 128
Height: 64
-Passive frames: 10
-Active frames: 40
+Passive frames: 50
+Active frames: 0
Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49
-Active cycles: 1
+Active cycles: 0
Frame rate: 6
Duration: 3600
-Active cooldown: 4
+Active cooldown: 0
Bubble slots: 0
diff --git a/assets/resources/dolphin/Sasquach_CloudG0ku_128x64/meta.txt b/assets/resources/dolphin/Sasquach_CloudG0ku_128x64/meta.txt
index e780d7e95..cb006d0e0 100644
--- a/assets/resources/dolphin/Sasquach_CloudG0ku_128x64/meta.txt
+++ b/assets/resources/dolphin/Sasquach_CloudG0ku_128x64/meta.txt
@@ -3,12 +3,12 @@ Version: 1
Width: 128
Height: 64
-Passive frames: 10
-Active frames: 38
-Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 46
-Active cycles: 1
+Passive frames: 47
+Active frames: 0
+Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46
+Active cycles: 0
Frame rate: 5
Duration: 3600
-Active cooldown: 1
+Active cooldown: 0
Bubble slots: 0
diff --git a/assets/resources/dolphin/Sasquach_Narut0_128x64/meta.txt b/assets/resources/dolphin/Sasquach_Narut0_128x64/meta.txt
index 1c4b1c117..7e7e55b26 100644
--- a/assets/resources/dolphin/Sasquach_Narut0_128x64/meta.txt
+++ b/assets/resources/dolphin/Sasquach_Narut0_128x64/meta.txt
@@ -3,12 +3,12 @@ Version: 1
Width: 128
Height: 64
-Passive frames: 10
-Active frames: 20
+Passive frames: 30
+Active frames: 0
Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
-Active cycles: 1
+Active cycles: 0
Frame rate: 6
Duration: 3600
-Active cooldown: 4
+Active cooldown: 0
Bubble slots: 0
diff --git a/assets/resources/dolphin/Sasquach_RMCF_128x64/meta.txt b/assets/resources/dolphin/Sasquach_RMCF_128x64/meta.txt
index ffc01409d..b6b3fdf3e 100644
--- a/assets/resources/dolphin/Sasquach_RMCF_128x64/meta.txt
+++ b/assets/resources/dolphin/Sasquach_RMCF_128x64/meta.txt
@@ -3,13 +3,13 @@ Version: 1
Width: 128
Height: 64
-Passive frames: 9
-Active frames: 99
-Frames order: 0 1 2 3 4 3 2 1 0 1 2 3 4 5 6 7 8 9 10 11 11 11 11 11 11 11 11 11 11 11 11 12 12 12 12 12 12 12 13 14 15 16 17 18 17 18 17 18 19 20 19 20 19 20 19 20 19 20 21 22 21 22 22 22 23 24 25 26 27 28 29 30 31 32 33 0 34 35 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 37 38
-Active cycles: 1
+Passive frames: 100
+Active frames: 0
+Frames order: 0 1 2 3 4 5 6 7 8 9 10 11 11 11 11 11 11 11 11 11 11 11 11 12 12 12 12 12 12 12 13 14 15 16 17 18 17 18 17 18 19 20 19 20 19 20 19 20 19 20 21 22 21 22 22 22 23 24 25 26 27 28 29 30 31 32 33 0 34 35 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 36 37 38
+Active cycles: 0
Frame rate: 4
Duration: 3600
-Active cooldown: 4
+Active cooldown: 0
Bubble slots: 1