-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add pico_low_power library #2852
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Draft
will-v-pi
wants to merge
106
commits into
raspberrypi:develop
Choose a base branch
from
will-v-pi:low-power-new
base: develop
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Draft
Changes from 100 commits
Commits
Show all changes
106 commits
Select commit
Hold shift + click to select a range
b8f699f
Separate linker scripts out into include files
will-v-pi 6dc06e6
Add customisable heap location, with pico_set_linker_script_var function
will-v-pi 727cabd
Add kitchen sink test of custom linker scripts
will-v-pi 3a83dc7
Separate out rp2_common and platform-specific linker script sections
will-v-pi 4b1a3ec
More de-duplication
will-v-pi ae97a22
Make overriding ram locations simpler
will-v-pi 3811e67
Make it possible to reference default locations in pico_set_linker_sc…
will-v-pi a20f86a
Add pico_add_linker_script_override_path to make overriding individua…
will-v-pi 6bd9e5b
Add simple overlay demo
will-v-pi 2bf8555
Add scripts to bazel build
will-v-pi fe2d56b
Move linker scripts out of crt0
will-v-pi 1bd7089
Make rp2350 text sections the default
will-v-pi 72adb67
Rename scripts include directories to standard_scripts and platform_s…
will-v-pi e47fe09
Move and add example to Bazel docs for changing linker scripts
will-v-pi 9c0ed0c
Add cc_library load to new bazel files
will-v-pi e44bdea
Add excludes.ld files for default memmap
will-v-pi dc3a2e8
Put mem functions in SRAM
will-v-pi afbc07e
transplant sleep2 onto develop
kilograham dffd4a5
Add sleep3 notes from meeting
liamfraser c81b09f
Make it compile and work with RP2040 and RP2350
will-v-pi 1807c25
Implement pstate functions
will-v-pi bcd2797
Fix pin_state functions on RP2350
will-v-pi b62de58
Fix hello_sleep_gpio on RP2040
will-v-pi abc6255
Add support for RP2040 dormant (using external RTC clock)
will-v-pi ed3716e
Pass low power state through powman reboot, so software knows what wa…
will-v-pi 5a2677c
Implement exclusive variable when sleeping
will-v-pi c3a3b7c
Demonstrate non-exclusive sleep
will-v-pi a1eb46f
Add skips of data_copy in arm crt0
will-v-pi 26b0a66
Add Risc-V crt0 data_cpy skip
will-v-pi fa1199e
Tidy up non-RP2040 defines
will-v-pi 1c65750
Redo memory handling
will-v-pi e2232d8
Add runtime init function to unpin xip cache that isn't persistent data
will-v-pi edb8838
Accept NULL pstate as default
will-v-pi 0e27c5b
Make persistent_data NOLOAD
will-v-pi 7bf2452
Persistent data now zeroed on non-persisted boot
will-v-pi 95eacfe
Add USB support and chars_available callback
will-v-pi 7e23f0b
Implement low_power_sleep_until_irq
will-v-pi 0559a34
Fix infinite loop with no persistent data
will-v-pi e65135f
Add encrypted sleep test
will-v-pi 7aa06f4
Update xip pinning load map
will-v-pi 49d03aa
Add support for sleep, dormant, and powman with tinyusb device and host
will-v-pi 10aa674
Use better runtime_init_rp2350_sleep_fix
will-v-pi 1806da6
Fix powman doc
will-v-pi 9cc19ed
Add bazel build, and some CMake function docs
will-v-pi c65b596
Fix config check
will-v-pi 7293ceb
Fix hardware_rosc bazel build
will-v-pi 575617e
Fix some kitchen sink errors
will-v-pi 7ce8c6a
fixups
will-v-pi 6509d94
Separate linker scripts out into include files
will-v-pi 9c1b67f
Add customisable heap location, with pico_set_linker_script_var function
will-v-pi 7fa5cbb
Add kitchen sink test of custom linker scripts
will-v-pi fe63e92
Remove pico_ld_constants and use pico_set_linker_script_var
will-v-pi 81a182b
Separate out rp2_common and platform-specific linker script sections
will-v-pi fba2c74
More de-duplication
will-v-pi f33d5a4
Make overriding ram locations simpler
will-v-pi 12c92b1
Make it possible to reference default locations in pico_set_linker_sc…
will-v-pi 1bcfac3
Add pico_add_linker_script_override_path to make overriding individua…
will-v-pi 609e666
Add simple overlay demo
will-v-pi 5343b6e
Add scripts to bazel build
will-v-pi 59fe386
Mark rtc_clksrc as rp2040 only in bazel build
will-v-pi cacafe6
Add some docs to low power functions
will-v-pi 1deea52
Run clk_sys from ROSC when dormant with DORMANT_CLOCK_SOURCE_LPOSC
will-v-pi 89276fa
Tidy up comments, and add more docs
will-v-pi 5ae8b76
Tidy up some comments
will-v-pi b521c11
Use gmtime_r instead of localtime_r on Clang
will-v-pi e464234
Apply documentation suggestions from code review to low_power.h
will-v-pi e51ca45
Apply suggestions from code review to low_power.c and low_power.h
will-v-pi fa6064c
Review fixups
will-v-pi 298fd2a
Fix some returns
will-v-pi 77e9e40
Add some doxygen to bitset.h, and tidy up some macros
will-v-pi d249a90
Rename clock_dest_set_... to clock_dest_bitset_... to avoid confusing…
will-v-pi b6589e7
Update copyright years
will-v-pi 50a241b
Apply some suggestions from code review
will-v-pi 97705aa
Improve rosc docs, and add RP2350 notes/asserts
will-v-pi 8b9d9ec
Rename standard_scripts and platform_scripts to script_include
will-v-pi 91c3a9a
Move pico_platform_link stuff into pico_plaftorm
will-v-pi 614f7f0
Remove rigidity from linker include paths
will-v-pi da23cf4
Rename all linker scripts intended to be included to .incl
will-v-pi 780c05e
Separate into section_... files which do only contain one section, an…
will-v-pi 2e7ca67
Add section_extra files to make adding extra sections simpler
will-v-pi 4180427
Fix comments, and add some more extra files
will-v-pi c122bf7
Add generated override files - currently unused, but can be overridde…
will-v-pi ea8320b
pico_add_linker_script_override_path can now be called after target_l…
will-v-pi ad35ad8
Add extra post_platform_end sections
will-v-pi 8e3aca5
review fixups
will-v-pi e9e9a09
Fix bazel PICO_DEFAULT_LINKER_SCRIPT comment
will-v-pi 519544e
Add PICO_DEFAULT_BINARY_TYPE to Bazel
will-v-pi 3f0615d
Fix PICO_DEFAULT_BINARY_TYPE descriptions
will-v-pi a26a42b
Add azel pico_set_binary_type transition, to allow setting binary typ…
will-v-pi df68b1e
Refactor bazel functionality following review
will-v-pi 41fd36e
Add kitchen_sink_ram_section and kitchen_sink_simple_overlay tests to…
will-v-pi ea9b114
Some tidyups
will-v-pi 7b040da
Merge branch 'include-linker-scripts' into low-power-new
will-v-pi 09e2857
Fixup merge
will-v-pi b144c1a
Merge branch 'develop' into low-power-new
will-v-pi df27c7b
Merge remote-tracking branch 'origin/develop' into low-power-new
will-v-pi b4d9929
some bitset cleanup
kilograham 500de3c
oops
kilograham 64639f7
more cleanup
kilograham d1cdadb
argh
kilograham 24d575f
Add note about accuracy to rosc functions
will-v-pi 79f74b2
Merge remote-tracking branch 'origin/develop' into low-power-new
will-v-pi 34a6c3a
Update memmap annotations
will-v-pi 95e8a9c
Fix the rename from bitset.h to fixed_bitset.h
will-v-pi 925e79b
Remove unused hardware_rosc functions
will-v-pi 032be3f
Update example privateaes.bin file
will-v-pi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,26 @@ | ||
| /* | ||
| * Copyright (c) 2026 Raspberry Pi (Trading) Ltd. | ||
| * | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| */ | ||
|
|
||
| #include "include/pico/util/fixed_bitset.h" | ||
|
|
||
| fixed_bitset_t *fixed_bitset_flip_all(fixed_bitset_t *bitset) { | ||
| check_fixed_bitset(bitset); | ||
| for (uint i=0;i<bitset->word_size;i++) { | ||
| bitset->words[i] = ~bitset->words[i]; | ||
| } | ||
| return bitset; | ||
| } | ||
|
|
||
| bool fixed_bitset_is_empty(fixed_bitset_t *bitset) { | ||
| check_fixed_bitset(bitset); | ||
| int i=0; | ||
| for (i=0;i<bitset->word_size-1;i++) { | ||
| if (bitset->words[i]) return false; | ||
| } | ||
| // we don't guarantee that bits above the size aren't set, so mask them off | ||
| return !(i && (bitset->words[i] << (32u -(bitset->size & 31u)))); | ||
| } | ||
|
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,283 @@ | ||
| /* | ||
| * Copyright (c) 2026 Raspberry Pi (Trading) Ltd. | ||
| * | ||
| * SPDX-License-Identifier: BSD-3-Clause | ||
| */ | ||
|
|
||
| #ifndef _PICO_UTIL_FIXED_BITSET_H | ||
| #define _PICO_UTIL_FIXED_BITSET_H | ||
|
|
||
| #include "pico.h" | ||
|
|
||
| /** \file fixed_bitset.h | ||
| * \defgroup fixed_bitset fixed_bitset | ||
| * \brief Simple fixed-size bitset implementation | ||
| * | ||
| * \ingroup pico_util | ||
| */ | ||
|
|
||
| #ifdef __cplusplus | ||
| extern "C" { | ||
| #endif | ||
|
|
||
| typedef struct { | ||
| uint16_t size; \ | ||
| uint16_t word_size; \ | ||
| uint32_t words[]; | ||
| } fixed_bitset_t; | ||
|
|
||
| /*! \brief Macro used to define a fixed-size bitset of a given size | ||
| * \ingroup fixed_bitset | ||
| * This macro is used to declare the type of a fixed-size bitset. It is used as follows: | ||
| * ``` | ||
| * typedef fixed_bitset_type_t(17) my_bitset_t; | ||
| * ``` | ||
| * will define a new bitset type called `my_bitset_t` that can hold 17 boolean values. | ||
| * | ||
| * The type can be used as `my_bitset_t bitset;` to declare a new bitset. | ||
| * | ||
| * \param N the number of boolean values in the bitset | ||
| */ | ||
| #define fixed_bitset_type(N) union { \ | ||
| fixed_bitset_t bitset; \ | ||
| struct { \ | ||
| uint16_t size; \ | ||
| uint16_t word_size; \ | ||
| uint32_t words[((N) + 31) / 32]; \ | ||
| } sized_bitset; \ | ||
| } | ||
| #define fixed_bitset_sizeof_for(N) ((((N) + 63u) / 32u) * 4u) | ||
|
|
||
| /*! \brief Macro used to create a bitset with all bits set to a value | ||
| * \ingroup fixed_bitset | ||
| * \param type the type of the bitset | ||
| * \param N the number of bits in the bitset | ||
| * \param fill the value to set the bits to (0 or 1) | ||
| * \return the bitset | ||
| */ | ||
| #define fixed_bitset_with_fill(type, N, fill) ({ type bitset; fixed_bitset_init(&bitset, type, N, fill); bitset; }) | ||
|
|
||
| // Quick test that the bitset macros give the correct size | ||
| extern fixed_bitset_type(32) __not_real_bitset32; | ||
| extern fixed_bitset_type(33) __not_real_bitset33; | ||
| static_assert(sizeof(__not_real_bitset32) == fixed_bitset_sizeof_for(1),""); | ||
| static_assert(sizeof(__not_real_bitset33) == fixed_bitset_sizeof_for(37), ""); | ||
| static_assert(sizeof(__not_real_bitset33) != fixed_bitset_sizeof_for(1), ""); | ||
|
|
||
| /*! \brief Initialize a bitset | ||
| * \ingroup fixed_bitset | ||
| * \param ptr the bitset to initialize | ||
| * \param type the type of the bitset | ||
| * \param N the number of bits in the bitset | ||
| * \param fill the value to fill the bitset with (0 or 1) | ||
| */ | ||
| #define fixed_bitset_init(ptr, type, N, fill) ({ \ | ||
| assert(sizeof(type) == fixed_bitset_sizeof_for(N)); \ | ||
| __unused type *type_check = ptr; \ | ||
| (ptr)->bitset.size = N; \ | ||
| (ptr)->bitset.word_size = ((N) + 31u) / 32u; \ | ||
| __builtin_memset(&(ptr)->bitset.words, (fill) ? 0xff : 0, (ptr)->bitset.word_size * sizeof(uint32_t)); \ | ||
| }) | ||
|
|
||
| /*! \brief Get the size of the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset to get the size of | ||
| * \return the size of the bitset | ||
| */ | ||
| static inline uint fixed_bitset_size(const fixed_bitset_t *bitset) { | ||
| return bitset->size; | ||
| } | ||
|
|
||
| /*! \brief Get the size of the bitset in words | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset to get the size of | ||
| * \return the size of the bitset in words | ||
| */ | ||
| static inline uint fixed_bitset_word_size(const fixed_bitset_t *bitset) { | ||
| return bitset->word_size; | ||
| } | ||
|
|
||
| /*! \brief Check that the bitset is valid | ||
| * \ingroup fixed_bitset | ||
| * This function will assert if the bitset is not valid. | ||
| * \param bitset the bitset to check | ||
| */ | ||
| static inline void check_fixed_bitset(const fixed_bitset_t *bitset) { | ||
| assert(bitset->word_size == (bitset->size + 31) / 32); | ||
| } | ||
|
|
||
| /*! \brief Write a word in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset to write to | ||
| * \param word_num the word number to write to | ||
| * \param value the value to write to the word | ||
| * \return the bitset | ||
| */ | ||
| static inline fixed_bitset_t *fixed_bitset_write_word(fixed_bitset_t *bitset, uint word_num, uint32_t value) { | ||
| check_fixed_bitset(bitset); | ||
| if (word_num < fixed_bitset_word_size(bitset)) { | ||
| bitset->words[word_num] = value; | ||
| } | ||
| return bitset; | ||
| } | ||
|
|
||
| /*! \brief Read a word in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \param word_num the word number to read from | ||
| * \return the value of the word | ||
| */ | ||
| static inline uint32_t fixed_bitset_read_word(const fixed_bitset_t *bitset, uint word_num) { | ||
| check_fixed_bitset(bitset); | ||
| if (word_num < fixed_bitset_word_size(bitset)) { | ||
| return bitset->words[word_num]; | ||
| } | ||
| return 0; | ||
| } | ||
|
|
||
| /*! \brief Clear all bits in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \return the bitset | ||
| */ | ||
| static inline fixed_bitset_t *fixed_bitset_clear_all(fixed_bitset_t *bitset) { | ||
| check_fixed_bitset(bitset); | ||
| __builtin_memset(bitset->words, 0, bitset->word_size * sizeof(uint32_t)); | ||
| return bitset; | ||
| } | ||
|
|
||
| /*! \brief Set all bits in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \return the bitset | ||
| */ | ||
| static inline fixed_bitset_t *fixed_bitset_set_all(fixed_bitset_t *bitset) { | ||
| check_fixed_bitset(bitset); | ||
| __builtin_memset(bitset->words, 0xff, bitset->word_size * sizeof(uint32_t)); | ||
| return bitset; | ||
| } | ||
|
|
||
| /*! \brief Flip all bits in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \return the bitset | ||
| */ | ||
| fixed_bitset_t *fixed_bitset_flip_all(fixed_bitset_t *bitset); | ||
|
|
||
| /*! \brief Determine if bitset is empty | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \return true if not bits are set | ||
| */ | ||
| bool fixed_bitset_is_empty(fixed_bitset_t *bitset); | ||
|
|
||
| /*! \brief Set a single bit in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \param bit_index the bit to set | ||
| * \return the bitset | ||
| */ | ||
| static inline fixed_bitset_t *fixed_bitset_set(fixed_bitset_t *bitset, uint bit_index) { | ||
| check_fixed_bitset(bitset); | ||
| if (bit_index < bitset->size) { | ||
| bitset->words[bit_index / 32u] |= 1u << (bit_index % 32u); | ||
| } | ||
| return bitset; | ||
| } | ||
|
|
||
| /*! \brief Clear a single bit in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \param bit_index the bit to clear | ||
| * \return the bitset | ||
| */ | ||
| static inline fixed_bitset_t *fixed_bitset_clear(fixed_bitset_t *bitset, uint bit_index) { | ||
| check_fixed_bitset(bitset); | ||
| if (bit_index < bitset->size) { | ||
| bitset->words[bit_index / 32u] &= ~(1u << (bit_index % 32u)); | ||
| } | ||
| return bitset; | ||
| } | ||
|
|
||
| /*! \brief Flip a single bit in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \param bit_index the bit to flip | ||
| * \return the bitset | ||
| */ | ||
| static inline fixed_bitset_t *fixed_bitset_flip(fixed_bitset_t *bitset, uint bit_index) { | ||
| check_fixed_bitset(bitset); | ||
| if (bit_index < bitset->size) { | ||
| bitset->words[bit_index / 32u] ^= 1u << (bit_index % 32u); | ||
| } | ||
| return bitset; | ||
| } | ||
|
|
||
|
|
||
| /*! \brief Get the value of a single bit in the bitset | ||
| * \ingroup fixed_bitset | ||
| * \param bitset the bitset | ||
| * \param bit_index the bit to get the value of | ||
| * \return the value of the bit | ||
| */ | ||
| static inline bool fixed_bitset_get(const fixed_bitset_t *bitset, uint bit_index) { | ||
| check_fixed_bitset(bitset); | ||
| assert(bit_index < bitset->size); | ||
| // if (bit < bitset->size) { | ||
| return bitset->words[bit_index / 32u] & (1u << (bit_index % 32u)); | ||
| // } | ||
| return false; | ||
| } | ||
|
|
||
| /*! \brief Check if two bitsets are equal | ||
| * \ingroup fixed_bitset | ||
| * \param bitset1 the first bitset to check | ||
| * \param bitset2 the second bitset to check | ||
| * \return true if the bitsets are equal, false otherwise | ||
| */ | ||
| static inline bool fixed_bitset_equal(const fixed_bitset_t *bitset1, const fixed_bitset_t *bitset2) { | ||
| check_fixed_bitset(bitset1); | ||
| check_fixed_bitset(bitset2); | ||
| assert(bitset1->size == bitset2->size); | ||
| return __builtin_memcmp(bitset1->words, bitset2->words, bitset1->word_size * sizeof(uint32_t)) == 0; | ||
| } | ||
|
|
||
| #if 0 // not currently used | ||
| typedef uint32_t tiny_ordinal_list_t; // ordinals must be 0->255 | ||
| typedef uint64_t small_ordinal_list_t; // ordinals must be 0->255 | ||
| #define ordinal_list_empty() 0 | ||
| #define ordinal_list_of1(v) (1u | ((v) << 8)) | ||
| #define ordinal_list_of2(v1, v2) (2u | ((v1) << 8) | ((v2) << 16)) | ||
| #define ordinal_list_of3(v1, v2, v3) (3u | ((v1) << 8) | ((v2) << 16) | (((v3) << 24))) | ||
| #define ordinal_list_of4(v1, v2, v3, v4) (4u | ((v1) << 8) | ((v2) << 16) | (((v3) << 24)) | (((uint64_t)(v4)) << 32)) | ||
| #define ordinal_list_of5(v1, v2, v3, v4, v5) (5u | ((v1) << 8) | ((v2) << 16) | (((v3) << 24)) | (((uint64_t)((v4) | ((v5)<<8u))) << 32)) | ||
|
|
||
| #define small_ordinal_list_foreach(bitarray, x) ({ \ | ||
| for(uint _i=1;_i<=((bitarray)&0xffu);_i++) { \ | ||
| uint bit = (uint8_t)((bitarray) >> (8 * _i)); \ | ||
| x; \ | ||
| } \ | ||
| }) | ||
|
|
||
| static inline fixed_bitset_t *fixed_bitset_set_bits(fixed_bitset_t *bitset, small_ordinal_list_t list) { | ||
| small_ordinal_list_foreach(list, fixed_bitset_set(bitset, bit)); | ||
| return bitset; | ||
| } | ||
|
|
||
| static inline fixed_bitset_t *fixed_bitset_clear_bits(fixed_bitset_t *bitset, small_ordinal_list_t list) { | ||
| small_ordinal_list_foreach(list, fixed_bitset_clear(bitset, bit)); | ||
| return bitset; | ||
| } | ||
|
|
||
|
|
||
| #define fixed_bitset_init_with_bits(ptr, type, N, list) ({ \ | ||
| /* not this performs checks */ \ | ||
| fixed_bitset_init(ptr, type, N, 0); \ | ||
| fixed_bitset_set_bits(&(ptr)->bitset, list); \ | ||
| }) | ||
|
|
||
| #endif | ||
| #ifdef __cplusplus | ||
| } | ||
| #endif | ||
| #endif | ||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.