Open lnxknl4 opened 1 year ago
Here is an example of implementing a custom protocol on STM32 to send and receive packetized messages with a host system:
// Packet structure
typedef struct {
uint8_t start_byte; // Start byte
uint8_t msg_len; // Message length
uint8_t msg_type; // Message type
uint8_t data[64]; // Message data
uint8_t crc; // CRC checksum
} packet_t;
// Function to calculate CRC uint8_t crc_calc(packet_t *pkt) { // CRC algorithm return crc; }
// Function to send packet void send_packet(packet_t *pkt) {
pkt->crc = crc_calc(pkt);
// Add start byte USART_SendData(START_BYTE);
// Send packet bytes over USART USART_SendData(pkt->msg_len); USART_SendData(pkt->msg_type); // etc... USART_SendData(pkt->crc); }
// Function to receive packet packet_t recv_packet() {
packet_t pkt;
// Wait for start byte while(USART_ReceiveData() != START_BYTE);
// Receive packet bytes pkt.msg_len = USART_ReceiveData(); pkt.msg_type = USART_ReceiveData(); // etc...
// Verify CRC if(pkt.crc != crc_calc(&pkt)) { // Error }
return pkt; }
// Create and send status packet packet_t pkt; pkt.msg_type = 1; // Status message
pkt.data[0] = 0x01; // Led on pkt.data[1] = 0x00; // Door closed pkt.data[2] = 23; // Room temp
send_packet(&pkt);
// Receive control packet packet_t ctrl_pkt = recv_packet();
if(ctrl_pkt.msg_type == 2) { // Control message
// Process data
if(ctrl_pkt.data[0]) {
// Turn on LED
}
}
This implements a basic protocol with packet formatting, checksum, message types, and data fields. The MCU can send status packets and receive control packets from a host system over USART.
typedef struct { unsigned long Signature; void (*APP_Start)(void); } APP_Interface;
typedef struct { unsigned long Signature; void (USB_Istr)(void); void (CTR_HP)(void); void (SD_Set_Changed)(void); unsigned char (MSD_WriteBlock)(unsigned char pBuffer, unsigned long WriteAddr, unsigned short NumByteToWrite); unsigned char (MSD_ReadBlock)(unsigned char pBuffer, unsigned long ReadAddr, unsigned short NumByteToRead); unsigned short (GetFont_8x14)(unsigned char chr, unsigned char row); unsigned char (*Get_Ref_Wave)(unsigned short idx); } LIB_Interface;
//** END OF FILE *** typedef struct { unsigned long Signature; void (*APP_Start)(void); } APP_Interface;
typedef struct { unsigned long Signature; void (USB_Istr)(void); void (CTR_HP)(void); void (SD_Set_Changed)(void); unsigned char (MSD_WriteBlock)(unsigned char pBuffer, unsigned long WriteAddr, unsigned short NumByteToWrite); unsigned char (MSD_ReadBlock)(unsigned char pBuffer, unsigned long ReadAddr, unsigned short NumByteToRead); unsigned short (Get_Font_8x14)(unsigned char chr, unsigned char row); unsigned char (*Get_Ref_Wave)(unsigned short idx); } LIB_Interface;
struct sr_dev_driver {
/* Driver-specific */
char *name;
char *longname;
int api_version;
int driver_type; // enum sr_dev_driver_type
int (*init) (struct sr_context *sr_ctx);
int (*cleanup) (void);
GSList *(*scan) (GSList *options);
const GSList *(*dev_mode_list) (const struct sr_dev_inst *sdi);
int (*config_get) (int id, GVariant **data,
const struct sr_dev_inst *sdi,
const struct sr_channel *ch,
const struct sr_channel_group *cg);
int (*config_set) (int id, GVariant *data,
struct sr_dev_inst *sdi,
struct sr_channel *ch,
struct sr_channel_group *cg);
int (*config_list) (int info_id, GVariant **data,
const struct sr_dev_inst *sdi,
const struct sr_channel_group *cg);
/* Device-specific */
int (*dev_open) (struct sr_dev_inst *sdi);
int (*dev_close) (struct sr_dev_inst *sdi);
int (*dev_destroy) (struct sr_dev_inst *sdi);
int (*dev_status_get) (const struct sr_dev_inst *sdi,
struct sr_status *status, gboolean prg);
int (*dev_acquisition_start) (struct sr_dev_inst *sdi,
void *cb_data);
int (*dev_acquisition_stop) (const struct sr_dev_inst *sdi,
void *cb_data);
/* Dynamic */
void *priv;
};
static const struct DSL_channels channel_modes[] = { // LA Stream {DSL_STREAM20x16, LOGIC, SR_CHANNEL_LOGIC, TRUE, 16, 16, 1, SR_KHZ(50), SR_MHZ(20), SR_KHZ(10), SR_MHZ(100), 1, "Use 16 Channels (Max 20MHz)"}, {DSL_STREAM25x12, LOGIC, SR_CHANNEL_LOGIC, TRUE, 16, 12, 1, SR_KHZ(50), SR_MHZ(25), SR_KHZ(10), SR_MHZ(100), 1, "Use 12 Channels (Max 25MHz)"}, {DSL_STREAM50x6, LOGIC, SR_CHANNEL_LOGIC, TRUE, 16, 6, 1, SR_KHZ(50), SR_MHZ(50), SR_KHZ(10), SR_MHZ(100), 1, "Use 6 Channels (Max 50MHz)"}, {DSL_STREAM100x3, LOGIC, SR_CHANNEL_LOGIC, TRUE, 16, 3, 1, SR_KHZ(50), SR_MHZ(100), SR_KHZ(10), SR_MHZ(100), 1, "Use 3 Channels (Max 100MHz)"},
struct {
// Byte 0
uint8_t Mode :3;
uint8_t Power :1;
uint8_t BasicFan :2;
uint8_t SwingAuto :1;
uint8_t :1; // Sleep Modes 1 & 3 (1 = On, 0 = Off)
// Byte 1
uint8_t Temp :4; // Degrees C.
uint8_t :4;
// Byte 2
uint8_t :4;
uint8_t Turbo :1;
uint8_t Light :1;
uint8_t IonFilter :1;
uint8_t XFan :1;
// Byte 3
uint8_t :4;
uint8_t :2; // (possibly timer related) (Typically 0b01)
uint8_t :2; // End of command block (B01)
// (B010 marker and a gap of 20ms)
// Byte 4
uint8_t SwingV :4;
uint8_t SwingH :1;
uint8_t :3;
// Byte 5~6
uint8_t pad0[2]; // Timer related. Typically 0 except when timer in use.
// Byte 7
uint8_t :4; // (Used in Timer mode)
uint8_t Sum1 :4; // checksum of the previous bytes (0-6)
// (gap of 40ms)
// (header mark and space)
// Byte 8~10
uint8_t pad1[3]; // Repeat of byte 0~2
// Byte 11
uint8_t :4;
uint8_t :2; // (possibly timer related) (Typically 0b11)
uint8_t :2; // End of command block (B01)
// (B010 marker and a gap of 20ms)
// Byte 12
const uint8_t kCoronaAcSections = 3;
/// Native representation of a Corona A/C message. union CoronaProtocol { uint8_t raw[kCoronaAcStateLength]; ///< The state of the IR remote. CoronaSection sections[kCoronaAcSections]; struct { // Byte 0 uint8_t :8; // Byte 1 uint8_t :8; // Byte 2 uint8_t :8; // Byte 3 uint8_t Fan :2; uint8_t :1; uint8_t Econo :1; uint8_t :1; // always on uint8_t :1; uint8_t SwingVToggle :1; uint8_t :1; // Byte 4 uint8_t :8; // Byte 5 uint8_t Temp :4; uint8_t Power :1; uint8_t PowerButton :1; uint8_t Mode :2; }; };
const uint8_t kCoronaAcOffTimerSection = 2; const uint16_t kCoronaAcTimerMax = 12 * 60; // 12H in Minutes // Min value on remote is 1 hour, actual sent value can be 2 secs const uint16_t kCoronaAcTimerOff = 0xffff; const uint16_t kCoronaAcTimerUnitsPerMin = 30; // 30 units = 1 minute
// Classes
/// Class for handling detailed Corona A/C messages. struct { // Byte 0 (least significant byte) uint8_t :8; // fixed value (0x81) // Byte 1 uint8_t Mode :2; uint8_t PowerOff :1; uint8_t Fan :3; uint8_t :2; // fixed value (0b11) // Byte 2 uint8_t Temp:5; ///< Temp in DegC minus 10(DEC). uint8_t :3; // Byte 3 uint8_t :8; // fixed value (0xFF) // Byte 4 uint8_t :8; // fixed value (0xFF) // Byte 5 uint8_t :8; // fixed value (0xFF) // Byte 6 uint8_t Sum:8; ///< Checksum value };
34 void setup() { 33 Serial.begin(115200); 32 delay(200); 31 30 // Set up what we want to send. 29 // See state_t, opmode_t, fanspeed_t, swingv_t, & swingh_t in IRsend.h for 28 // all the various options. 27 ac.next.protocol = decode_type_t::DAIKIN; // Set a protocol to use. 26 ac.next.model = 1; // Some A/Cs have different models. Try just the first. 25 ac.next.mode = stdAc::opmode_t::kCool; // Run in cool mode initially. 24 ac.next.celsius = true; // Use Celsius for temp units. False = Fahrenheit 23 ac.next.degrees = 25; // 25 degrees. 22 ac.next.fanspeed = stdAc::fanspeed_t::kMedium; // Start the fan at medium. 21 ac.next.swingv = stdAc::swingv_t::kOff; // Don't swing the fan up or down. 20 ac.next.swingh = stdAc::swingh_t::kOff; // Don't swing the fan left or right. 19 ac.next.light = false; // Turn off any LED/Lights/Display that we can. 18 ac.next.beep = false; // Turn off any beep from the A/C if we can. 17 ac.next.econo = false; // Turn off any economy modes if we can. 16 ac.next.filter = false; // Turn off any Ion/Mold/Health filters if we can. 15 ac.next.turbo = false; // Don't use any turbo/powerful/etc modes. 14 ac.next.quiet = false; // Don't use any quiet/silent/etc modes. 13 ac.next.sleep = -1; // Don't set any sleep time or modes. 12 ac.next.clean = false; // Turn off any Cleaning options if we can. 11 ac.next.clock = -1; // Don't set any current time if we can avoid it. 10 ac.next.power = false; // Initially start with the unit off. 9 8 Serial.println("Try to turn on & off every supported A/C type ...");
PubSubClient mqtt_client(espClient); String lastMqttCmd = FPSTR("None"); String lastMqttCmdTopic = FPSTR("None"); uint32_t lastMqttCmdTime = 0; uint32_t lastConnectedTime = 0; uint32_t lastDisconnectedTime = 0; uint32_t mqttDisconnectCounter = 0; uint32_t mqttSentCounter = 0; uint32_t mqttRecvCounter = 0; bool wasConnected = true;
char MqttServer[kHostnameLength + 1] = "10.0.0.4"; char MqttPort[kPortLength + 1] = "1883"; char MqttUsername[kUsernameLength + 1] = ""; char MqttPassword[kPasswordLength + 1] = ""; char MqttPrefix[kHostnameLength + 1] = "";
String MqttAck; // Sub-topic we send back acknowledgements on. String MqttSend; // Sub-topic we get new commands from. String MqttRecv; // Topic we send received IRs to. String MqttLog; // Topic we send log messages to. String MqttLwt; // Topic for the Last Will & Testament. String MqttClimate; // Sub-topic for the climate topics. String MqttClimateCmnd; // Sub-topic for the climate command topics.
String MqttDiscovery; String MqttUniqueId;
String MqttDiscoverySensor;
String MqttHAName; String MqttClientId;
String MqttSensorStat;
NORMAL examples/IRMQTTServer/IRMQTTServer.ino arduino utf-8[unix] /\<protoc…[5/30] 4% ㏑:4943/3507☰℅: 1 ERDTreeToggle
void doRestart(const char* str, const bool serial_only) {
if (!serial_only) mqttLog(str); else
debug(str);
delay(2000); // Enough time for messages to be sent. ESP.restart(); delay(5000); // Enough time to ensure we don't return. }
if (inputLength > stateSize * 2) { debug("AirCon code to large for the given protocol."); return false; }
// Ptr to the least significant byte of the resulting state for this protocol. uint8_t *statePtr = &state[stateSize - 1];
// Convert the string into a state array of the correct length. for (uint16_t i = 0; i < inputLength; i++) { // Grab the next least sigificant hexadecimal digit from the string. uint8_t c = tolower(str[inputLength + strOffset - i - 1]); if (isxdigit(c)) { if (isdigit(c)) c -= '0'; else c = c - 'a' + 10; } else { debug("Aborting! Non-hexadecimal char found in AirCon state:"); debug(str.c_str()); return false; } if (i % 2 == 1) { // Odd: Upper half of the byte. statePtr += (c << 4); statePtr--; // Advance up to the next least significant byte of state. } else { // Even: Lower half of the byte. statePtr = c; } } if (!irsend->send(irType, state, stateSize)) { debug("Unexpected AirCon type in send request. Not sent."); return false; }
server.on("/", handleRoot); server.on("/ir", handleIr);
server.on("/inline", [](){ server.send(200, "text/plain", "this works as well"); });
server.onNotFound(handleNotFound);
server.begin(); Serial.println("HTTP server started");
void handleIr() { for (uint8_t i = 0; i < server.args(); i++) { if (server.argName(i) == "code") { uint32_t code = strtoul(server.arg(i).c_str(), NULL, 10);
irsend.sendNEC(code, 32);
}
} handleRoot(); }
/// Event structure contains detailed information about an event. /// \note MUST REMAIN UNCHANGED: \b os_event shall be consistent in every CMSIS-RTOS. /// However the struct may be extended at the end. typedef struct { osStatus status; ///< status code: event or error information union { uint32_t v; ///< message as 32-bit value void *p; ///< message or mail as void pointer int32_t signals; ///< signal flags } value; ///< event value union { osMailQId mail_id; ///< mail id obtained by \ref osMailCreate osMessageQId message_id; ///< message id obtained by \ref osMessageCreate } def; ///< event definition } osEvent;
/// Definition structure for message queue.
/// \note CAN BE CHANGED: \b os_messageQ_def is implementation specific in every CMSIS-RTOS.
typedef struct os_messageQ_def {
uint32_t queue_sz; ///< number of elements in the queue
uint32_t item_sz; ///< size of an item
#if( configSUPPORT_STATIC_ALLOCATION == 1 )
uint8_t *buffer; ///< buffer for static allocation; NULL for dynamic allocation
osStaticMessageQDef_t *controlblock; ///< control block to hold queue's data for static allocation; NULL for dynamic allocatio
n
#endif
//void *pool; ///< memory array for messages
} osMessageQDef_t;
#if (defined (osFeature_SysTick) && (osFeature_SysTick != 0)) // System Timer available
/// Get the RTOS kernel system timer counter
/// \note MUST REMAIN UNCHANGED: \b osKernelSysTick shall be consistent in every CMSIS-RTOS.
/// \return RTOS kernel system timer as 32-bit value
uint32_t osKernelSysTick (void);
/// The RTOS kernel system timer frequency in Hz
/// \note Reflects the system timer setting and is typically defined in a configuration file.
#define osKernelSysTickFrequency (configTICK_RATE_HZ)
/// Convert a microseconds value to a RTOS kernel system timer value.
/// \param microsec time value in microseconds.
/// \return time value normalized to the \ref osKernelSysTickFrequency
#define osKernelSysTickMicroSec(microsec) (((uint64_t)microsec * (osKernelSysTickFrequency)) / 1000000)
#endif // System Timer available
#define osThreadDef(name, thread, priority, instances, stacksz) \
extern const osThreadDef_t os_thread_def_##name
struct {
uint16_t PE_UnchunkSupport : 1u; /*!< Unchunked support */
uint16_t PE_FastRoleSwapSupport : 1u; /*!< Fast role swap support (not yet implemented) */
uint16_t Is_GetPPSStatus_Supported : 1u; /*!< Get PPS status message supported by PE */
uint16_t Is_SrcCapaExt_Supported : 1u; /*!< Source_Capabilities_Extended message supported by PE */
uint16_t Is_Alert_Supported : 1u; /*!< Alert message supported by PE */
uint16_t Is_GetStatus_Supported : 1u; /*!< Get_Status message supported by PE (Is_Alert_Supported should be enabled) */
uint16_t Is_GetManufacturerInfo_Supported : 1u; /*!< Manufacturer_Info message supported by PE */
uint16_t Is_GetCountryCodes_Supported : 1u; /*!< Get_Country_Codes message supported by PE */
uint16_t Is_GetCountryInfo_Supported : 1u; /*!< Get_Country_Info message supported by PE */
uint16_t Is_SecurityRequest_Supported : 1u; /*!< Security_Response message supported by PE */
uint16_t Is_FirmUpdateRequest_Supported : 1u; /*!< Firmware update response message supported by PE */
uint16_t Is_SnkCapaExt_Supported : 1u; /*!< Sink_Capabilities_Extended message supported by PE */
uint16_t reserved : 3u; /*!< Reserved bits */
} d;
}USBPD_PD3SupportTypeDef;
#if defined(USBPD_REV30_SUPPORT)
USBPD_PD3SupportTypeDef PE_PD3_Support; /*!< PD3 structure support flags based on @ref USBPD_PD3SupportTypeDef
*/
#else
uint16_t reserved : 16u; /*!< Reserved bits */
typedef struct
{
USBPD_SpecRev_TypeDef PE_SpecRevision : 2u; /*!< PE Specification revision */
USBPD_PortPowerRole_TypeDef PE_PowerRole : 1u; /*!< PE Power role */
struct {
uint8_t MeasReportValue :7; /*!< Enable Measure reporting every tr x 40 ms */
uint8_t MeasReportActivation :1; /*!< Enable or Disable Measure reporting */
}d;
}u;
uint8_t Reserved :8; /*!< Reserved bits */
} GUI_USER_ParamsTypeDef;
#if !defined(_RTOS)
extern volatile uint32_t GUI_Flag;
#endif /* !_RTOS */
/* Exported functions ------------------------------------------------------- */
/** @defgroup USBPD_GUI_API_Exported_Functions USBPD GUI API exported functions
* @{
*/
// ==== Thread Management ====
/// Create a Thread Definition with function, priority, and stack requirements.
/// \param name name of the thread function.
/// \param priority initial priority of the thread function.
/// \param instances number of possible thread instances.
/// \param stacksz stack size (in bytes) requirements for the thread function.
/// \note CAN BE CHANGED: The parameters to \b osThreadDef shall be consistent but the
/// macro body is implementation specific in every CMSIS-RTOS.
{
uint32_t DPM_ListOfRcvSRCPDO[USBPD_MAX_NB_PDO]; /*!< The list of received Source Power Data Objects from Port
partner
(when Port partner is a Source or a DRP port).
*/
uint32_t DPM_NumberOfRcvSRCPDO; /*!< The number of received Source Power Data Objects from po
rt Partner
(when Port partner is a Source or a DRP port).
This parameter must be set to a value lower than USBPD_M
/**
* @brief USBPD DPM handle Structure definition
* @{
*/
LL_TIM_OC_SetCompareCH1(TIMX, (TimeUs + TIMX->CNT) % TIM_MAX_TIME);\
LL_TIM_ClearFlag_CC1(TIMX); \
}while(0)
/** @brief Clear the specified UART pending flag.
* @param __HANDLE__ specifies the UART Handle.
* @param __FLAG__ specifies the flag to check.
* This parameter can be any combination of the following values:
* @arg @ref UART_CLEAR_PEF Parity Error Clear Flag
* @arg @ref UART_CLEAR_FEF Framing Error Clear Flag
* @arg @ref UART_CLEAR_NEF Noise detected Clear Flag
* @arg @ref UART_CLEAR_OREF Overrun Error Clear Flag
* @arg @ref UART_CLEAR_IDLEF IDLE line detected Clear Flag
* @arg @ref UART_CLEAR_TXFECF TXFIFO empty clear Flag
* @arg @ref UART_CLEAR_TCF Transmission Complete Clear Flag
* @arg @ref UART_CLEAR_LBDF LIN Break Detection Clear Flag
* @arg @ref UART_CLEAR_CTSF CTS Interrupt Clear Flag
* @arg @ref UART_CLEAR_CMF Character Match Clear Flag
* @arg @ref UART_CLEAR_WUF Wake Up from stop mode Clear Flag
* @retval None
*/
{ \
switch(__HAL_RCC_GET_USART2_SOURCE()) \
{ \
case RCC_USART2CLKSOURCE_PCLK1: \
(__CLOCKSOURCE__) = UART_CLOCKSOURCE_PCLK1; \
break; \
case RCC_USART2CLKSOURCE_HSI: \
(__CLOCKSOURCE__) = UART_CLOCKSOURCE_HSI; \
break; \
case RCC_USART2CLKSOURCE_SYSCLK: \
(__CLOCKSOURCE__) = UART_CLOCKSOURCE_SYSCLK; \
break; \
case RCC_USART2CLKSOURCE_LSE: \
(__CLOCKSOURCE__) = UART_CLOCKSOURCE_LSE; \
break; \
default: \
(__CLOCKSOURCE__) = UART_CLOCKSOURCE_UNDEFINED; \
break; \
/-----------------------------------------------------------------------------------/ /* All the stuff below this point is internal to uIP and should not be
typedef struct { / IP header. / u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; u16_t ipchksum; u16_t srcipaddr[2], destipaddr[2];
/* TCP header. */
u16_t srcport,
destport;
u8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
u16_t tcpchksum;
u8_t urgp[2];
u8_t optdata[4];
} uip_tcpip_hdr;
`/-----------------------------------------------------------------------------------/ /* All the stuff below this point is internal to uIP and should not be
typedef struct { / IP header. / u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; u16_t ipchksum; u16_t srcipaddr[2], destipaddr[2];
/* TCP header. */
u16_t srcport,
destport;
u8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
u16_t tcpchksum;
u8_t urgp[2];
u8_t optdata[4];
} uip_tcpip_hdr; `
`/-----------------------------------------------------------------------------------/ / u8_t uip_flags:
typedef struct { / IP header. / u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; u16_t ipchksum; u16_t srcipaddr[2], destipaddr[2];
/* TCP header. */
u16_t srcport,
destport;
u8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
u16_t tcpchksum;
u8_t urgp[2];
u8_t optdata[4];
} uip_tcpip_hdr; `
/*-----------------------------------------------------------------------------------*/
/* u8_t uip_flags:
*
* When the application is called, uip_flags will contain the flags
* that are defined in this file. Please read below for more
* infomation.
--
typedef struct {
/* IP header. */
u8_t vhl,
tos,
len[2],
ipid[2],
ipoffset[2],
ttl,
proto;
u16_t ipchksum;
u16_t srcipaddr[2],
destipaddr[2];
/* TCP header. */
u16_t srcport,
destport;
u8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
u16_t tcpchksum;
u8_t urgp[2];
u8_t optdata[4];
} uip_tcpip_hdr;
`/-----------------------------------------------------------------------------------/ / u8_t uip_flags:
typedef struct { / IP header. / u8_t vhl, tos, len[2], ipid[2], ipoffset[2], ttl, proto; u16_t ipchksum; u16_t srcipaddr[2], destipaddr[2];
/* TCP header. */
u16_t srcport,
destport;
u8_t seqno[4],
ackno[4],
tcpoffset,
flags,
wnd[2];
u16_t tcpchksum;
u8_t urgp[2];
u8_t optdata[4];
} uip_tcpip_hdr; `
<!---
your comment goes here
and here
-->
/* Colorspace conversion */
struct jpeg_color_converter {
JMETHOD(void, start_pass, (j_compress_ptr cinfo));
JMETHOD(void, color_convert, (j_compress_ptr cinfo,
JSAMPARRAY input_buf, JSAMPIMAGE output_buf,
JDIMENSION output_row, int num_rows));
/* Data source object for decompression */
typedef struct jpeg_source_mgr {
const JOCTET * next_input_byte; /* => next byte to read from buffer */
size_t bytes_in_buffer; /* # of bytes remaining in buffer */
JMETHOD(void, init_source, (j_decompress_ptr cinfo));
JMETHOD(boolean, fill_input_buffer, (j_decompress_ptr cinfo));
JMETHOD(void, skip_input_data, (j_decompress_ptr cinfo, long num_bytes));
JMETHOD(boolean, resync_to_restart, (j_decompress_ptr cinfo, int desired));
JMETHOD(void, term_source, (j_decompress_ptr cinfo));
} jpeg_source_mgr;
typedef struct Button {
uint16_t ticks;
uint8_t repeat : 4;
uint8_t event : 4;
uint8_t state : 3;
uint8_t debounce_cnt : 3;
uint8_t active_level : 1;
uint8_t button_level : 1;
uint8_t button_id;
uint8_t (*hal_button_Level)(uint8_t button_id_);
BtnCallback cb[number_of_event];
struct Button* next;
}Button;
#ifdef __cplusplus
extern "C" {
#endif
void button_init(struct Button* handle, uint8_t(*pin_level)(uint8_t), uint8_t active_level, uint8_t button_id);
void button_attach(struct Button* handle, PressEvent event, BtnCallback cb);
PressEvent get_button_event(struct Button* handle);
int button_start(struct Button* handle);
void button_stop(struct Button* handle);
void button_ticks(void);
hello
AI generate code snips