diff --git a/src/ble-pybricks-service/actions.ts b/src/ble-pybricks-service/actions.ts index cda33a01..d6c989b0 100644 --- a/src/ble-pybricks-service/actions.ts +++ b/src/ble-pybricks-service/actions.ts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2021-2024 The Pybricks Authors +// Copyright (c) 2021-2025 The Pybricks Authors // // Actions for Bluetooth Low Energy Pybricks service @@ -85,11 +85,13 @@ export const sendLegacyStartReplCommand = createAction((id: number) => ({ * * @since Pybricks Profile v1.4.0 */ -export const sendStartUserProgramCommand = createAction((id: number, slot: number) => ({ - type: 'blePybricksServiceCommand.action.sendStartUserProgram', - id, - slot, -})); +export const sendStartUserProgramCommand = createAction( + (id: number, slot: number | null) => ({ + type: 'blePybricksServiceCommand.action.sendStartUserProgram', + id, + slot, + }), +); /** * Action that requests to write user program metadata. diff --git a/src/ble-pybricks-service/protocol.ts b/src/ble-pybricks-service/protocol.ts index 773aa25a..4e8edd1a 100644 --- a/src/ble-pybricks-service/protocol.ts +++ b/src/ble-pybricks-service/protocol.ts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020-2024 The Pybricks Authors +// Copyright (c) 2020-2025 The Pybricks Authors // // Definitions related to the Pybricks Bluetooth low energy GATT service. @@ -114,12 +114,20 @@ export function createStopUserProgramCommand(): Uint8Array { * Parameters: * - slot: Program identifier (one byte). Slots 0--127 are reserved for * downloaded user programs. Slots 128--255 are for builtin user programs. + * If null, the hub will start the program slot selected on the hub. * * @since Pybricks Profile v1.4.0 */ export function createStartUserProgramCommand( - slot: number | BuiltinProgramId, + slot: number | BuiltinProgramId | null, ): Uint8Array { + // Omit optional slot id to start currently active slot. + if (slot === null) { + const msg = new Uint8Array(1); + msg[0] = CommandType.StartUserProgram; + return msg; + } + const msg = new Uint8Array(2); msg[0] = CommandType.StartUserProgram; msg[1] = slot; diff --git a/src/hub/actions.ts b/src/hub/actions.ts index 422b630e..ac1d7de1 100644 --- a/src/hub/actions.ts +++ b/src/hub/actions.ts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020-2024 The Pybricks Authors +// Copyright (c) 2020-2025 The Pybricks Authors import { createAction } from '../actions'; import { FileFormat } from '../ble-pybricks-service/protocol'; @@ -26,7 +26,7 @@ export const downloadAndRun = createAction( fileFormat: FileFormat | null, useLegacyDownload: boolean, useLegacyStartUserProgram: boolean, - slot: number, + slot: number | null, ) => ({ type: 'hub.action.downloadAndRun', fileFormat, diff --git a/src/hub/sagas.test.ts b/src/hub/sagas.test.ts index 552b3918..5a6a9dc2 100644 --- a/src/hub/sagas.test.ts +++ b/src/hub/sagas.test.ts @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020-2024 The Pybricks Authors +// Copyright (c) 2020-2025 The Pybricks Authors import { AsyncSaga } from '../../test'; import { alertsShowAlert } from '../alerts/actions'; @@ -38,7 +38,7 @@ describe('downloadAndRun', () => { saga.updateState({ editor: { isReady: true } }); - saga.put(downloadAndRun(FileFormat.Mpy5, true, true, 0)); + saga.put(downloadAndRun(FileFormat.Mpy5, true, true, null)); // first, it gets the value from the current editor const editorValueAction = await saga.take(); diff --git a/src/toolbar/buttons/run/RunButton.test.tsx b/src/toolbar/buttons/run/RunButton.test.tsx index 02edae82..010d0884 100644 --- a/src/toolbar/buttons/run/RunButton.test.tsx +++ b/src/toolbar/buttons/run/RunButton.test.tsx @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2022-2024 The Pybricks Authors +// Copyright (c) 2022-2025 The Pybricks Authors import { act, cleanup } from '@testing-library/react'; import React from 'react'; @@ -43,7 +43,7 @@ test.each([ FileFormat.MultiMpy6, legacyDownload, legacyStartUserProgram, - 0, + null, ), ); }, diff --git a/src/toolbar/buttons/run/RunButton.tsx b/src/toolbar/buttons/run/RunButton.tsx index a7ce63c0..7dad40e6 100644 --- a/src/toolbar/buttons/run/RunButton.tsx +++ b/src/toolbar/buttons/run/RunButton.tsx @@ -1,5 +1,5 @@ // SPDX-License-Identifier: MIT -// Copyright (c) 2020-2024 The Pybricks Authors +// Copyright (c) 2020-2025 The Pybricks Authors import React from 'react'; import { useDispatch } from 'react-redux'; @@ -48,7 +48,7 @@ const RunButton: React.FunctionComponent = ({ id }) => { preferredFileFormat, useLegacyDownload, useLegacyStartUserProgram, - 0, // No slot UI yet + null, // No slot UI yet, downloading to active hub slot ), ) }