mirror of
https://github.com/google/pebble.git
synced 2025-07-05 06:10:27 -04:00
156 lines
5.4 KiB
C
156 lines
5.4 KiB
C
/*
|
|
* Copyright 2024 Google LLC
|
|
*
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
* you may not use this file except in compliance with the License.
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
* See the License for the specific language governing permissions and
|
|
* limitations under the License.
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include "applib/app_message/app_message.h"
|
|
#include "applib/app_timer.h"
|
|
#include "services/normal/app_message/app_message_sender.h"
|
|
#include "util/attributes.h"
|
|
#include "util/uuid.h"
|
|
|
|
typedef struct CommSession CommSession;
|
|
|
|
#define ACK_NACK_TIME_OUT_MS (10000)
|
|
#define APP_MESSAGE_ENDPOINT_ID (0x30)
|
|
|
|
typedef enum {
|
|
CMD_PUSH = 0x01,
|
|
CMD_REQUEST = 0x02,
|
|
CMD_ACK = 0xff,
|
|
CMD_NACK = 0x7f,
|
|
} AppMessageCmd;
|
|
|
|
typedef struct PACKED {
|
|
AppMessageCmd command:8;
|
|
uint8_t transaction_id;
|
|
} AppMessageHeader;
|
|
|
|
//! The actual wire format of an app message message
|
|
typedef struct PACKED {
|
|
AppMessageHeader header;
|
|
Uuid uuid;
|
|
Dictionary dictionary; //!< Variable length!
|
|
} AppMessagePush;
|
|
// AppMessageHeader and Uuid size should be opaque to user of API
|
|
#define APP_MSG_HDR_OVRHD_SIZE (offsetof(AppMessagePush, dictionary))
|
|
|
|
#define APP_MSG_8K_DICT_SIZE (sizeof(Dictionary) + sizeof(Tuple) + (8 * 1024))
|
|
|
|
typedef struct PACKED {
|
|
AppMessageHeader header;
|
|
} AppMessageAck;
|
|
|
|
// For a diagram of the state machine:
|
|
// https://pebbletechnology.atlassian.net/wiki/pages/editpage.action?pageId=91914242
|
|
|
|
typedef enum AppMessagePhaseOut {
|
|
//! The App Message Outbox is not enabled. To enable it, call app_message_open().
|
|
OUT_CLOSED = 0,
|
|
//! The dictionary writing can be "started" by calling app_message_outbox_begin()
|
|
OUT_ACCEPTING,
|
|
//! app_message_outbox_begin() has been called and the dictionary can be written and then sent.
|
|
OUT_WRITING,
|
|
//! app_message_outbox_send() has been called. The ack/nack timeout timer has been set and
|
|
//! we're awaiting an ack/nack on the sent message AND the callback from the AppOutbox subsystem
|
|
//! that the data has been consumed. These 2 things happen in parallel, the order in which they
|
|
//! happen is undefined.
|
|
OUT_AWAITING_REPLY_AND_OUTBOX_CALLBACK,
|
|
//! We're still awaiting the AppMessage ack/nack, but the AppOutbox subsystem has indicated that
|
|
//! the data has been consumed.
|
|
OUT_AWAITING_REPLY,
|
|
//! We're still awaiting the callback from the AppOutbox subsystem to indicate the data has been
|
|
//! consumed, but we have already received the AppMessage ack/nack. This state is possible because
|
|
//! acking at a lower layer (i.e. PPoGATT) can happen with a slight delay.
|
|
OUT_AWAITING_OUTBOX_CALLBACK,
|
|
} AppMessagePhaseOut;
|
|
|
|
typedef struct AppMessageCtxInbox {
|
|
bool is_open;
|
|
void *user_context;
|
|
AppMessageInboxReceived received_callback;
|
|
AppMessageInboxDropped dropped_callback;
|
|
} AppMessageCtxInbox;
|
|
|
|
typedef struct AppMessageCtxOutbox {
|
|
DictionaryIterator iterator;
|
|
size_t transmission_size_limit;
|
|
|
|
AppMessageAppOutboxData *app_outbox_message;
|
|
|
|
AppMessageOutboxSent sent_callback;
|
|
AppMessageOutboxFailed failed_callback;
|
|
void *user_context;
|
|
|
|
AppTimer *ack_nack_timer;
|
|
|
|
struct PACKED {
|
|
AppMessagePhaseOut phase:8;
|
|
uint8_t transaction_id;
|
|
uint16_t not_ready_throttle_ms; // used for throttling app task when outbox is not ready
|
|
AppMessageResult result:16;
|
|
};
|
|
} AppMessageCtxOutbox;
|
|
|
|
typedef struct AppMessageCtx {
|
|
AppMessageCtxInbox inbox;
|
|
AppMessageCtxOutbox outbox;
|
|
} AppMessageCtx;
|
|
|
|
_Static_assert(sizeof(AppMessageCtx) <= 112,
|
|
"AppMessageCtx must not exceed 112 bytes!");
|
|
|
|
typedef struct {
|
|
CommSession *session;
|
|
//! To give us some room for future changes. This structure ends up in a buffer that is sized by
|
|
//! the app, so we can't easily increase the size of this once shipped.
|
|
uint8_t padding[8];
|
|
uint8_t data[];
|
|
} AppMessageReceiverHeader;
|
|
|
|
#ifndef UNITTEST
|
|
_Static_assert(sizeof(AppMessageReceiverHeader) == 12,
|
|
"The size of AppMessageReceiverHeader cannot grow beyond 12 bytes!");
|
|
#endif
|
|
|
|
void app_message_init(void);
|
|
|
|
AppMessageResult app_message_inbox_open(AppMessageCtxInbox *inbox, size_t size_inbound);
|
|
|
|
void app_message_inbox_close(AppMessageCtxInbox *inbox);
|
|
|
|
typedef struct AppInboxConsumerInfo AppInboxConsumerInfo;
|
|
|
|
void app_message_inbox_receive(CommSession *session, AppMessagePush *push_message, size_t length,
|
|
AppInboxConsumerInfo *consumer_info);
|
|
|
|
AppMessageResult app_message_outbox_open(AppMessageCtxOutbox *outbox, size_t size_outbound);
|
|
|
|
void app_message_outbox_close(AppMessageCtxOutbox *outbox);
|
|
|
|
void app_message_out_handle_ack_nack_received(const AppMessageHeader *header);
|
|
|
|
void app_message_inbox_send_ack_nack_reply(CommSession *session, const uint8_t transaction_id,
|
|
AppMessageCmd cmd);
|
|
|
|
void app_message_inbox_handle_dropped_messages(uint32_t num_drops);
|
|
|
|
void app_message_app_protocol_msg_callback(CommSession *session,
|
|
const uint8_t* data, size_t length,
|
|
AppInboxConsumerInfo *consumer_info);
|
|
|
|
void app_message_app_protocol_system_nack_callback(CommSession *session,
|
|
const uint8_t* data, size_t length);
|