mirror of
https://github.com/google/pebble.git
synced 2025-07-17 19:46:40 -04:00
Import of the watch repository from Pebble
This commit is contained in:
commit
3b92768480
10334 changed files with 2564465 additions and 0 deletions
256
src/fw/console/pulse_pp.c
Normal file
256
src/fw/console/pulse_pp.c
Normal file
|
@ -0,0 +1,256 @@
|
|||
/*
|
||||
* 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.
|
||||
*/
|
||||
|
||||
#include <bluetooth/bt_driver_comm.h>
|
||||
|
||||
#include "comm/bt_lock.h"
|
||||
|
||||
#include "console/pulse_protocol_impl.h"
|
||||
#include "console/pulse2_transport_impl.h"
|
||||
|
||||
#include "kernel/event_loop.h"
|
||||
#include "kernel/events.h"
|
||||
#include "kernel/pbl_malloc.h"
|
||||
|
||||
#include "services/common/comm_session/session_transport.h"
|
||||
|
||||
#include "system/passert.h"
|
||||
#include "system/logging.h"
|
||||
|
||||
#include "util/attributes.h"
|
||||
#include "util/math.h"
|
||||
|
||||
#include <string.h>
|
||||
|
||||
#define PULSE_PP_OPCODE_DATA (1)
|
||||
#define PULSE_PP_OPCODE_OPEN (2)
|
||||
#define PULSE_PP_OPCODE_CLOSE (3)
|
||||
|
||||
#define PULSE_PP_OPCODE_UNKNOWN (255)
|
||||
|
||||
typedef struct PACKED PulsePPPacket {
|
||||
uint8_t opcode;
|
||||
uint8_t data[0];
|
||||
} PulsePPPacket;
|
||||
|
||||
typedef struct PACKED PulsePPCallbackPacket {
|
||||
size_t packet_length;
|
||||
PulsePPPacket packet;
|
||||
} PulsePPCallbackPacket;
|
||||
|
||||
typedef struct {
|
||||
CommSession *session;
|
||||
} PULSETransport;
|
||||
|
||||
//! The CommSession that the PULSE transport is managing.
|
||||
//! Currently there's only one for the System session.
|
||||
static PULSETransport s_transport;
|
||||
|
||||
static void prv_send_next(Transport *transport) {
|
||||
CommSession *session = s_transport.session;
|
||||
PBL_ASSERTN(session);
|
||||
|
||||
size_t bytes_remaining = comm_session_send_queue_get_length(session);
|
||||
size_t mss = pulse_reliable_max_send_size() - sizeof(PulsePPPacket);
|
||||
|
||||
while (bytes_remaining) {
|
||||
bt_unlock();
|
||||
PulsePPPacket *resp = (PulsePPPacket*) pulse_reliable_send_begin(PULSE2_PEBBLE_PROTOCOL);
|
||||
bt_lock();
|
||||
|
||||
if (resp) {
|
||||
resp->opcode = PULSE_PP_OPCODE_DATA;
|
||||
|
||||
const size_t bytes_to_copy = MIN(bytes_remaining, mss);
|
||||
comm_session_send_queue_copy(session, 0 /* start_offset */,
|
||||
bytes_to_copy, &resp->data[0]);
|
||||
pulse_reliable_send(resp, bytes_to_copy + sizeof(PulsePPPacket));
|
||||
comm_session_send_queue_consume(session, bytes_to_copy);
|
||||
|
||||
bytes_remaining -= bytes_to_copy;
|
||||
} else {
|
||||
// Reliable transport went down while waiting to send.
|
||||
// The CommSession has already been closed so simply return without doing
|
||||
// anything further.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void prv_reset(Transport *transport) {
|
||||
PBL_LOG(LOG_LEVEL_INFO, "Unimplemented");
|
||||
}
|
||||
|
||||
static void prv_granted_kernel_main_cb(void *ctx) {
|
||||
ResponsivenessGrantedHandler granted_handler = ctx;
|
||||
granted_handler();
|
||||
}
|
||||
|
||||
static void prv_set_connection_responsiveness(
|
||||
Transport *transport, BtConsumer consumer, ResponseTimeState state, uint16_t max_period_secs,
|
||||
ResponsivenessGrantedHandler granted_handler) {
|
||||
if (granted_handler) {
|
||||
launcher_task_add_callback(prv_granted_kernel_main_cb, granted_handler);
|
||||
}
|
||||
}
|
||||
|
||||
static CommSessionTransportType prv_get_type(struct Transport *transport) {
|
||||
return CommSessionTransportType_PULSE;
|
||||
}
|
||||
|
||||
static void prv_send_job(void *data) {
|
||||
CommSession *session = (CommSession *)data;
|
||||
bt_driver_run_send_next_job(session, true);
|
||||
}
|
||||
|
||||
static bool prv_schedule_send_next_job(CommSession *session) {
|
||||
launcher_task_add_callback(prv_send_job, session);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool prv_is_current_task_schedule_task(struct Transport *transport) {
|
||||
return launcher_task_is_current_task();
|
||||
}
|
||||
|
||||
//! Defined in session.c
|
||||
extern void comm_session_set_capabilities(
|
||||
CommSession *session, CommSessionCapability capability_flags);
|
||||
|
||||
bool pulse_transport_is_connected(void) {
|
||||
return (s_transport.session != NULL);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------------------------
|
||||
void pulse_transport_set_connected(bool is_connected) {
|
||||
if (pulse_transport_is_connected() == is_connected) {
|
||||
return;
|
||||
}
|
||||
|
||||
static const TransportImplementation s_pulse_transport_implementation = {
|
||||
.send_next = prv_send_next,
|
||||
.reset = prv_reset,
|
||||
.set_connection_responsiveness = prv_set_connection_responsiveness,
|
||||
.get_type = prv_get_type,
|
||||
.schedule = prv_schedule_send_next_job,
|
||||
.is_current_task_schedule_task = prv_is_current_task_schedule_task,
|
||||
};
|
||||
|
||||
bool send_event = true;
|
||||
|
||||
if (is_connected) {
|
||||
s_transport.session = comm_session_open((Transport *) &s_transport,
|
||||
&s_pulse_transport_implementation,
|
||||
TransportDestinationHybrid);
|
||||
if (!s_transport.session) {
|
||||
PBL_LOG(LOG_LEVEL_ERROR, "CommSession couldn't be opened");
|
||||
send_event = false;
|
||||
}
|
||||
|
||||
// Give it the appropriate capabilities
|
||||
const CommSessionCapability capabilities = CommSessionRunState |
|
||||
CommSessionInfiniteLogDumping |
|
||||
CommSessionVoiceApiSupport |
|
||||
CommSessionAppMessage8kSupport |
|
||||
CommSessionWeatherAppSupport |
|
||||
CommSessionExtendedNotificationService;
|
||||
comm_session_set_capabilities(s_transport.session, capabilities);
|
||||
} else {
|
||||
comm_session_close(s_transport.session, CommSessionCloseReason_UnderlyingDisconnection);
|
||||
s_transport.session = NULL;
|
||||
}
|
||||
|
||||
if (send_event) {
|
||||
PebbleEvent e = {
|
||||
.type = PEBBLE_BT_CONNECTION_EVENT,
|
||||
.bluetooth = {
|
||||
.connection = {
|
||||
.state = (s_transport.session) ? PebbleBluetoothConnectionEventStateConnected
|
||||
: PebbleBluetoothConnectionEventStateDisconnected
|
||||
}
|
||||
}
|
||||
};
|
||||
event_put(&e);
|
||||
}
|
||||
}
|
||||
|
||||
static void prv_pulse_pp_transport_set_connected(bool connected) {
|
||||
bt_lock();
|
||||
pulse_transport_set_connected(connected);
|
||||
bt_unlock();
|
||||
}
|
||||
|
||||
static void prv_pulse_pp_handle_data(void *data, size_t length) {
|
||||
bt_lock();
|
||||
|
||||
if (!s_transport.session) {
|
||||
PBL_LOG(LOG_LEVEL_ERROR, "Received PULSE serial data, but session not connected!");
|
||||
goto unlock;
|
||||
}
|
||||
comm_session_receive_router_write(s_transport.session, data, length);
|
||||
|
||||
unlock:
|
||||
bt_unlock();
|
||||
}
|
||||
|
||||
static void prv_pulse_pp_send_cb(void *data) {
|
||||
PulsePPCallbackPacket *cb_data = data;
|
||||
uint8_t *resp = pulse_reliable_send_begin(PULSE2_PEBBLE_PROTOCOL);
|
||||
memcpy(resp, &cb_data->packet, cb_data->packet_length);
|
||||
pulse_reliable_send(resp, cb_data->packet_length);
|
||||
kernel_free(data);
|
||||
}
|
||||
|
||||
static void prv_pulse_pp_send(uint8_t opcode, uint8_t *data, size_t data_length) {
|
||||
size_t packet_length = sizeof(PulsePPCallbackPacket) + data_length;
|
||||
PulsePPCallbackPacket *cb_data = kernel_malloc_check(packet_length);
|
||||
cb_data->packet_length = sizeof(PulsePPPacket) + data_length;
|
||||
cb_data->packet.opcode = opcode;
|
||||
|
||||
if (data) {
|
||||
memcpy(&cb_data->packet.data[0], data, data_length);
|
||||
}
|
||||
|
||||
launcher_task_add_callback(prv_pulse_pp_send_cb, cb_data);
|
||||
}
|
||||
|
||||
void pulse_pp_transport_open_handler(void) {
|
||||
return;
|
||||
}
|
||||
|
||||
void pulse_pp_transport_closed_handler(void) {
|
||||
prv_pulse_pp_transport_set_connected(false);
|
||||
}
|
||||
|
||||
void pulse_pp_transport_handle_received_data(void *data, size_t length) {
|
||||
PulsePPPacket *packet = data;
|
||||
|
||||
switch (packet->opcode) {
|
||||
case PULSE_PP_OPCODE_DATA:
|
||||
prv_pulse_pp_handle_data(&packet->data[0], length - sizeof(PulsePPPacket));
|
||||
break;
|
||||
case PULSE_PP_OPCODE_OPEN:
|
||||
prv_pulse_pp_send(PULSE_PP_OPCODE_OPEN, NULL, 0);
|
||||
prv_pulse_pp_transport_set_connected(true);
|
||||
break;
|
||||
case PULSE_PP_OPCODE_CLOSE:
|
||||
prv_pulse_pp_transport_set_connected(false);
|
||||
prv_pulse_pp_send(PULSE_PP_OPCODE_CLOSE, NULL, 0);
|
||||
break;
|
||||
default:
|
||||
prv_pulse_pp_send(PULSE_PP_OPCODE_UNKNOWN, &packet->opcode, sizeof(packet->opcode));
|
||||
break;
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue