Flipper Zero

This commit is contained in:
Armin 2024-01-19 20:39:19 +01:00
parent 36403d810b
commit ea28282d1c
6 changed files with 79 additions and 40 deletions

View File

@ -404,6 +404,16 @@ If `IR_SEND_PIN` is specified (as constant), it reduces program size and improve
### List of public IR code databases
http://www.harctoolbox.org/IR-resources.html
### Flipper Zero
[Flipper IRDB Database](https://github.com/Lucaslhm/Flipper-IRDB)
| [Flipper decoding](https://github.com/flipperdevices/flipperzero-firmware/tree/release/lib/infrared/encoder_decoder) | [IRremote decoding](https://github.com/Arduino-IRremote/Arduino-IRremote/tree/master/src) |
|-|-|
| Samsung32 | Samsung |
| NEC | NEC |
| NECext | ONKYO |
| [\<start bit>\<VendorID:16>\<VendorID parity:4>\<Genre1:4>\<Genre2:4>\<Command:10>\<ID:2>\<Parity:8>\<stop bit>](https://github.com/flipperdevices/flipperzero-firmware/blob/027ea9ea36da137144548295c016d99255af53c3/lib/infrared/encoder_decoder/kaseikyo/infrared_decoder_kaseikyo.c#L26)<br/>and ID is MSB of address.<br/>address: 8A 02 20 00<br/>command: 56 03 00 00<br/>-> **IRremote:**<br/>Address 0x6A8, sendPanasonic (for 02 20) and Command 0x35 | \<start bit>\<VendorID:16>\<VendorID parity:4>\<Address:12>\<Command:8>\<Parity of VendorID parity, Address and Command:8>\<stop bit> |
<br/>
@ -763,15 +773,18 @@ If you can provide **examples of using a periodic timer for interrupts** for the
<br/>
# Timer and pin usage
The **receiver sample interval of 50 &micro;s is generated by a timer**. On many boards this must be a hardware timer. On some boards where a software timer is available, the software timer is used.<br/>
Every pin can be used for receiving.
The **receiver sample interval of 50 &micro;s is generated by a timer**. On many boards this must be a hardware timer. On some boards where a software timer is available, the software timer is used.
Every pin can be used for receiving.<br/>
If software PWM is selected, which is default, every pin can also be used for sending. Sending with software PWM does not require a timer!
The TinyReceiver example uses the **TinyReceiver** library, which can **only receive NEC codes, but does not require any timer** and runs even on a 1 MHz ATtiny85.
The code for the timer and the **timer selection** is located in [private/IRTimer.hpp](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/private/IRTimer.hpp). It can be adjusted here.<br/>
The code for the timer and the **timer selection** is located in [private/IRTimer.hpp](https://github.com/Arduino-IRremote/Arduino-IRremote/blob/master/src/private/IRTimer.hpp). The selected timer can be adjusted here.
**Be aware that the hardware timer used for receiving should not be used for analogWrite()!**.<br/>
| Board/CPU | Receive<br/>& PWM Timers| Hardware-PWM Pin | analogWrite()<br/>pins occupied by timer |
| Board/CPU | Receive<br/>& send PWM Timer<br/>Default timer is **bold** | Hardware-Send-PWM Pin | analogWrite()<br/>pins occupied by timer |
|-|-|-|-|
| [ATtiny84](https://github.com/SpenceKonde/ATTinyCore/blob/v2.0.0-devThis-is-the-head-submit-PRs-against-this/avr/extras/ATtiny_x4.md) | **1** | **6** | |
| [ATtiny85 > 4 MHz](https://github.com/SpenceKonde/ATTinyCore/blob/v2.0.0-devThis-is-the-head-submit-PRs-against-this/avr/extras/ATtiny_x5.md) | **0**, 1 | **0**, 4 | **0**, 1 & 4 |
@ -787,9 +800,9 @@ The code for the timer and the **timer selection** is located in [private/IRTime
| [ATmega64, ATmega128, ATmega1281, ATmega2561](https://github.com/MCUdude/MegaCore#supported-microcontrollers) | **1** | **13** |
| [ATmega8515, ATmega162](https://github.com/MCUdude/MajorCore#pinout ) | **1** | **13** |
| ATmega168, **ATmega328** | 1, **2** | 9, **3** | 9 & 10, **3 & 11** |
| ATmega1280, ATmega2560 | 1, **2**, 3, 4, 5 | 5, 6, **9**, 11, 46 | |
| ATmega1280, **ATmega2560** | 1, **2**, 3, 4, 5 | 5, 6, **9**, 11, 46 | 5, 6, **9**, 11, 46 |
| ATmega4809 | **TCB0** | **A4** | |
| Leonardo (Atmega32u4) | 1, 3, **4_HS** | 5, **9**, 13 | |
| Leonardo (Atmega32u4) | 1, 3, **4_HS** | 5, **9**, 13 | 5, **9**, 13 |
| Zero (SAMD) | **TC3** | \*, **9** | |
| [ESP32](http://esp32.net/) | **Ledc chan. 0** | All pins | |
| [Sparkfun Pro Micro](https://www.sparkfun.com/products/12640) | 1, **3** | **5**, 9 | |

View File

@ -145,8 +145,13 @@
#define VCC_UNDERVOLTAGE_CHECKS_BEFORE_STOP 6 // Shutdown after 6 times (60 seconds) VCC below VCC_UNDERVOLTAGE_THRESHOLD_MILLIVOLT or 1 time below VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT
#endif
#if !defined(VOLTAGE_USB_LOWER_THRESHOLD_MILLIVOLT)
#define VOLTAGE_USB_LOWER_THRESHOLD_MILLIVOLT 4300
#if !defined(VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT)
#define VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT 4300 // Assume USB powered above this voltage
#endif
#if !defined(VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT)
#define VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT 4950 // Assume USB powered below this voltage, because of the loss in USB cable. If we have > 4950, we assume to be powered by VIN.
// In contrast to e.g. powered by VIN, which results in almost perfect 5 volt supply
#endif
extern long sLastVCCCheckMillis;

View File

@ -540,11 +540,12 @@ uint16_t getVoltageMillivoltWith_1_1VoltReference(uint8_t aADCChannelForVoltageM
}
/*
* Return true if sVCCVoltageMillivolt is > 4.3 V
* Return true if sVCCVoltageMillivolt is > 4.3 V and < 4.95 V
*/
bool isVCCUSBPowered() {
readVCCVoltageMillivolt();
return (sVCCVoltageMillivolt > VOLTAGE_USB_LOWER_THRESHOLD_MILLIVOLT);
return (VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT < sVCCVoltageMillivolt
&& sVCCVoltageMillivolt < VOLTAGE_USB_POWERED_UPPER_THRESHOLD_MILLIVOLT);
}
/*
@ -602,7 +603,6 @@ bool isVCCUndervoltageMultipleTimes() {
return false;
}
/*
* Return true if VCC_EMERGENCY_UNDERVOLTAGE_THRESHOLD_MILLIVOLT (3 V) reached
*/

View File

@ -105,7 +105,8 @@ uint32_t sMillisOfLastReceivedIRFrame = 0;
#if defined(USE_SERIAL_LCD) || defined(USE_PARALLEL_LCD)
#define USE_LCD
# if defined(__AVR__) && defined(ADCSRA) && defined(ADATE)
// For cyclically display of VCC
// For cyclically display of VCC and isVCCUSBPowered()
#define VOLTAGE_USB_POWERED_LOWER_THRESHOLD_MILLIVOLT 4250
#include "ADCUtils.hpp"
#define MILLIS_BETWEEN_VOLTAGE_PRINT 5000
#define LCD_VOLTAGE_START_INDEX 11
@ -114,13 +115,12 @@ bool ProtocolStringOverwritesVoltage = false;
# endif
#define LCD_IR_COMMAND_START_INDEX 9
#endif // defined(USE_SERIAL_LCD) || defined(USE_PARALLEL_LCD)
void printsVCCVoltageMillivoltOnLCD();
void printIRResultOnLCD();
size_t printByteHexOnLCD(uint16_t aHexByteValue);
void printSpacesOnLCD(uint_fast8_t aNumberOfSpacesToPrint);
uint16_t sVCCMillivolt;
#endif // defined(USE_SERIAL_LCD) || defined(USE_PARALLEL_LCD)
void setup() {
#if FLASHEND >= 0x3FFF // For 16k flash or more, like ATtiny1604. Code does not fit in program memory of ATtiny85 etc.
@ -180,8 +180,8 @@ void setup() {
Serial.println(F(" us are subtracted from all marks and added to all spaces for decoding"));
#endif
#if defined(USE_LCD) && defined(__AVR__) && defined(ADCSRA) && defined(ADATE)
getVCCVoltageMillivoltSimple(); // to initialize ADC mux and reference
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
readVCCVoltageMillivolt();
#endif
#if defined(USE_SERIAL_LCD)
@ -201,7 +201,7 @@ void setup() {
#endif
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
sVCCMillivolt = getVCCVoltageMillivoltSimple();
readVCCVoltageMillivolt();
#endif
}
@ -236,10 +236,10 @@ void loop() {
if ((IrReceiver.decodedIRData.protocol == UNKNOWN || digitalRead(DEBUG_BUTTON_PIN) == LOW)
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
&& sVCCMillivolt > 4222
|| isVCCUSBPowered()
#endif
) {
// Print more info, but only if we are connected to USB, i.e. VCC is > 4222 mV, because this may take to long to detect some fast repeats
) {
// Print more info, but only if we are connected to USB, i.e. VCC is > 4300 mV, because this may take to long to detect some fast repeats
IrReceiver.printIRSendUsage(&Serial);
IrReceiver.printIRResultRawFormatted(&Serial, false); // print ticks, this is faster :-)
}
@ -266,10 +266,17 @@ void loop() {
} // if (IrReceiver.decode())
/*
* Check for attention every 10 minute, after the current measurement was finished
* Check if generating attention beep every minute, after the current measurement was finished
*/
if (millis() - sMillisOfLastReceivedIRFrame >= MILLIS_BETWEEN_ATTENTION_BEEP) {
if ((millis() - sMillisOfLastReceivedIRFrame) >= MILLIS_BETWEEN_ATTENTION_BEEP
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
&& !isVCCUSBPowered()
#endif
) {
sMillisOfLastReceivedIRFrame = millis();
#if defined(USE_LCD) && defined(ADC_UTILS_ARE_AVAILABLE)
printsVCCVoltageMillivoltOnLCD();
#endif
IrReceiver.stop();
tone(TONE_PIN, 2200);
delay(50);
@ -284,18 +291,25 @@ void loop() {
* Periodically print VCC
*/
sMillisOfLastVoltagePrint = millis();
sVCCMillivolt = getVCCVoltageMillivoltSimple();
char tVoltageString[5];
dtostrf(sVCCMillivolt / 1000.0, 4, 2, tVoltageString);
myLCD.setCursor(LCD_VOLTAGE_START_INDEX - 1, 0);
myLCD.print(' ');
myLCD.print(tVoltageString);
myLCD.print('V');
readVCCVoltageMillivolt();
printsVCCVoltageMillivoltOnLCD();
}
#endif
}
#if defined(USE_LCD)
void printsVCCVoltageMillivoltOnLCD() {
# if defined(ADC_UTILS_ARE_AVAILABLE)
char tVoltageString[5];
dtostrf(sVCCVoltageMillivolt / 1000.0, 4, 2, tVoltageString);
myLCD.setCursor(LCD_VOLTAGE_START_INDEX - 1, 0);
myLCD.print(' ');
myLCD.print(tVoltageString);
myLCD.print('V');
# endif
}
/*
* LCD output for 1602 LCDs
* 40 - 55 Milliseconds per initial output
@ -305,7 +319,6 @@ void loop() {
*
*/
void printIRResultOnLCD() {
#if defined(USE_LCD)
static uint16_t sLastProtocolIndex = 4711;
static uint16_t sLastProtocolAddress = 4711;
static uint16_t sLastCommand = 0;
@ -421,10 +434,8 @@ void printIRResultOnLCD() {
myLCD.print(' ');
}
} // IrReceiver.decodedIRData.protocol == UNKNOWN
#endif // defined(USE_LCD)
}
#if defined(USE_LCD)
size_t printByteHexOnLCD(uint16_t aHexByteValue) {
myLCD.print(F("0x"));
size_t tPrintSize = 2;
@ -440,4 +451,4 @@ void printSpacesOnLCD(uint_fast8_t aNumberOfSpacesToPrint) {
myLCD.print(' ');
}
}
#endif
#endif // defined(USE_LCD)

View File

@ -87,9 +87,10 @@
// 01000000 00100100 0110Dev_ Sub_Dev_ Fun____ XOR( B2, B3, B4) - Byte 0,1 and vendor parity showing Panasonic vendor code 0x2002.
// 1. interpretation: <start bit><VendorID:16><VendorID parity:4><Device:4><Subdevice:8><Function:8><Parity:8><stop bit>
// see: http://www.remotecentral.com/cgi-bin/mboard/rc-pronto/thread.cgi?26152
// 2. interpretation: <start bit><VendorID:16><VendorID parity:4><Genre1:4><Genre2:4><Command:10><ID:2><Parity:8><stop bit>
// 2. interpretation (Flipper Zero style): <start bit><VendorID:16><VendorID parity:4><Genre1:4><Genre2:4><Command:10><ID:2><Parity:8><stop bit>
// see: https://www.mikrocontroller.net/articles/IRMP_-_english#KASEIKYO
// Implemented is: <start bit><VendorID:16><VendorID parity:4><Address:12><Command:8><Parity of VendorID parity, Address and Command:8><stop bit>
// Implemented is Samsung style: <start bit><VendorID:16><VendorID parity:4><Address:12><Command:8><Parity of VendorID parity, Address and Command:8><stop bit>
// which is derived from Samsung remotes and may not be optimal for Denon kind of Kaseikyo protokol usage.
//
#define KASEIKYO_VENDOR_ID_BITS 16
#define KASEIKYO_VENDOR_ID_PARITY_BITS 4
@ -126,7 +127,7 @@ KASEIKYO_HEADER_SPACE, KASEIKYO_BIT_MARK, KASEIKYO_ONE_SPACE, KASEIKYO_BIT_MARK,
************************************/
/**
* Address can be interpreted as sub-device << 8 + device
* Address can be interpreted as sub-device << 4 + 4 bit device
*/
void IRsend::sendKaseikyo(uint16_t aAddress, uint8_t aCommand, int_fast8_t aNumberOfRepeats, uint16_t aVendorCode) {
// Set IR carrier frequency

View File

@ -72,6 +72,10 @@
// https://www.mikrocontroller.net/articles/IRMP_-_english#SAMSUNG48
// LSB first, 1 start bit + 16 bit address + 16 or 32 bit data + 1 stop bit.
// Here https://forum.arduino.cc/t/klimaanlage-per-ir-steuern/1051381/10 the address (0xB24D) is also 8 bits and then 8 inverted bits
//
// Here https://github.com/flipperdevices/flipperzero-firmware/blob/master/lib/infrared/encoder_decoder/samsung/infrared_decoder_samsung.c#L18
// Address is 8 bit + same 8 bit if data is 8 bit and ~8 bit.
//
// IRP notation: {38k,5553}<1,-1|1,-3>(8,-8,D:8,S:8,F:8,~F:8,1,^110)+ ==> 8 bit + 8 bit inverted data - Samsung32
// IRP notation: {38k,5553}<1,-1|1,-3>(8,-8,D:8,S:8,F:16,1,^110)+ ==> 16 bit data - still Samsung32
// IRP notation: {38k,5553}<1,-1|1,-3>(8,-8,D:8,S:8,F:8,~F:8,G:8,~G:8,1,^110)+ ==> 2 x (8 bit + 8 bit inverted data) - Samsung48
@ -84,7 +88,7 @@
// except SAMSUNG_HEADER_MARK, values are like NEC
#define SAMSUNG_UNIT 560 // 21.28 periods of 38 kHz, 11.2 ticks TICKS_LOW = 8.358 TICKS_HIGH = 15.0
#define SAMSUNG_HEADER_MARK (8 * SAMSUNG_UNIT) // 4500 | 180
#define SAMSUNG_HEADER_MARK (8 * SAMSUNG_UNIT) // 4500 | 180 periods
#define SAMSUNG_HEADER_SPACE (8 * SAMSUNG_UNIT) // 4500
#define SAMSUNG_BIT_MARK SAMSUNG_UNIT
#define SAMSUNG_ONE_SPACE (3 * SAMSUNG_UNIT) // 1690 | 33.8 TICKS_LOW = 25.07 TICKS_HIGH = 45.0
@ -93,8 +97,7 @@
#define SAMSUNG_AVERAGE_DURATION 55000 // SAMSUNG_HEADER_MARK + SAMSUNG_HEADER_SPACE + 32 * 2,5 * SAMSUNG_UNIT + SAMSUNG_UNIT // 2.5 because we assume more zeros than ones
#define SAMSUNG_REPEAT_DURATION (SAMSUNG_HEADER_MARK + SAMSUNG_HEADER_SPACE + SAMSUNG_BIT_MARK + SAMSUNG_ZERO_SPACE + SAMSUNG_BIT_MARK)
#define SAMSUNG_REPEAT_PERIOD 110000 // Commands are repeated every 110 ms (measured from start to start) for as long as the key on the remote control is held down.
#define SAMSUNG_REPEAT_DISTANCE (SAMSUNG_REPEAT_PERIOD - SAMSUNG_AVERAGE_DURATION)
#define SAMSUNG_MAXIMUM_REPEAT_DISTANCE (SAMSUNG_REPEAT_DISTANCE + (SAMSUNG_REPEAT_DISTANCE / 4)) // Just a guess
#define SAMSUNG_MAXIMUM_REPEAT_DISTANCE (SAMSUNG_REPEAT_PERIOD + (SAMSUNG_REPEAT_PERIOD / 4)) // 137000 - Just a guess
struct PulseDistanceWidthProtocolConstants SamsungProtocolConstants = { SAMSUNG, SAMSUNG_KHZ, SAMSUNG_HEADER_MARK,
SAMSUNG_HEADER_SPACE, SAMSUNG_BIT_MARK, SAMSUNG_ONE_SPACE, SAMSUNG_BIT_MARK, SAMSUNG_ZERO_SPACE, PROTOCOL_IS_LSB_FIRST,
@ -165,6 +168,12 @@ void IRsend::sendSamsung(uint16_t aAddress, uint16_t aCommand, int_fast8_t aNumb
// Send 8 command bits and then 8 inverted command bits LSB first
tSendValue.UBytes[2] = aCommand;
tSendValue.UBytes[3] = ~aCommand;
if (aAddress < 0x100) {
// This makes it flipper IRDB compatible
// https://github.com/flipperdevices/flipperzero-firmware/blob/master/lib/infrared/encoder_decoder/samsung/infrared_decoder_samsung.c#L18
// Duplicate address byte, if data is 8 bit and 8 bit inverted and address is 8bit
tSendValue.UBytes[1] = aAddress;
}
} else {
// Send 16 command bits
tSendValue.UWords[1] = aCommand;