From 5126263f91ead7d807381a6d8d5135e5f8dfb0b8 Mon Sep 17 00:00:00 2001 From: Phil Howard Date: Mon, 9 Oct 2023 17:36:13 +0100 Subject: [PATCH] Badger2038/2040W: Remove old/incompatible examples. Badger now lives at: https://github.com/pimoroni/badger2040 --- micropython/examples/badger2040/README.md | 101 -- .../289-0-wind-in-the-willows-abridged.txt | 1341 ----------------- .../badger2040/assets/badge_image.png | Bin 3498 -> 0 bytes .../examples/badger2040/assets/badgerpunk.png | Bin 36468 -> 0 bytes .../examples/badger2040/assets/boot.py | 6 - .../badger2040/assets/launchericons.png | Bin 9981 -> 0 bytes micropython/examples/badger2040/badge.py | 183 --- micropython/examples/badger2040/badger_os.py | 183 --- micropython/examples/badger2040/battery.py | 163 -- .../examples/badger2040/button_test.py | 67 - micropython/examples/badger2040/clock.py | 154 -- micropython/examples/badger2040/conway.py | 215 --- micropython/examples/badger2040/ebook.py | 263 ---- micropython/examples/badger2040/fonts.py | 134 -- micropython/examples/badger2040/help.py | 42 - micropython/examples/badger2040/image.py | 127 -- micropython/examples/badger2040/info.py | 42 - micropython/examples/badger2040/launcher.py | 241 --- micropython/examples/badger2040/led.py | 15 - micropython/examples/badger2040/list.py | 315 ---- .../badger2040/micropython-builtins.cmake | 55 - .../examples/badger2040/pin_interrupt.py | 65 - micropython/examples/badger2040/qrgen.py | 155 -- .../examples/badger2040w/WIFI_CONFIG.py | 3 - .../examples/badger2040w/badges/badge.jpg | Bin 7878 -> 0 bytes .../examples/badger2040w/badges/badge.txt | 7 - .../289-0-wind-in-the-willows-abridged.txt | 1341 ----------------- .../examples/badger2040w/examples/badge.py | 172 --- .../examples/badger2040w/examples/clock.py | 94 -- .../examples/badger2040w/examples/ebook.py | 244 --- .../examples/badger2040w/examples/fonts.py | 129 -- .../examples/badger2040w/examples/help.py | 41 - .../badger2040w/examples/icon-badge.jpg | Bin 1793 -> 0 bytes .../badger2040w/examples/icon-clock.jpg | Bin 1928 -> 0 bytes .../badger2040w/examples/icon-ebook.jpg | Bin 1623 -> 0 bytes .../badger2040w/examples/icon-fonts.jpg | Bin 1195 -> 0 bytes .../badger2040w/examples/icon-help.jpg | Bin 2151 -> 0 bytes .../badger2040w/examples/icon-image.jpg | Bin 1367 -> 0 bytes .../badger2040w/examples/icon-info.jpg | Bin 2062 -> 0 bytes .../badger2040w/examples/icon-list.jpg | Bin 1548 -> 0 bytes .../badger2040w/examples/icon-net-info.jpg | Bin 1485 -> 0 bytes .../badger2040w/examples/icon-news.jpg | Bin 1987 -> 0 bytes .../badger2040w/examples/icon-qrgen.jpg | Bin 2593 -> 0 bytes .../badger2040w/examples/icon-weather.jpg | Bin 1591 -> 0 bytes .../examples/badger2040w/examples/image.py | 119 -- .../examples/badger2040w/examples/info.py | 44 - .../examples/badger2040w/examples/list.py | 312 ---- .../examples/badger2040w/examples/net_info.py | 48 - .../examples/badger2040w/examples/news.py | 215 --- .../examples/badger2040w/examples/qrgen.py | 139 -- .../examples/badger2040w/examples/weather.py | 106 -- .../examples/badger2040w/icons/icon-cloud.jpg | Bin 2405 -> 0 bytes .../examples/badger2040w/icons/icon-rain.jpg | Bin 3324 -> 0 bytes .../examples/badger2040w/icons/icon-snow.jpg | Bin 4008 -> 0 bytes .../examples/badger2040w/icons/icon-storm.jpg | Bin 3055 -> 0 bytes .../examples/badger2040w/icons/icon-sun.jpg | Bin 3117 -> 0 bytes .../examples/badger2040w/images/README.txt | 3 - .../badger2040w/images/badgerpunk.jpg | Bin 9264 -> 0 bytes micropython/examples/badger2040w/launcher.py | 183 --- .../examples/badger2040w/lib/badger2040w.py | 181 --- .../examples/badger2040w/lib/badger_os.py | 188 --- .../badger2040w/lib/network_manager.py | 108 -- micropython/examples/badger2040w/main.py | 1 - micropython/examples/badger2040w/readme.md | 113 -- .../examples/badger2040w/uf2-manifest.txt | 10 - 65 files changed, 7668 deletions(-) delete mode 100644 micropython/examples/badger2040/assets/289-0-wind-in-the-willows-abridged.txt delete mode 100644 micropython/examples/badger2040/assets/badge_image.png delete mode 100644 micropython/examples/badger2040/assets/badgerpunk.png delete mode 100644 micropython/examples/badger2040/assets/boot.py delete mode 100644 micropython/examples/badger2040/assets/launchericons.png delete mode 100644 micropython/examples/badger2040/badge.py delete mode 100644 micropython/examples/badger2040/badger_os.py delete mode 100644 micropython/examples/badger2040/battery.py delete mode 100644 micropython/examples/badger2040/button_test.py delete mode 100644 micropython/examples/badger2040/clock.py delete mode 100644 micropython/examples/badger2040/conway.py delete mode 100644 micropython/examples/badger2040/ebook.py delete mode 100644 micropython/examples/badger2040/fonts.py delete mode 100644 micropython/examples/badger2040/help.py delete mode 100644 micropython/examples/badger2040/image.py delete mode 100644 micropython/examples/badger2040/info.py delete mode 100644 micropython/examples/badger2040/launcher.py delete mode 100644 micropython/examples/badger2040/led.py delete mode 100644 micropython/examples/badger2040/list.py delete mode 100644 micropython/examples/badger2040/micropython-builtins.cmake delete mode 100644 micropython/examples/badger2040/pin_interrupt.py delete mode 100644 micropython/examples/badger2040/qrgen.py delete mode 100644 micropython/examples/badger2040w/WIFI_CONFIG.py delete mode 100644 micropython/examples/badger2040w/badges/badge.jpg delete mode 100644 micropython/examples/badger2040w/badges/badge.txt delete mode 100644 micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt delete mode 100644 micropython/examples/badger2040w/examples/badge.py delete mode 100644 micropython/examples/badger2040w/examples/clock.py delete mode 100644 micropython/examples/badger2040w/examples/ebook.py delete mode 100644 micropython/examples/badger2040w/examples/fonts.py delete mode 100644 micropython/examples/badger2040w/examples/help.py delete mode 100644 micropython/examples/badger2040w/examples/icon-badge.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-clock.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-ebook.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-fonts.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-help.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-image.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-info.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-list.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-net-info.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-news.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-qrgen.jpg delete mode 100644 micropython/examples/badger2040w/examples/icon-weather.jpg delete mode 100644 micropython/examples/badger2040w/examples/image.py delete mode 100644 micropython/examples/badger2040w/examples/info.py delete mode 100644 micropython/examples/badger2040w/examples/list.py delete mode 100644 micropython/examples/badger2040w/examples/net_info.py delete mode 100644 micropython/examples/badger2040w/examples/news.py delete mode 100644 micropython/examples/badger2040w/examples/qrgen.py delete mode 100644 micropython/examples/badger2040w/examples/weather.py delete mode 100644 micropython/examples/badger2040w/icons/icon-cloud.jpg delete mode 100644 micropython/examples/badger2040w/icons/icon-rain.jpg delete mode 100644 micropython/examples/badger2040w/icons/icon-snow.jpg delete mode 100644 micropython/examples/badger2040w/icons/icon-storm.jpg delete mode 100644 micropython/examples/badger2040w/icons/icon-sun.jpg delete mode 100644 micropython/examples/badger2040w/images/README.txt delete mode 100644 micropython/examples/badger2040w/images/badgerpunk.jpg delete mode 100644 micropython/examples/badger2040w/launcher.py delete mode 100644 micropython/examples/badger2040w/lib/badger2040w.py delete mode 100644 micropython/examples/badger2040w/lib/badger_os.py delete mode 100644 micropython/examples/badger2040w/lib/network_manager.py delete mode 100644 micropython/examples/badger2040w/main.py delete mode 100644 micropython/examples/badger2040w/readme.md delete mode 100644 micropython/examples/badger2040w/uf2-manifest.txt diff --git a/micropython/examples/badger2040/README.md b/micropython/examples/badger2040/README.md index a49fcc16..f5df6482 100644 --- a/micropython/examples/badger2040/README.md +++ b/micropython/examples/badger2040/README.md @@ -1,104 +1,3 @@ # Badger 2040 Examples :warning: This code has been deprecated in favour of a dedicated Badger 2040 project: https://github.com/pimoroni/badger2040 - -- [Function Examples](#function-examples) - - [Battery](#battery) - - [Button Test](#button-test) - - [LED](#led) - - [Pin interrupt](#pin-interrupt) -- [Application Examples](#application-examples) - - [Badge](#badge) - - [Checklist](#checklist) - - [Clock](#clock) - - [E-Book](#e-book) - - [Fonts](#fonts) - - [Image](#image) - - [QR gen](#qr-gen) - - [Launcher](#launcher) - - [Conway](#conway) - - -## Function Examples - -### Battery -[battery.py](battery.py) - -An example of how to read the battery voltage and display a battery level indicator. - -### Button Test -[button_test.py](button_test.py) - -An example of how to read Badger2040's buttons and display a unique message for each. - -### LED -[led.py](led.py) - -Blinks Badger's LED on and off. - -### Pin interrupt -[pin_interrupt.py](pin_interrupt.py) - -An example of drawing text and graphics and using the buttons. - -## Application Examples - -### Badge -[badge.py](badge.py) - -Create your own name badge! This application looks for two files on your MicroPython drive: -* `badge.txt` - A text file containing 6 lines, corresponding to the 6 different pieces of text on the badge -* `badge-image.bin` - A 104x128px 1-bit colour depth image to display alongside the text. You can use `examples/badger2040/image_converter/convert.py` to convert them: - -```shell -python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png -``` - -### Checklist -[list.py](list.py) - -A checklist application, letting you navigate through items and tick each of them off. - -* `checklist.txt` - A text file containing the titles of items for the list. - -### Clock -[clock.py](clock.py) - -A simple clock showing the time and date, that uses the E Ink's fast speed to update every second. - -### E-Book -[ebook.py](ebook.py) - -A mini text file e-reader. Comes pre-loaded with an excerpt of The Wind In the Willows. - -### Fonts -[fonts.py](fonts.py) - -A demonstration of the various fonts that can be used in your programs. - -### Image -[image.py](image.py) - -An image gallery. Displays and lets you cycle through any images stored within the MicroPython device's `/images` directory. Images must be 296x128 pixels with 1-bit colour depth. You can use `examples/badger2040/image_converter/convert.py` to convert them: - -```shell -python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png -``` - -### QR gen -[qrgen.py](qrgen.py) - -Displays and lets you cycle through multiple QR codes, with configuration stored in text files within the MicroPython device's `/qrcodes` directory. - -- `/qrcodes/qrcode.txt` - A text file containing 9 lines. The first line should be a URL which will be converted into and displayed as a QR code. Up to 8 more lines of information can be added, which will be shown as plain text to the right of the QR code. -- `/qrcodes/*.txt` - additional text files can be created using the same format. All text files can be cycled through. - -### Launcher -[launcher.py](launcher.py) - -A launcher-style application, providing a menu of other applications that can be loaded, as well as information such as battery level. - -### Conway -[conway.py](conway.py) - -Conway's classic Game of Life, implemented on the Badger. Note: this application is *not* linked from the Launcher by default - it can be run directly using Thonny or your MicroPython editor of choice, or you can modify the Launcher to add it (you'll want to update `launchericons.png` as well) diff --git a/micropython/examples/badger2040/assets/289-0-wind-in-the-willows-abridged.txt b/micropython/examples/badger2040/assets/289-0-wind-in-the-willows-abridged.txt deleted file mode 100644 index f6243fd9..00000000 --- a/micropython/examples/badger2040/assets/289-0-wind-in-the-willows-abridged.txt +++ /dev/null @@ -1,1341 +0,0 @@ -The Project Gutenberg eBook of The Wind in the Willows, by Kenneth Grahame - -This eBook is for the use of anyone anywhere in the United States and -most other parts of the world at no cost and with almost no restrictions -whatsoever. You may copy it, give it away or re-use it under the terms -of the Project Gutenberg License included with this eBook or online at -www.gutenberg.org. If you are not located in the United States, you -will have to check the laws of the country where you are located before -using this eBook. - -Title: The Wind in the Willows - -Author: Kenneth Grahame - -Release Date: July, 1995 [eBook #289] -[Most recently updated: May 15, 2021] - -Language: English - -Character set encoding: UTF-8 - -Produced by: Mike Lough and David Widger - -*** START OF THE PROJECT GUTENBERG EBOOK THE WIND IN THE WILLOWS *** - -[Illustration] - - - - -The Wind in the Willows - -by Kenneth Grahame - -Author Of “The Golden Age,” “Dream Days,” Etc. - - -Contents - - CHAPTER I. THE RIVER BANK - CHAPTER II. THE OPEN ROAD - - - - -I. -THE RIVER BANK - - -The Mole had been working very hard all the morning, spring-cleaning -his little home. First with brooms, then with dusters; then on ladders -and steps and chairs, with a brush and a pail of whitewash; till he had -dust in his throat and eyes, and splashes of whitewash all over his -black fur, and an aching back and weary arms. Spring was moving in the -air above and in the earth below and around him, penetrating even his -dark and lowly little house with its spirit of divine discontent and -longing. It was small wonder, then, that he suddenly flung down his -brush on the floor, said “Bother!” and “O blow!” and also “Hang -spring-cleaning!” and bolted out of the house without even waiting to -put on his coat. Something up above was calling him imperiously, and he -made for the steep little tunnel which answered in his case to the -gravelled carriage-drive owned by animals whose residences are nearer -to the sun and air. So he scraped and scratched and scrabbled and -scrooged and then he scrooged again and scrabbled and scratched and -scraped, working busily with his little paws and muttering to himself, -“Up we go! Up we go!” till at last, pop! his snout came out into the -sunlight, and he found himself rolling in the warm grass of a great -meadow. - -“This is fine!” he said to himself. “This is better than whitewashing!” -The sunshine struck hot on his fur, soft breezes caressed his heated -brow, and after the seclusion of the cellarage he had lived in so long -the carol of happy birds fell on his dulled hearing almost like a -shout. Jumping off all his four legs at once, in the joy of living and -the delight of spring without its cleaning, he pursued his way across -the meadow till he reached the hedge on the further side. - -“Hold up!” said an elderly rabbit at the gap. “Sixpence for the -privilege of passing by the private road!” He was bowled over in an -instant by the impatient and contemptuous Mole, who trotted along the -side of the hedge chaffing the other rabbits as they peeped hurriedly -from their holes to see what the row was about. “Onion-sauce! -Onion-sauce!” he remarked jeeringly, and was gone before they could -think of a thoroughly satisfactory reply. Then they all started -grumbling at each other. “How _stupid_ you are! Why didn’t you tell -him——” “Well, why didn’t _you_ say——” “You might have reminded him——” -and so on, in the usual way; but, of course, it was then much too late, -as is always the case. - -It all seemed too good to be true. Hither and thither through the -meadows he rambled busily, along the hedgerows, across the copses, -finding everywhere birds building, flowers budding, leaves -thrusting—everything happy, and progressive, and occupied. And instead -of having an uneasy conscience pricking him and whispering “whitewash!” -he somehow could only feel how jolly it was to be the only idle dog -among all these busy citizens. After all, the best part of a holiday is -perhaps not so much to be resting yourself, as to see all the other -fellows busy working. - -He thought his happiness was complete when, as he meandered aimlessly -along, suddenly he stood by the edge of a full-fed river. Never in his -life had he seen a river before—this sleek, sinuous, full-bodied -animal, chasing and chuckling, gripping things with a gurgle and -leaving them with a laugh, to fling itself on fresh playmates that -shook themselves free, and were caught and held again. All was a-shake -and a-shiver—glints and gleams and sparkles, rustle and swirl, chatter -and bubble. The Mole was bewitched, entranced, fascinated. By the side -of the river he trotted as one trots, when very small, by the side of a -man who holds one spell-bound by exciting stories; and when tired at -last, he sat on the bank, while the river still chattered on to him, a -babbling procession of the best stories in the world, sent from the -heart of the earth to be told at last to the insatiable sea. - -As he sat on the grass and looked across the river, a dark hole in the -bank opposite, just above the water’s edge, caught his eye, and -dreamily he fell to considering what a nice snug dwelling-place it -would make for an animal with few wants and fond of a bijou riverside -residence, above flood level and remote from noise and dust. As he -gazed, something bright and small seemed to twinkle down in the heart -of it, vanished, then twinkled once more like a tiny star. But it could -hardly be a star in such an unlikely situation; and it was too -glittering and small for a glow-worm. Then, as he looked, it winked at -him, and so declared itself to be an eye; and a small face began -gradually to grow up round it, like a frame round a picture. - -A brown little face, with whiskers. - -A grave round face, with the same twinkle in its eye that had first -attracted his notice. - -Small neat ears and thick silky hair. - -It was the Water Rat! - -Then the two animals stood and regarded each other cautiously. - -“Hullo, Mole!” said the Water Rat. - -“Hullo, Rat!” said the Mole. - -“Would you like to come over?” enquired the Rat presently. - -“Oh, its all very well to _talk_,” said the Mole, rather pettishly, he -being new to a river and riverside life and its ways. - -The Rat said nothing, but stooped and unfastened a rope and hauled on -it; then lightly stepped into a little boat which the Mole had not -observed. It was painted blue outside and white within, and was just -the size for two animals; and the Mole’s whole heart went out to it at -once, even though he did not yet fully understand its uses. - -The Rat sculled smartly across and made fast. Then he held up his -forepaw as the Mole stepped gingerly down. “Lean on that!” he said. -“Now then, step lively!” and the Mole to his surprise and rapture found -himself actually seated in the stern of a real boat. - -“This has been a wonderful day!” said he, as the Rat shoved off and -took to the sculls again. “Do you know, I’ve never been in a boat -before in all my life.” - -“What?” cried the Rat, open-mouthed: “Never been in a—you never—well -I—what have you been doing, then?” - -“Is it so nice as all that?” asked the Mole shyly, though he was quite -prepared to believe it as he leant back in his seat and surveyed the -cushions, the oars, the rowlocks, and all the fascinating fittings, and -felt the boat sway lightly under him. - -“Nice? It’s the _only_ thing,” said the Water Rat solemnly, as he leant -forward for his stroke. “Believe me, my young friend, there is -_nothing_—absolute nothing—half so much worth doing as simply messing -about in boats. Simply messing,” he went on dreamily: -“messing—about—in—boats; messing——” - -“Look ahead, Rat!” cried the Mole suddenly. - -It was too late. The boat struck the bank full tilt. The dreamer, the -joyous oarsman, lay on his back at the bottom of the boat, his heels in -the air. - -“—about in boats—or _with_ boats,” the Rat went on composedly, picking -himself up with a pleasant laugh. “In or out of ’em, it doesn’t matter. -Nothing seems really to matter, that’s the charm of it. Whether you get -away, or whether you don’t; whether you arrive at your destination or -whether you reach somewhere else, or whether you never get anywhere at -all, you’re always busy, and you never do anything in particular; and -when you’ve done it there’s always something else to do, and you can do -it if you like, but you’d much better not. Look here! If you’ve really -nothing else on hand this morning, supposing we drop down the river -together, and have a long day of it?” - -The Mole waggled his toes from sheer happiness, spread his chest with a -sigh of full contentment, and leaned back blissfully into the soft -cushions. “_What_ a day I’m having!” he said. “Let us start at once!” - -“Hold hard a minute, then!” said the Rat. He looped the painter through -a ring in his landing-stage, climbed up into his hole above, and after -a short interval reappeared staggering under a fat, wicker -luncheon-basket. - -“Shove that under your feet,” he observed to the Mole, as he passed it -down into the boat. Then he untied the painter and took the sculls -again. - -“What’s inside it?” asked the Mole, wriggling with curiosity. - -“There’s cold chicken inside it,” replied the Rat briefly; “ -coldtonguecoldhamcoldbeefpickledgherkinssaladfrenchrollscresssandwiches -pottedme atgingerbeerlemonadesodawater——” - -“O stop, stop,” cried the Mole in ecstacies: “This is too much!” - -“Do you really think so?” enquired the Rat seriously. “It’s only what I -always take on these little excursions; and the other animals are -always telling me that I’m a mean beast and cut it _very_ fine!” - -The Mole never heard a word he was saying. Absorbed in the new life he -was entering upon, intoxicated with the sparkle, the ripple, the scents -and the sounds and the sunlight, he trailed a paw in the water and -dreamed long waking dreams. The Water Rat, like the good little fellow -he was, sculled steadily on and forebore to disturb him. - -“I like your clothes awfully, old chap,” he remarked after some half an -hour or so had passed. “I’m going to get a black velvet smoking-suit -myself some day, as soon as I can afford it.” - -“I beg your pardon,” said the Mole, pulling himself together with an -effort. “You must think me very rude; but all this is so new to me. -So—this—is—a—River!” - -“_The_ River,” corrected the Rat. - -“And you really live by the river? What a jolly life!” - -“By it and with it and on it and in it,” said the Rat. “It’s brother -and sister to me, and aunts, and company, and food and drink, and -(naturally) washing. It’s my world, and I don’t want any other. What it -hasn’t got is not worth having, and what it doesn’t know is not worth -knowing. Lord! the times we’ve had together! Whether in winter or -summer, spring or autumn, it’s always got its fun and its excitements. -When the floods are on in February, and my cellars and basement are -brimming with drink that’s no good to me, and the brown water runs by -my best bedroom window; or again when it all drops away and, shows -patches of mud that smells like plum-cake, and the rushes and weed clog -the channels, and I can potter about dry shod over most of the bed of -it and find fresh food to eat, and things careless people have dropped -out of boats!” - -“But isn’t it a bit dull at times?” the Mole ventured to ask. “Just you -and the river, and no one else to pass a word with?” - -“No one else to—well, I mustn’t be hard on you,” said the Rat with -forbearance. “You’re new to it, and of course you don’t know. The bank -is so crowded nowadays that many people are moving away altogether: O -no, it isn’t what it used to be, at all. Otters, kingfishers, -dabchicks, moorhens, all of them about all day long and always wanting -you to _do_ something—as if a fellow had no business of his own to -attend to!” - -“What lies over _there?_” asked the Mole, waving a paw towards a -background of woodland that darkly framed the water-meadows on one side -of the river. - -“That? O, that’s just the Wild Wood,” said the Rat shortly. “We don’t -go there very much, we river-bankers.” - -“Aren’t they—aren’t they very _nice_ people in there?” said the Mole, a -trifle nervously. - -“W-e-ll,” replied the Rat, “let me see. The squirrels are all right. -_And_ the rabbits—some of ’em, but rabbits are a mixed lot. And then -there’s Badger, of course. He lives right in the heart of it; wouldn’t -live anywhere else, either, if you paid him to do it. Dear old Badger! -Nobody interferes with _him_. They’d better not,” he added -significantly. - -“Why, who _should_ interfere with him?” asked the Mole. - -“Well, of course—there—are others,” explained the Rat in a hesitating -sort of way. - -“Weasels—and stoats—and foxes—and so on. They’re all right in a way—I’m -very good friends with them—pass the time of day when we meet, and all -that—but they break out sometimes, there’s no denying it, and -then—well, you can’t really trust them, and that’s the fact.” - -The Mole knew well that it is quite against animal-etiquette to dwell -on possible trouble ahead, or even to allude to it; so he dropped the -subject. - -“And beyond the Wild Wood again?” he asked: “Where it’s all blue and -dim, and one sees what may be hills or perhaps they mayn’t, and -something like the smoke of towns, or is it only cloud-drift?” - -“Beyond the Wild Wood comes the Wide World,” said the Rat. “And that’s -something that doesn’t matter, either to you or me. I’ve never been -there, and I’m never going, nor you either, if you’ve got any sense at -all. Don’t ever refer to it again, please. Now then! Here’s our -backwater at last, where we’re going to lunch.” - -Leaving the main stream, they now passed into what seemed at first -sight like a little land-locked lake. Green turf sloped down to either -edge, brown snaky tree-roots gleamed below the surface of the quiet -water, while ahead of them the silvery shoulder and foamy tumble of a -weir, arm-in-arm with a restless dripping mill-wheel, that held up in -its turn a grey-gabled mill-house, filled the air with a soothing -murmur of sound, dull and smothery, yet with little clear voices -speaking up cheerfully out of it at intervals. It was so very beautiful -that the Mole could only hold up both forepaws and gasp, “O my! O my! O -my!” - -The Rat brought the boat alongside the bank, made her fast, helped the -still awkward Mole safely ashore, and swung out the luncheon-basket. -The Mole begged as a favour to be allowed to unpack it all by himself; -and the Rat was very pleased to indulge him, and to sprawl at full -length on the grass and rest, while his excited friend shook out the -table-cloth and spread it, took out all the mysterious packets one by -one and arranged their contents in due order, still gasping, “O my! O -my!” at each fresh revelation. When all was ready, the Rat said, “Now, -pitch in, old fellow!” and the Mole was indeed very glad to obey, for -he had started his spring-cleaning at a very early hour that morning, -as people _will_ do, and had not paused for bite or sup; and he had -been through a very great deal since that distant time which now seemed -so many days ago. - -“What are you looking at?” said the Rat presently, when the edge of -their hunger was somewhat dulled, and the Mole’s eyes were able to -wander off the table-cloth a little. - -“I am looking,” said the Mole, “at a streak of bubbles that I see -travelling along the surface of the water. That is a thing that strikes -me as funny.” - -“Bubbles? Oho!” said the Rat, and chirruped cheerily in an inviting -sort of way. - -A broad glistening muzzle showed itself above the edge of the bank, and -the Otter hauled himself out and shook the water from his coat. - -“Greedy beggars!” he observed, making for the provender. “Why didn’t -you invite me, Ratty?” - -“This was an impromptu affair,” explained the Rat. “By the way—my -friend Mr. Mole.” - -“Proud, I’m sure,” said the Otter, and the two animals were friends -forthwith. - -“Such a rumpus everywhere!” continued the Otter. “All the world seems -out on the river to-day. I came up this backwater to try and get a -moment’s peace, and then stumble upon you fellows!—At least—I beg -pardon—I don’t exactly mean that, you know.” - -There was a rustle behind them, proceeding from a hedge wherein last -year’s leaves still clung thick, and a stripy head, with high shoulders -behind it, peered forth on them. - -“Come on, old Badger!” shouted the Rat. - -The Badger trotted forward a pace or two; then grunted, “H’m! Company,” -and turned his back and disappeared from view. - -“That’s _just_ the sort of fellow he is!” observed the disappointed -Rat. “Simply hates Society! Now we shan’t see any more of him to-day. -Well, tell us, _who’s_ out on the river?” - -“Toad’s out, for one,” replied the Otter. “In his brand-new wager-boat; -new togs, new everything!” - -The two animals looked at each other and laughed. - -“Once, it was nothing but sailing,” said the Rat, “Then he tired of -that and took to punting. Nothing would please him but to punt all day -and every day, and a nice mess he made of it. Last year it was -house-boating, and we all had to go and stay with him in his -house-boat, and pretend we liked it. He was going to spend the rest of -his life in a house-boat. It’s all the same, whatever he takes up; he -gets tired of it, and starts on something fresh.” - -“Such a good fellow, too,” remarked the Otter reflectively: “But no -stability—especially in a boat!” - -From where they sat they could get a glimpse of the main stream across -the island that separated them; and just then a wager-boat flashed into -view, the rower—a short, stout figure—splashing badly and rolling a -good deal, but working his hardest. The Rat stood up and hailed him, -but Toad—for it was he—shook his head and settled sternly to his work. - -“He’ll be out of the boat in a minute if he rolls like that,” said the -Rat, sitting down again. - -“Of course he will,” chuckled the Otter. “Did I ever tell you that good -story about Toad and the lock-keeper? It happened this way. Toad....” - -An errant May-fly swerved unsteadily athwart the current in the -intoxicated fashion affected by young bloods of May-flies seeing life. -A swirl of water and a “cloop!” and the May-fly was visible no more. - -Neither was the Otter. - -The Mole looked down. The voice was still in his ears, but the turf -whereon he had sprawled was clearly vacant. Not an Otter to be seen, as -far as the distant horizon. - -But again there was a streak of bubbles on the surface of the river. - -The Rat hummed a tune, and the Mole recollected that animal-etiquette -forbade any sort of comment on the sudden disappearance of one’s -friends at any moment, for any reason or no reason whatever. - -“Well, well,” said the Rat, “I suppose we ought to be moving. I wonder -which of us had better pack the luncheon-basket?” He did not speak as -if he was frightfully eager for the treat. - -“O, please let me,” said the Mole. So, of course, the Rat let him. - -Packing the basket was not quite such pleasant work as unpacking the -basket. It never is. But the Mole was bent on enjoying everything, and -although just when he had got the basket packed and strapped up tightly -he saw a plate staring up at him from the grass, and when the job had -been done again the Rat pointed out a fork which anybody ought to have -seen, and last of all, behold! the mustard pot, which he had been -sitting on without knowing it—still, somehow, the thing got finished at -last, without much loss of temper. - -The afternoon sun was getting low as the Rat sculled gently homewards -in a dreamy mood, murmuring poetry-things over to himself, and not -paying much attention to Mole. But the Mole was very full of lunch, and -self-satisfaction, and pride, and already quite at home in a boat (so -he thought) and was getting a bit restless besides: and presently he -said, “Ratty! Please, _I_ want to row, now!” - -The Rat shook his head with a smile. “Not yet, my young friend,” he -said—“wait till you’ve had a few lessons. It’s not so easy as it -looks.” - -The Mole was quiet for a minute or two. But he began to feel more and -more jealous of Rat, sculling so strongly and so easily along, and his -pride began to whisper that he could do it every bit as well. He jumped -up and seized the sculls, so suddenly, that the Rat, who was gazing out -over the water and saying more poetry-things to himself, was taken by -surprise and fell backwards off his seat with his legs in the air for -the second time, while the triumphant Mole took his place and grabbed -the sculls with entire confidence. - -“Stop it, you _silly_ ass!” cried the Rat, from the bottom of the boat. -“You can’t do it! You’ll have us over!” - -The Mole flung his sculls back with a flourish, and made a great dig at -the water. He missed the surface altogether, his legs flew up above his -head, and he found himself lying on the top of the prostrate Rat. -Greatly alarmed, he made a grab at the side of the boat, and the next -moment—Sploosh! - -Over went the boat, and he found himself struggling in the river. - -O my, how cold the water was, and O, how _very_ wet it felt. How it -sang in his ears as he went down, down, down! How bright and welcome -the sun looked as he rose to the surface coughing and spluttering! How -black was his despair when he felt himself sinking again! Then a firm -paw gripped him by the back of his neck. It was the Rat, and he was -evidently laughing—the Mole could _feel_ him laughing, right down his -arm and through his paw, and so into his—the Mole’s—neck. - -The Rat got hold of a scull and shoved it under the Mole’s arm; then he -did the same by the other side of him and, swimming behind, propelled -the helpless animal to shore, hauled him out, and set him down on the -bank, a squashy, pulpy lump of misery. - -When the Rat had rubbed him down a bit, and wrung some of the wet out -of him, he said, “Now, then, old fellow! Trot up and down the -towing-path as hard as you can, till you’re warm and dry again, while I -dive for the luncheon-basket.” - -So the dismal Mole, wet without and ashamed within, trotted about till -he was fairly dry, while the Rat plunged into the water again, -recovered the boat, righted her and made her fast, fetched his floating -property to shore by degrees, and finally dived successfully for the -luncheon-basket and struggled to land with it. - -When all was ready for a start once more, the Mole, limp and dejected, -took his seat in the stern of the boat; and as they set off, he said in -a low voice, broken with emotion, “Ratty, my generous friend! I am very -sorry indeed for my foolish and ungrateful conduct. My heart quite -fails me when I think how I might have lost that beautiful -luncheon-basket. Indeed, I have been a complete ass, and I know it. -Will you overlook it this once and forgive me, and let things go on as -before?” - -“That’s all right, bless you!” responded the Rat cheerily. “What’s a -little wet to a Water Rat? I’m more in the water than out of it most -days. Don’t you think any more about it; and, look here! I really think -you had better come and stop with me for a little time. It’s very plain -and rough, you know—not like Toad’s house at all—but you haven’t seen -that yet; still, I can make you comfortable. And I’ll teach you to row, -and to swim, and you’ll soon be as handy on the water as any of us.” - -The Mole was so touched by his kind manner of speaking that he could -find no voice to answer him; and he had to brush away a tear or two -with the back of his paw. But the Rat kindly looked in another -direction, and presently the Mole’s spirits revived again, and he was -even able to give some straight back-talk to a couple of moorhens who -were sniggering to each other about his bedraggled appearance. - -When they got home, the Rat made a bright fire in the parlour, and -planted the Mole in an arm-chair in front of it, having fetched down a -dressing-gown and slippers for him, and told him river stories till -supper-time. Very thrilling stories they were, too, to an -earth-dwelling animal like Mole. Stories about weirs, and sudden -floods, and leaping pike, and steamers that flung hard bottles—at least -bottles were certainly flung, and _from_ steamers, so presumably _by_ -them; and about herons, and how particular they were whom they spoke -to; and about adventures down drains, and night-fishings with Otter, or -excursions far a-field with Badger. Supper was a most cheerful meal; -but very shortly afterwards a terribly sleepy Mole had to be escorted -upstairs by his considerate host, to the best bedroom, where he soon -laid his head on his pillow in great peace and contentment, knowing -that his new-found friend the River was lapping the sill of his window. - -This day was only the first of many similar ones for the emancipated -Mole, each of them longer and full of interest as the ripening summer -moved onward. He learnt to swim and to row, and entered into the joy of -running water; and with his ear to the reed-stems he caught, at -intervals, something of what the wind went whispering so constantly -among them. - - - - -II. -THE OPEN ROAD - - -“Ratty,” said the Mole suddenly, one bright summer morning, “if you -please, I want to ask you a favour.” - -The Rat was sitting on the river bank, singing a little song. He had -just composed it himself, so he was very taken up with it, and would -not pay proper attention to Mole or anything else. Since early morning -he had been swimming in the river, in company with his friends the -ducks. And when the ducks stood on their heads suddenly, as ducks will, -he would dive down and tickle their necks, just under where their chins -would be if ducks had chins, till they were forced to come to the -surface again in a hurry, spluttering and angry and shaking their -feathers at him, for it is impossible to say quite _all_ you feel when -your head is under water. At last they implored him to go away and -attend to his own affairs and leave them to mind theirs. So the Rat -went away, and sat on the river bank in the sun, and made up a song -about them, which he called - -“DUCKS’ DITTY.” - -All along the backwater, -Through the rushes tall, -Ducks are a-dabbling, -Up tails all! -Ducks’ tails, drakes’ tails, -Yellow feet a-quiver, -Yellow bills all out of sight -Busy in the river! - -Slushy green undergrowth -Where the roach swim— -Here we keep our larder, -Cool and full and dim. - -Everyone for what he likes! -_We_ like to be -Heads down, tails up, -Dabbling free! - -High in the blue above -Swifts whirl and call— -_We_ are down a-dabbling -Uptails all! - - -“I don’t know that I think so _very_ much of that little song, Rat,” -observed the Mole cautiously. He was no poet himself and didn’t care -who knew it; and he had a candid nature. - -“Nor don’t the ducks neither,” replied the Rat cheerfully. “They say, -‘_Why_ can’t fellows be allowed to do what they like _when_ they like -and _as_ they like, instead of other fellows sitting on banks and -watching them all the time and making remarks and poetry and things -about them? What _nonsense_ it all is!’ That’s what the ducks say.” - -“So it is, so it is,” said the Mole, with great heartiness. - -“No, it isn’t!” cried the Rat indignantly. - -“Well then, it isn’t, it isn’t,” replied the Mole soothingly. “But what -I wanted to ask you was, won’t you take me to call on Mr. Toad? I’ve -heard so much about him, and I do so want to make his acquaintance.” - -“Why, certainly,” said the good-natured Rat, jumping to his feet and -dismissing poetry from his mind for the day. “Get the boat out, and -we’ll paddle up there at once. It’s never the wrong time to call on -Toad. Early or late he’s always the same fellow. Always good-tempered, -always glad to see you, always sorry when you go!” - -“He must be a very nice animal,” observed the Mole, as he got into the -boat and took the sculls, while the Rat settled himself comfortably in -the stern. - -“He is indeed the best of animals,” replied Rat. “So simple, so -good-natured, and so affectionate. Perhaps he’s not very clever—we -can’t all be geniuses; and it may be that he is both boastful and -conceited. But he has got some great qualities, has Toady.” - -Rounding a bend in the river, they came in sight of a handsome, -dignified old house of mellowed red brick, with well-kept lawns -reaching down to the water’s edge. - -“There’s Toad Hall,” said the Rat; “and that creek on the left, where -the notice-board says, ‘Private. No landing allowed,’ leads to his -boat-house, where we’ll leave the boat. The stables are over there to -the right. That’s the banqueting-hall you’re looking at now—very old, -that is. Toad is rather rich, you know, and this is really one of the -nicest houses in these parts, though we never admit as much to Toad.” - -They glided up the creek, and the Mole shipped his sculls as they -passed into the shadow of a large boat-house. Here they saw many -handsome boats, slung from the cross beams or hauled up on a slip, but -none in the water; and the place had an unused and a deserted air. - -The Rat looked around him. “I understand,” said he. “Boating is played -out. He’s tired of it, and done with it. I wonder what new fad he has -taken up now? Come along and let’s look him up. We shall hear all about -it quite soon enough.” - -They disembarked, and strolled across the gay flower-decked lawns in -search of Toad, whom they presently happened upon resting in a wicker -garden-chair, with a pre-occupied expression of face, and a large map -spread out on his knees. - -“Hooray!” he cried, jumping up on seeing them, “this is splendid!” He -shook the paws of both of them warmly, never waiting for an -introduction to the Mole. “How _kind_ of you!” he went on, dancing -round them. “I was just going to send a boat down the river for you, -Ratty, with strict orders that you were to be fetched up here at once, -whatever you were doing. I want you badly—both of you. Now what will -you take? Come inside and have something! You don’t know how lucky it -is, your turning up just now!” - -“Let’s sit quiet a bit, Toady!” said the Rat, throwing himself into an -easy chair, while the Mole took another by the side of him and made -some civil remark about Toad’s “delightful residence.” - -“Finest house on the whole river,” cried Toad boisterously. “Or -anywhere else, for that matter,” he could not help adding. - -Here the Rat nudged the Mole. Unfortunately the Toad saw him do it, and -turned very red. There was a moment’s painful silence. Then Toad burst -out laughing. “All right, Ratty,” he said. “It’s only my way, you know. -And it’s not such a very bad house, is it? You know you rather like it -yourself. Now, look here. Let’s be sensible. You are the very animals I -wanted. You’ve got to help me. It’s most important!” - -“It’s about your rowing, I suppose,” said the Rat, with an innocent -air. “You’re getting on fairly well, though you splash a good bit -still. With a great deal of patience, and any quantity of coaching, you -may——” - -“O, pooh! boating!” interrupted the Toad, in great disgust. “Silly -boyish amusement. I’ve given that up _long_ ago. Sheer waste of time, -that’s what it is. It makes me downright sorry to see you fellows, who -ought to know better, spending all your energies in that aimless -manner. No, I’ve discovered the real thing, the only genuine occupation -for a life time. I propose to devote the remainder of mine to it, and -can only regret the wasted years that lie behind me, squandered in -trivialities. Come with me, dear Ratty, and your amiable friend also, -if he will be so very good, just as far as the stable-yard, and you -shall see what you shall see!” - -He led the way to the stable-yard accordingly, the Rat following with a -most mistrustful expression; and there, drawn out of the coach house -into the open, they saw a gipsy caravan, shining with newness, painted -a canary-yellow picked out with green, and red wheels. - -“There you are!” cried the Toad, straddling and expanding himself. -“There’s real life for you, embodied in that little cart. The open -road, the dusty highway, the heath, the common, the hedgerows, the -rolling downs! Camps, villages, towns, cities! Here to-day, up and off -to somewhere else to-morrow! Travel, change, interest, excitement! The -whole world before you, and a horizon that’s always changing! And mind! -this is the very finest cart of its sort that was ever built, without -any exception. Come inside and look at the arrangements. Planned ’em -all myself, I did!” - -The Mole was tremendously interested and excited, and followed him -eagerly up the steps and into the interior of the caravan. The Rat only -snorted and thrust his hands deep into his pockets, remaining where he -was. - -It was indeed very compact and comfortable. Little sleeping bunks—a -little table that folded up against the wall—a cooking-stove, lockers, -bookshelves, a bird-cage with a bird in it; and pots, pans, jugs and -kettles of every size and variety. - -“All complete!” said the Toad triumphantly, pulling open a locker. “You -see—biscuits, potted lobster, sardines—everything you can possibly -want. Soda-water here—baccy there—letter-paper, bacon, jam, cards and -dominoes—you’ll find,” he continued, as they descended the steps again, -“you’ll find that nothing what ever has been forgotten, when we make -our start this afternoon.” - -“I beg your pardon,” said the Rat slowly, as he chewed a straw, “but -did I overhear you say something about ‘_we_,’ and ‘_start_,’ and -‘_this afternoon?_’” - -“Now, you dear good old Ratty,” said Toad, imploringly, “don’t begin -talking in that stiff and sniffy sort of way, because you know you’ve -_got_ to come. I can’t possibly manage without you, so please consider -it settled, and don’t argue—it’s the one thing I can’t stand. You -surely don’t mean to stick to your dull fusty old river all your life, -and just live in a hole in a bank, and _boat?_ I want to show you the -world! I’m going to make an _animal_ of you, my boy!” - -“I don’t care,” said the Rat, doggedly. “I’m not coming, and that’s -flat. And I _am_ going to stick to my old river, _and_ live in a hole, -_and_ boat, as I’ve always done. And what’s more, Mole’s going to stick -to me and do as I do, aren’t you, Mole?” - -“Of course I am,” said the Mole, loyally. “I’ll always stick to you, -Rat, and what you say is to be—has got to be. All the same, it sounds -as if it might have been—well, rather fun, you know!” he added, -wistfully. Poor Mole! The Life Adventurous was so new a thing to him, -and so thrilling; and this fresh aspect of it was so tempting; and he -had fallen in love at first sight with the canary-coloured cart and all -its little fitments. - -The Rat saw what was passing in his mind, and wavered. He hated -disappointing people, and he was fond of the Mole, and would do almost -anything to oblige him. Toad was watching both of them closely. - -“Come along in, and have some lunch,” he said, diplomatically, “and -we’ll talk it over. We needn’t decide anything in a hurry. Of course, -_I_ don’t really care. I only want to give pleasure to you fellows. -‘Live for others!’ That’s my motto in life.” - -During luncheon—which was excellent, of course, as everything at Toad -Hall always was—the Toad simply let himself go. Disregarding the Rat, -he proceeded to play upon the inexperienced Mole as on a harp. -Naturally a voluble animal, and always mastered by his imagination, he -painted the prospects of the trip and the joys of the open life and the -roadside in such glowing colours that the Mole could hardly sit in his -chair for excitement. Somehow, it soon seemed taken for granted by all -three of them that the trip was a settled thing; and the Rat, though -still unconvinced in his mind, allowed his good-nature to over-ride his -personal objections. He could not bear to disappoint his two friends, -who were already deep in schemes and anticipations, planning out each -day’s separate occupation for several weeks ahead. - -When they were quite ready, the now triumphant Toad led his companions -to the paddock and set them to capture the old grey horse, who, without -having been consulted, and to his own extreme annoyance, had been told -off by Toad for the dustiest job in this dusty expedition. He frankly -preferred the paddock, and took a deal of catching. Meantime Toad -packed the lockers still tighter with necessaries, and hung nosebags, -nets of onions, bundles of hay, and baskets from the bottom of the -cart. At last the horse was caught and harnessed, and they set off, all -talking at once, each animal either trudging by the side of the cart or -sitting on the shaft, as the humour took him. It was a golden -afternoon. The smell of the dust they kicked up was rich and -satisfying; out of thick orchards on either side the road, birds called -and whistled to them cheerily; good-natured wayfarers, passing them, -gave them “Good-day,” or stopped to say nice things about their -beautiful cart; and rabbits, sitting at their front doors in the -hedgerows, held up their fore-paws, and said, “O my! O my! O my!” - -Late in the evening, tired and happy and miles from home, they drew up -on a remote common far from habitations, turned the horse loose to -graze, and ate their simple supper sitting on the grass by the side of -the cart. Toad talked big about all he was going to do in the days to -come, while stars grew fuller and larger all around them, and a yellow -moon, appearing suddenly and silently from nowhere in particular, came -to keep them company and listen to their talk. At last they turned in -to their little bunks in the cart; and Toad, kicking out his legs, -sleepily said, “Well, good night, you fellows! This is the real life -for a gentleman! Talk about your old river!” - -“I _don’t_ talk about my river,” replied the patient Rat. “You _know_ I -don’t, Toad. But I _think_ about it,” he added pathetically, in a lower -tone: “I think about it—all the time!” - -The Mole reached out from under his blanket, felt for the Rat’s paw in -the darkness, and gave it a squeeze. “I’ll do whatever you like, -Ratty,” he whispered. “Shall we run away to-morrow morning, quite -early—_very_ early—and go back to our dear old hole on the river?” - -“No, no, we’ll see it out,” whispered back the Rat. “Thanks awfully, -but I ought to stick by Toad till this trip is ended. It wouldn’t be -safe for him to be left to himself. It won’t take very long. His fads -never do. Good night!” - -The end was indeed nearer than even the Rat suspected. - -After so much open air and excitement the Toad slept very soundly, and -no amount of shaking could rouse him out of bed next morning. So the -Mole and Rat turned to, quietly and manfully, and while the Rat saw to -the horse, and lit a fire, and cleaned last night’s cups and platters, -and got things ready for breakfast, the Mole trudged off to the nearest -village, a long way off, for milk and eggs and various necessaries the -Toad had, of course, forgotten to provide. The hard work had all been -done, and the two animals were resting, thoroughly exhausted, by the -time Toad appeared on the scene, fresh and gay, remarking what a -pleasant easy life it was they were all leading now, after the cares -and worries and fatigues of housekeeping at home. - -They had a pleasant ramble that day over grassy downs and along narrow -by-lanes, and camped as before, on a common, only this time the two -guests took care that Toad should do his fair share of work. In -consequence, when the time came for starting next morning, Toad was by -no means so rapturous about the simplicity of the primitive life, and -indeed attempted to resume his place in his bunk, whence he was hauled -by force. Their way lay, as before, across country by narrow lanes, and -it was not till the afternoon that they came out on the high-road, -their first high-road; and there disaster, fleet and unforeseen, sprang -out on them—disaster momentous indeed to their expedition, but simply -overwhelming in its effect on the after-career of Toad. - -They were strolling along the high-road easily, the Mole by the horse’s -head, talking to him, since the horse had complained that he was being -frightfully left out of it, and nobody considered him in the least; the -Toad and the Water Rat walking behind the cart talking together—at -least Toad was talking, and Rat was saying at intervals, “Yes, -precisely; and what did _you_ say to _him?_”—and thinking all the time -of something very different, when far behind them they heard a faint -warning hum; like the drone of a distant bee. Glancing back, they saw a -small cloud of dust, with a dark centre of energy, advancing on them at -incredible speed, while from out the dust a faint “Poop-poop!” wailed -like an uneasy animal in pain. Hardly regarding it, they turned to -resume their conversation, when in an instant (as it seemed) the -peaceful scene was changed, and with a blast of wind and a whirl of -sound that made them jump for the nearest ditch, It was on them! The -“Poop-poop” rang with a brazen shout in their ears, they had a moment’s -glimpse of an interior of glittering plate-glass and rich morocco, and -the magnificent motor-car, immense, breath-snatching, passionate, with -its pilot tense and hugging his wheel, possessed all earth and air for -the fraction of a second, flung an enveloping cloud of dust that -blinded and enwrapped them utterly, and then dwindled to a speck in the -far distance, changed back into a droning bee once more. - -The old grey horse, dreaming, as he plodded along, of his quiet -paddock, in a new raw situation such as this simply abandoned himself -to his natural emotions. Rearing, plunging, backing steadily, in spite -of all the Mole’s efforts at his head, and all the Mole’s lively -language directed at his better feelings, he drove the cart backwards -towards the deep ditch at the side of the road. It wavered an -instant—then there was a heartrending crash—and the canary-coloured -cart, their pride and their joy, lay on its side in the ditch, an -irredeemable wreck. - -The Rat danced up and down in the road, simply transported with -passion. “You villains!” he shouted, shaking both fists, “You -scoundrels, you highwaymen, you—you—roadhogs!—I’ll have the law of you! -I’ll report you! I’ll take you through all the Courts!” His -home-sickness had quite slipped away from him, and for the moment he -was the skipper of the canary-coloured vessel driven on a shoal by the -reckless jockeying of rival mariners, and he was trying to recollect -all the fine and biting things he used to say to masters of -steam-launches when their wash, as they drove too near the bank, used -to flood his parlour-carpet at home. - -Toad sat straight down in the middle of the dusty road, his legs -stretched out before him, and stared fixedly in the direction of the -disappearing motor-car. He breathed short, his face wore a placid -satisfied expression, and at intervals he faintly murmured “Poop-poop!” - -The Mole was busy trying to quiet the horse, which he succeeded in -doing after a time. Then he went to look at the cart, on its side in -the ditch. It was indeed a sorry sight. Panels and windows smashed, -axles hopelessly bent, one wheel off, sardine-tins scattered over the -wide world, and the bird in the bird-cage sobbing pitifully and calling -to be let out. - -The Rat came to help him, but their united efforts were not sufficient -to right the cart. “Hi! Toad!” they cried. “Come and bear a hand, can’t -you!” - -The Toad never answered a word, or budged from his seat in the road; so -they went to see what was the matter with him. They found him in a sort -of a trance, a happy smile on his face, his eyes still fixed on the -dusty wake of their destroyer. At intervals he was still heard to -murmur “Poop-poop!” - -The Rat shook him by the shoulder. “Are you coming to help us, Toad?” -he demanded sternly. - -“Glorious, stirring sight!” murmured Toad, never offering to move. “The -poetry of motion! The _real_ way to travel! The _only_ way to travel! -Here to-day—in next week to-morrow! Villages skipped, towns and cities -jumped—always somebody else’s horizon! O bliss! O poop-poop! O my! O -my!” - -“O _stop_ being an ass, Toad!” cried the Mole despairingly. - -“And to think I never _knew!_” went on the Toad in a dreamy monotone. -“All those wasted years that lie behind me, I never knew, never even -_dreamt!_ But _now_—but now that I know, now that I fully realise! O -what a flowery track lies spread before me, henceforth! What -dust-clouds shall spring up behind me as I speed on my reckless way! -What carts I shall fling carelessly into the ditch in the wake of my -magnificent onset! Horrid little carts—common carts—canary-coloured -carts!” - -“What are we to do with him?” asked the Mole of the Water Rat. - -“Nothing at all,” replied the Rat firmly. “Because there is really -nothing to be done. You see, I know him from of old. He is now -possessed. He has got a new craze, and it always takes him that way, in -its first stage. He’ll continue like that for days now, like an animal -walking in a happy dream, quite useless for all practical purposes. -Never mind him. Let’s go and see what there is to be done about the -cart.” - -A careful inspection showed them that, even if they succeeded in -righting it by themselves, the cart would travel no longer. The axles -were in a hopeless state, and the missing wheel was shattered into -pieces. - -The Rat knotted the horse’s reins over his back and took him by the -head, carrying the bird cage and its hysterical occupant in the other -hand. “Come on!” he said grimly to the Mole. “It’s five or six miles to -the nearest town, and we shall just have to walk it. The sooner we make -a start the better.” - -“But what about Toad?” asked the Mole anxiously, as they set off -together. “We can’t leave him here, sitting in the middle of the road -by himself, in the distracted state he’s in! It’s not safe. Supposing -another Thing were to come along?” - -“O, _bother_ Toad,” said the Rat savagely; “I’ve done with him!” - -They had not proceeded very far on their way, however, when there was a -pattering of feet behind them, and Toad caught them up and thrust a paw -inside the elbow of each of them; still breathing short and staring -into vacancy. - -“Now, look here, Toad!” said the Rat sharply: “as soon as we get to the -town, you’ll have to go straight to the police-station, and see if they -know anything about that motor-car and who it belongs to, and lodge a -complaint against it. And then you’ll have to go to a blacksmith’s or a -wheelwright’s and arrange for the cart to be fetched and mended and put -to rights. It’ll take time, but it’s not quite a hopeless smash. -Meanwhile, the Mole and I will go to an inn and find comfortable rooms -where we can stay till the cart’s ready, and till your nerves have -recovered their shock.” - -“Police-station! Complaint!” murmured Toad dreamily. “Me _complain_ of -that beautiful, that heavenly vision that has been vouchsafed me! -_Mend_ the _cart!_ I’ve done with carts for ever. I never want to see -the cart, or to hear of it, again. O, Ratty! You can’t think how -obliged I am to you for consenting to come on this trip! I wouldn’t -have gone without you, and then I might never have seen that—that swan, -that sunbeam, that thunderbolt! I might never have heard that -entrancing sound, or smelt that bewitching smell! I owe it all to you, -my best of friends!” - -The Rat turned from him in despair. “You see what it is?” he said to -the Mole, addressing him across Toad’s head: “He’s quite hopeless. I -give it up—when we get to the town we’ll go to the railway station, and -with luck we may pick up a train there that’ll get us back to riverbank -to-night. And if ever you catch me going a-pleasuring with this -provoking animal again!”—He snorted, and during the rest of that weary -trudge addressed his remarks exclusively to Mole. - -On reaching the town they went straight to the station and deposited -Toad in the second-class waiting-room, giving a porter twopence to keep -a strict eye on him. They then left the horse at an inn stable, and -gave what directions they could about the cart and its contents. -Eventually, a slow train having landed them at a station not very far -from Toad Hall, they escorted the spell-bound, sleep-walking Toad to -his door, put him inside it, and instructed his housekeeper to feed -him, undress him, and put him to bed. Then they got out their boat from -the boat-house, sculled down the river home, and at a very late hour -sat down to supper in their own cosy riverside parlour, to the Rat’s -great joy and contentment. - -The following evening the Mole, who had risen late and taken things -very easy all day, was sitting on the bank fishing, when the Rat, who -had been looking up his friends and gossiping, came strolling along to -find him. “Heard the news?” he said. “There’s nothing else being talked -about, all along the river bank. Toad went up to Town by an early train -this morning. And he has ordered a large and very expensive motor-car.” - - - -*** END OF THE PROJECT GUTENBERG EBOOK THE WIND IN THE WILLOWS *** - -***** This file should be named 289-0.txt or 289-0.zip ***** -This and all associated files of various formats will be found in: - https://www.gutenberg.org/2/8/289/ - -Updated editions will replace the previous one--the old editions will -be renamed. - -Creating the works from print editions not protected by U.S. copyright -law means that no one owns a United States copyright in these works, -so the Foundation (and you!) can copy and distribute it in the -United States without permission and without paying copyright -royalties. Special rules, set forth in the General Terms of Use part -of this license, apply to copying and distributing Project -Gutenberg-tm electronic works to protect the PROJECT GUTENBERG-tm -concept and trademark. Project Gutenberg is a registered trademark, -and may not be used if you charge for an eBook, except by following -the terms of the trademark license, including paying royalties for use -of the Project Gutenberg trademark. If you do not charge anything for -copies of this eBook, complying with the trademark license is very -easy. You may use this eBook for nearly any purpose such as creation -of derivative works, reports, performances and research. Project -Gutenberg eBooks may be modified and printed and given away--you may -do practically ANYTHING in the United States with eBooks not protected -by U.S. copyright law. Redistribution is subject to the trademark -license, especially commercial redistribution. - -START: FULL LICENSE - -THE FULL PROJECT GUTENBERG LICENSE -PLEASE READ THIS BEFORE YOU DISTRIBUTE OR USE THIS WORK - -To protect the Project Gutenberg-tm mission of promoting the free -distribution of electronic works, by using or distributing this work -(or any other work associated in any way with the phrase "Project -Gutenberg"), you agree to comply with all the terms of the Full -Project Gutenberg-tm License available with this file or online at -www.gutenberg.org/license. - -Section 1. General Terms of Use and Redistributing Project -Gutenberg-tm electronic works - -1.A. By reading or using any part of this Project Gutenberg-tm -electronic work, you indicate that you have read, understand, agree to -and accept all the terms of this license and intellectual property -(trademark/copyright) agreement. If you do not agree to abide by all -the terms of this agreement, you must cease using and return or -destroy all copies of Project Gutenberg-tm electronic works in your -possession. If you paid a fee for obtaining a copy of or access to a -Project Gutenberg-tm electronic work and you do not agree to be bound -by the terms of this agreement, you may obtain a refund from the -person or entity to whom you paid the fee as set forth in paragraph -1.E.8. - -1.B. "Project Gutenberg" is a registered trademark. It may only be -used on or associated in any way with an electronic work by people who -agree to be bound by the terms of this agreement. There are a few -things that you can do with most Project Gutenberg-tm electronic works -even without complying with the full terms of this agreement. See -paragraph 1.C below. There are a lot of things you can do with Project -Gutenberg-tm electronic works if you follow the terms of this -agreement and help preserve free future access to Project Gutenberg-tm -electronic works. See paragraph 1.E below. - -1.C. The Project Gutenberg Literary Archive Foundation ("the -Foundation" or PGLAF), owns a compilation copyright in the collection -of Project Gutenberg-tm electronic works. Nearly all the individual -works in the collection are in the public domain in the United -States. If an individual work is unprotected by copyright law in the -United States and you are located in the United States, we do not -claim a right to prevent you from copying, distributing, performing, -displaying or creating derivative works based on the work as long as -all references to Project Gutenberg are removed. Of course, we hope -that you will support the Project Gutenberg-tm mission of promoting -free access to electronic works by freely sharing Project Gutenberg-tm -works in compliance with the terms of this agreement for keeping the -Project Gutenberg-tm name associated with the work. You can easily -comply with the terms of this agreement by keeping this work in the -same format with its attached full Project Gutenberg-tm License when -you share it without charge with others. - -1.D. The copyright laws of the place where you are located also govern -what you can do with this work. Copyright laws in most countries are -in a constant state of change. If you are outside the United States, -check the laws of your country in addition to the terms of this -agreement before downloading, copying, displaying, performing, -distributing or creating derivative works based on this work or any -other Project Gutenberg-tm work. The Foundation makes no -representations concerning the copyright status of any work in any -country other than the United States. - -1.E. Unless you have removed all references to Project Gutenberg: - -1.E.1. The following sentence, with active links to, or other -immediate access to, the full Project Gutenberg-tm License must appear -prominently whenever any copy of a Project Gutenberg-tm work (any work -on which the phrase "Project Gutenberg" appears, or with which the -phrase "Project Gutenberg" is associated) is accessed, displayed, -performed, viewed, copied or distributed: - - This eBook is for the use of anyone anywhere in the United States and - most other parts of the world at no cost and with almost no - restrictions whatsoever. You may copy it, give it away or re-use it - under the terms of the Project Gutenberg License included with this - eBook or online at www.gutenberg.org. If you are not located in the - United States, you will have to check the laws of the country where - you are located before using this eBook. - -1.E.2. If an individual Project Gutenberg-tm electronic work is -derived from texts not protected by U.S. copyright law (does not -contain a notice indicating that it is posted with permission of the -copyright holder), the work can be copied and distributed to anyone in -the United States without paying any fees or charges. If you are -redistributing or providing access to a work with the phrase "Project -Gutenberg" associated with or appearing on the work, you must comply -either with the requirements of paragraphs 1.E.1 through 1.E.7 or -obtain permission for the use of the work and the Project Gutenberg-tm -trademark as set forth in paragraphs 1.E.8 or 1.E.9. - -1.E.3. If an individual Project Gutenberg-tm electronic work is posted -with the permission of the copyright holder, your use and distribution -must comply with both paragraphs 1.E.1 through 1.E.7 and any -additional terms imposed by the copyright holder. Additional terms -will be linked to the Project Gutenberg-tm License for all works -posted with the permission of the copyright holder found at the -beginning of this work. - -1.E.4. Do not unlink or detach or remove the full Project Gutenberg-tm -License terms from this work, or any files containing a part of this -work or any other work associated with Project Gutenberg-tm. - -1.E.5. Do not copy, display, perform, distribute or redistribute this -electronic work, or any part of this electronic work, without -prominently displaying the sentence set forth in paragraph 1.E.1 with -active links or immediate access to the full terms of the Project -Gutenberg-tm License. - -1.E.6. You may convert to and distribute this work in any binary, -compressed, marked up, nonproprietary or proprietary form, including -any word processing or hypertext form. However, if you provide access -to or distribute copies of a Project Gutenberg-tm work in a format -other than "Plain Vanilla ASCII" or other format used in the official -version posted on the official Project Gutenberg-tm website -(www.gutenberg.org), you must, at no additional cost, fee or expense -to the user, provide a copy, a means of exporting a copy, or a means -of obtaining a copy upon request, of the work in its original "Plain -Vanilla ASCII" or other form. Any alternate format must include the -full Project Gutenberg-tm License as specified in paragraph 1.E.1. - -1.E.7. Do not charge a fee for access to, viewing, displaying, -performing, copying or distributing any Project Gutenberg-tm works -unless you comply with paragraph 1.E.8 or 1.E.9. - -1.E.8. You may charge a reasonable fee for copies of or providing -access to or distributing Project Gutenberg-tm electronic works -provided that: - -* You pay a royalty fee of 20% of the gross profits you derive from - the use of Project Gutenberg-tm works calculated using the method - you already use to calculate your applicable taxes. The fee is owed - to the owner of the Project Gutenberg-tm trademark, but he has - agreed to donate royalties under this paragraph to the Project - Gutenberg Literary Archive Foundation. Royalty payments must be paid - within 60 days following each date on which you prepare (or are - legally required to prepare) your periodic tax returns. Royalty - payments should be clearly marked as such and sent to the Project - Gutenberg Literary Archive Foundation at the address specified in - Section 4, "Information about donations to the Project Gutenberg - Literary Archive Foundation." - -* You provide a full refund of any money paid by a user who notifies - you in writing (or by e-mail) within 30 days of receipt that s/he - does not agree to the terms of the full Project Gutenberg-tm - License. You must require such a user to return or destroy all - copies of the works possessed in a physical medium and discontinue - all use of and all access to other copies of Project Gutenberg-tm - works. - -* You provide, in accordance with paragraph 1.F.3, a full refund of - any money paid for a work or a replacement copy, if a defect in the - electronic work is discovered and reported to you within 90 days of - receipt of the work. - -* You comply with all other terms of this agreement for free - distribution of Project Gutenberg-tm works. - -1.E.9. If you wish to charge a fee or distribute a Project -Gutenberg-tm electronic work or group of works on different terms than -are set forth in this agreement, you must obtain permission in writing -from the Project Gutenberg Literary Archive Foundation, the manager of -the Project Gutenberg-tm trademark. Contact the Foundation as set -forth in Section 3 below. - -1.F. - -1.F.1. Project Gutenberg volunteers and employees expend considerable -effort to identify, do copyright research on, transcribe and proofread -works not protected by U.S. copyright law in creating the Project -Gutenberg-tm collection. Despite these efforts, Project Gutenberg-tm -electronic works, and the medium on which they may be stored, may -contain "Defects," such as, but not limited to, incomplete, inaccurate -or corrupt data, transcription errors, a copyright or other -intellectual property infringement, a defective or damaged disk or -other medium, a computer virus, or computer codes that damage or -cannot be read by your equipment. - -1.F.2. LIMITED WARRANTY, DISCLAIMER OF DAMAGES - Except for the "Right -of Replacement or Refund" described in paragraph 1.F.3, the Project -Gutenberg Literary Archive Foundation, the owner of the Project -Gutenberg-tm trademark, and any other party distributing a Project -Gutenberg-tm electronic work under this agreement, disclaim all -liability to you for damages, costs and expenses, including legal -fees. YOU AGREE THAT YOU HAVE NO REMEDIES FOR NEGLIGENCE, STRICT -LIABILITY, BREACH OF WARRANTY OR BREACH OF CONTRACT EXCEPT THOSE -PROVIDED IN PARAGRAPH 1.F.3. YOU AGREE THAT THE FOUNDATION, THE -TRADEMARK OWNER, AND ANY DISTRIBUTOR UNDER THIS AGREEMENT WILL NOT BE -LIABLE TO YOU FOR ACTUAL, DIRECT, INDIRECT, CONSEQUENTIAL, PUNITIVE OR -INCIDENTAL DAMAGES EVEN IF YOU GIVE NOTICE OF THE POSSIBILITY OF SUCH -DAMAGE. - -1.F.3. LIMITED RIGHT OF REPLACEMENT OR REFUND - If you discover a -defect in this electronic work within 90 days of receiving it, you can -receive a refund of the money (if any) you paid for it by sending a -written explanation to the person you received the work from. If you -received the work on a physical medium, you must return the medium -with your written explanation. The person or entity that provided you -with the defective work may elect to provide a replacement copy in -lieu of a refund. If you received the work electronically, the person -or entity providing it to you may choose to give you a second -opportunity to receive the work electronically in lieu of a refund. If -the second copy is also defective, you may demand a refund in writing -without further opportunities to fix the problem. - -1.F.4. Except for the limited right of replacement or refund set forth -in paragraph 1.F.3, this work is provided to you 'AS-IS', WITH NO -OTHER WARRANTIES OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT -LIMITED TO WARRANTIES OF MERCHANTABILITY OR FITNESS FOR ANY PURPOSE. - -1.F.5. Some states do not allow disclaimers of certain implied -warranties or the exclusion or limitation of certain types of -damages. If any disclaimer or limitation set forth in this agreement -violates the law of the state applicable to this agreement, the -agreement shall be interpreted to make the maximum disclaimer or -limitation permitted by the applicable state law. The invalidity or -unenforceability of any provision of this agreement shall not void the -remaining provisions. - -1.F.6. INDEMNITY - You agree to indemnify and hold the Foundation, the -trademark owner, any agent or employee of the Foundation, anyone -providing copies of Project Gutenberg-tm electronic works in -accordance with this agreement, and any volunteers associated with the -production, promotion and distribution of Project Gutenberg-tm -electronic works, harmless from all liability, costs and expenses, -including legal fees, that arise directly or indirectly from any of -the following which you do or cause to occur: (a) distribution of this -or any Project Gutenberg-tm work, (b) alteration, modification, or -additions or deletions to any Project Gutenberg-tm work, and (c) any -Defect you cause. - -Section 2. Information about the Mission of Project Gutenberg-tm - -Project Gutenberg-tm is synonymous with the free distribution of -electronic works in formats readable by the widest variety of -computers including obsolete, old, middle-aged and new computers. It -exists because of the efforts of hundreds of volunteers and donations -from people in all walks of life. - -Volunteers and financial support to provide volunteers with the -assistance they need are critical to reaching Project Gutenberg-tm's -goals and ensuring that the Project Gutenberg-tm collection will -remain freely available for generations to come. In 2001, the Project -Gutenberg Literary Archive Foundation was created to provide a secure -and permanent future for Project Gutenberg-tm and future -generations. To learn more about the Project Gutenberg Literary -Archive Foundation and how your efforts and donations can help, see -Sections 3 and 4 and the Foundation information page at -www.gutenberg.org - -Section 3. Information about the Project Gutenberg Literary -Archive Foundation - -The Project Gutenberg Literary Archive Foundation is a non-profit -501(c)(3) educational corporation organized under the laws of the -state of Mississippi and granted tax exempt status by the Internal -Revenue Service. The Foundation's EIN or federal tax identification -number is 64-6221541. Contributions to the Project Gutenberg Literary -Archive Foundation are tax deductible to the full extent permitted by -U.S. federal laws and your state's laws. - -The Foundation's business office is located at 809 North 1500 West, -Salt Lake City, UT 84116, (801) 596-1887. Email contact links and up -to date contact information can be found at the Foundation's website -and official page at www.gutenberg.org/contact - -Section 4. Information about Donations to the Project Gutenberg -Literary Archive Foundation - -Project Gutenberg-tm depends upon and cannot survive without -widespread public support and donations to carry out its mission of -increasing the number of public domain and licensed works that can be -freely distributed in machine-readable form accessible by the widest -array of equipment including outdated equipment. Many small donations -($1 to $5,000) are particularly important to maintaining tax exempt -status with the IRS. - -The Foundation is committed to complying with the laws regulating -charities and charitable donations in all 50 states of the United -States. Compliance requirements are not uniform and it takes a -considerable effort, much paperwork and many fees to meet and keep up -with these requirements. We do not solicit donations in locations -where we have not received written confirmation of compliance. To SEND -DONATIONS or determine the status of compliance for any particular -state visit www.gutenberg.org/donate - -While we cannot and do not solicit contributions from states where we -have not met the solicitation requirements, we know of no prohibition -against accepting unsolicited donations from donors in such states who -approach us with offers to donate. - -International donations are gratefully accepted, but we cannot make -any statements concerning tax treatment of donations received from -outside the United States. U.S. laws alone swamp our small staff. - -Please check the Project Gutenberg web pages for current donation -methods and addresses. Donations are accepted in a number of other -ways including checks, online payments and credit card donations. To -donate, please visit: www.gutenberg.org/donate - -Section 5. General Information About Project Gutenberg-tm electronic works - -Professor Michael S. Hart was the originator of the Project -Gutenberg-tm concept of a library of electronic works that could be -freely shared with anyone. For forty years, he produced and -distributed Project Gutenberg-tm eBooks with only a loose network of -volunteer support. - -Project Gutenberg-tm eBooks are often created from several printed -editions, all of which are confirmed as not protected by copyright in -the U.S. unless a copyright notice is included. Thus, we do not -necessarily keep eBooks in compliance with any particular paper -edition. - -Most people start at our website which has the main PG search -facility: www.gutenberg.org - -This website includes information about Project Gutenberg-tm, -including how to make donations to the Project Gutenberg Literary -Archive Foundation, how to help produce our new eBooks, and how to -subscribe to our email newsletter to hear about new eBooks. - - diff --git a/micropython/examples/badger2040/assets/badge_image.png b/micropython/examples/badger2040/assets/badge_image.png deleted file mode 100644 index b5147dc73af9e358ed42403bcb3a2d275e05c253..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3498 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 Y2k?WF#JYsI@&Et;07*qoM6N<$g5A!R4FCWD diff --git a/micropython/examples/badger2040/assets/badgerpunk.png b/micropython/examples/badger2040/assets/badgerpunk.png deleted file mode 100644 index f7568a2ee3f5066b3759d9df0a3289a4110d2dfc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 36468 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 0 and length > width: - text = text[:-1] - else: - text += "" - return text - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw the badge, including user text -def draw_badge(): - display.pen(0) - display.clear() - - # Draw badge image - display.image(BADGE_IMAGE, IMAGE_WIDTH, HEIGHT, WIDTH - IMAGE_WIDTH, 0) - - # Draw a border around the image - display.pen(0) - display.thickness(1) - display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0) - display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1) - display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1) - display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1) - - # Uncomment this if a white background is wanted behind the company - # display.pen(15) - # display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1) - - # Draw the company - display.pen(15) # Change this to 0 if a white background is used - display.font("serif") - display.thickness(3) - display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, COMPANY_TEXT_SIZE) - - # Draw a white background behind the name - display.pen(15) - display.thickness(1) - display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT) - - # Draw the name, scaling it based on the available width - display.pen(0) - display.font("sans") - display.thickness(4) - name_size = 2.0 # A sensible starting scale - while True: - name_length = display.measure_text(name, name_size) - if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: - name_size -= 0.01 - else: - display.text(name, (TEXT_WIDTH - name_length) // 2, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, name_size) - break - - # Draw a white backgrounds behind the details - display.pen(15) - display.thickness(1) - display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1) - display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1) - - # Draw the first detail's title and text - display.pen(0) - display.font("sans") - display.thickness(3) - name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE) - display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), DETAILS_TEXT_SIZE) - display.thickness(2) - display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), DETAILS_TEXT_SIZE) - - # Draw the second detail's title and text - display.thickness(3) - name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE) - display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), DETAILS_TEXT_SIZE) - display.thickness(2) - display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), DETAILS_TEXT_SIZE) - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Create a new Badger and set it to update NORMAL -display = badger2040.Badger2040() -display.led(128) -display.update_speed(badger2040.UPDATE_NORMAL) - -# Open the badge file -try: - badge = open("badge.txt", "r") -except OSError: - with open("badge.txt", "w") as f: - f.write(DEFAULT_TEXT) - f.flush() - badge = open("badge.txt", "r") - -# Read in the next 6 lines -company = badge.readline() # "mustelid inc" -name = badge.readline() # "H. Badger" -detail1_title = badge.readline() # "RP2040" -detail1_text = badge.readline() # "2MB Flash" -detail2_title = badge.readline() # "E ink" -detail2_text = badge.readline() # "296x128px" - -# Truncate all of the text (except for the name as that is scaled) -company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH) - -detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) -detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE, - TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE)) - -detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) -detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE, - TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE)) - - -# ------------------------------ -# Main program -# ------------------------------ - -draw_badge() - -while True: - if display.pressed(badger2040.BUTTON_A) or display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C) or display.pressed(badger2040.BUTTON_UP) or display.pressed(badger2040.BUTTON_DOWN): - badger_os.warning(display, "To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt") - time.sleep(4) - - draw_badge() - - display.update() - - # If on battery, halt the Badger to save power, it will wake up if any of the front buttons are pressed - display.halt() diff --git a/micropython/examples/badger2040/badger_os.py b/micropython/examples/badger2040/badger_os.py deleted file mode 100644 index 6eb70972..00000000 --- a/micropython/examples/badger2040/badger_os.py +++ /dev/null @@ -1,183 +0,0 @@ -"""Keep track of app state in persistent flash storage.""" - -import os -import gc -import time -import json -import machine -import badger2040 - - -def get_battery_level(): - # Battery measurement - vbat_adc = machine.ADC(badger2040.PIN_BATTERY) - vref_adc = machine.ADC(badger2040.PIN_1V2_REF) - vref_en = machine.Pin(badger2040.PIN_VREF_POWER) - vref_en.init(machine.Pin.OUT) - vref_en.value(0) - - # Enable the onboard voltage reference - vref_en.value(1) - - # Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries - vdd = 1.24 * (65535 / vref_adc.read_u16()) - vbat = ( - (vbat_adc.read_u16() / 65535) * 3 * vdd - ) # 3 in this is a gain, not rounding of 3.3V - - # Disable the onboard voltage reference - vref_en.value(0) - - # Convert the voltage to a level to display onscreen - return vbat - - -def get_disk_usage(): - # f_bfree and f_bavail should be the same? - # f_files, f_ffree, f_favail and f_flag are unsupported. - f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/") - - f_total_size = f_frsize * f_blocks - f_total_free = f_bsize * f_bfree - f_total_used = f_total_size - f_total_free - - f_used = 100 / f_total_size * f_total_used - f_free = 100 / f_total_size * f_total_free - - return f_total_size, f_used, f_free - - -def state_running(): - state = {"running": "launcher"} - state_load("launcher", state) - return state["running"] - - -def state_clear_running(): - running = state_running() - state_modify("launcher", {"running": "launcher"}) - return running != "launcher" - - -def state_set_running(app): - state_modify("launcher", {"running": app}) - - -def state_launch(): - app = state_running() - if app is not None and app != "launcher": - launch("_" + app) - - -def state_delete(app): - try: - os.remove("/state/{}.json".format(app)) - except OSError: - pass - - -def state_save(app, data): - try: - with open("/state/{}.json".format(app), "w") as f: - f.write(json.dumps(data)) - f.flush() - except OSError: - import os - try: - os.stat("/state") - except OSError: - os.mkdir("/state") - state_save(app, data) - - -def state_modify(app, data): - state = {} - state_load(app, state) - state.update(data) - state_save(app, state) - - -def state_load(app, defaults): - try: - data = json.loads(open("/state/{}.json".format(app), "r").read()) - if type(data) is dict: - defaults.update(data) - return True - except (OSError, ValueError): - pass - - state_save(app, defaults) - return False - - -def launch(file): - state_set_running(file[1:]) - - gc.collect() - - button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) - button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) - - def quit_to_launcher(pin): - if button_a.value() and button_c.value(): - machine.reset() - - button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) - button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) - - try: - try: - __import__(file[1:]) # Try to import _[file] (drop underscore prefix) - except ImportError: - __import__(file) # Failover to importing [_file] - - except ImportError: - # If the app doesn't exist, notify the user - warning(None, "Could not launch: " + file[1:]) - time.sleep(4.0) - except Exception as e: - # If the app throws an error, catch it and display! - print(e) - warning(None, str(e)) - time.sleep(4.0) - - # If the app exits or errors, do not relaunch! - state_clear_running() - machine.reset() # Exit back to launcher - - -# Draw an overlay box with a given message within it -def warning(display, message, width=badger2040.WIDTH - 40, height=badger2040.HEIGHT - 40, line_spacing=20, text_size=0.6): - if display is None: - display = badger2040.Badger2040() - display.led(128) - - # Draw a light grey background - display.pen(12) - display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height) - - # Take the provided message and split it up into - # lines that fit within the specified width - words = message.split(" ") - - lines = [] - current_line = "" - for word in words: - if display.measure_text(current_line + word + " ", text_size) < width: - current_line += word + " " - else: - lines.append(current_line.strip()) - current_line = word + " " - lines.append(current_line.strip()) - - display.pen(0) - display.thickness(2) - - # Display each line of text from the message, centre-aligned - num_lines = len(lines) - for i in range(num_lines): - length = display.measure_text(lines[i], text_size) - current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2 - display.text(lines[i], (badger2040.WIDTH - length) // 2, (badger2040.HEIGHT // 2) + current_line, text_size) - - display.update() diff --git a/micropython/examples/badger2040/battery.py b/micropython/examples/badger2040/battery.py deleted file mode 100644 index eaa97bb1..00000000 --- a/micropython/examples/badger2040/battery.py +++ /dev/null @@ -1,163 +0,0 @@ -import badger2040 -from machine import Pin, ADC -import time - -# Global Constants -# for e.g. 2xAAA batteries, try max 3.4 min 3.0 -MAX_BATTERY_VOLTAGE = 4.0 -MIN_BATTERY_VOLTAGE = 3.2 - -WIDTH = badger2040.WIDTH -HEIGHT = badger2040.HEIGHT - -BATT_WIDTH = 200 -BATT_HEIGHT = 100 -BATT_BORDER = 10 -BATT_TERM_WIDTH = 20 -BATT_TERM_HEIGHT = 50 -BATT_BAR_PADDING = 10 -BATT_BAR_HEIGHT = BATT_HEIGHT - (BATT_BORDER * 2) - (BATT_BAR_PADDING * 2) -BATT_BAR_START = ((WIDTH - BATT_WIDTH) // 2) + BATT_BORDER + BATT_BAR_PADDING -BATT_BAR_END = ((WIDTH + BATT_WIDTH) // 2) - BATT_BORDER - BATT_BAR_PADDING - -NUM_BATT_BARS = 4 - - -# ------------------------------ -# Utility functions -# ------------------------------ - - -def map_value(input, in_min, in_max, out_min, out_max): - return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw the frame of the reader -def draw_battery(level, resolution): - display.pen(15) - display.clear() - - display.thickness(1) - - # Draw the battery outline - display.pen(0) - display.rectangle( - (WIDTH - BATT_WIDTH) // 2, (HEIGHT - BATT_HEIGHT) // 2, BATT_WIDTH, BATT_HEIGHT - ) - - display.rectangle( - (WIDTH + BATT_WIDTH) // 2, - (HEIGHT - BATT_TERM_HEIGHT) // 2, - BATT_TERM_WIDTH, - BATT_TERM_HEIGHT, - ) - - display.pen(15) - display.rectangle( - (WIDTH - BATT_WIDTH) // 2 + BATT_BORDER, - (HEIGHT - BATT_HEIGHT) // 2 + BATT_BORDER, - BATT_WIDTH - BATT_BORDER * 2, - BATT_HEIGHT - BATT_BORDER * 2, - ) - - # Add a special check for no battery - if level < 1: - X = WIDTH // 2 - Y = HEIGHT // 2 - - display.pen(0) - display.thickness(1) - thickness = (BATT_BORDER * 3) // 2 - start_extra = thickness // 3 - end_extra = (thickness * 2) // 3 - for i in range(0, thickness): - excess = i // 2 - display.line( - X - (BATT_HEIGHT // 2) + i - excess - start_extra, - Y - (BATT_HEIGHT // 2) - excess - start_extra, - X + (BATT_HEIGHT // 2) + i - excess + end_extra, - Y + (BATT_HEIGHT // 2) - excess + end_extra, - ) - display.pen(15) - for i in range(0 - thickness, 0): - display.line( - X - (BATT_HEIGHT // 2) + i, - Y - (BATT_HEIGHT // 2), - X + (BATT_HEIGHT // 2) + i, - Y + (BATT_HEIGHT // 2), - ) - else: - # Draw the battery bars - display.pen(0) - length = ( - BATT_BAR_END - BATT_BAR_START - ((NUM_BATT_BARS - 1) * BATT_BAR_PADDING) - ) // NUM_BATT_BARS - current_level = 0.0 - normalised_level = level / resolution - for i in range(NUM_BATT_BARS): - current_level = (1.0 * i) / NUM_BATT_BARS - if normalised_level > current_level: - pos = i * (length + BATT_BAR_PADDING) - display.rectangle( - BATT_BAR_START + pos, - (HEIGHT - BATT_BAR_HEIGHT) // 2, - length, - BATT_BAR_HEIGHT, - ) - - display.update() - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Create a new Badger and set it to update FAST -display = badger2040.Badger2040() -display.update_speed(badger2040.UPDATE_FAST) - -# Set up the ADCs for measuring battery voltage -vbat_adc = ADC(badger2040.PIN_BATTERY) -vref_adc = ADC(badger2040.PIN_1V2_REF) -vref_en = Pin(badger2040.PIN_VREF_POWER) -vref_en.init(Pin.OUT) -vref_en.value(0) - - -# ------------------------------ -# Main program loop -# ------------------------------ - -last_level = -1 - -while True: - # Enable the onboard voltage reference - vref_en.value(1) - - # Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries - vdd = 1.24 * (65535 / vref_adc.read_u16()) - vbat = ( - (vbat_adc.read_u16() / 65535) * 3 * vdd - ) # 3 in this is a gain, not rounding of 3.3V - - # Disable the onboard voltage reference - vref_en.value(0) - - # Print out the voltage - print("Battery Voltage = ", vbat, "V", sep="") - - # Convert the voltage to a level to display onscreen - level = int( - map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, NUM_BATT_BARS) - ) - - # Only draw if the battery level has changed significantly - if level != last_level: - draw_battery(level, NUM_BATT_BARS) - last_level = level - - time.sleep(1) diff --git a/micropython/examples/badger2040/button_test.py b/micropython/examples/badger2040/button_test.py deleted file mode 100644 index 23954027..00000000 --- a/micropython/examples/badger2040/button_test.py +++ /dev/null @@ -1,67 +0,0 @@ -import badger2040 -import machine -import time - -display = badger2040.Badger2040() -display.update_speed(badger2040.UPDATE_TURBO) -display.pen(15) -display.clear() -display.update() - -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) -# the User button (boot/usr on back of board) is inverted from the others -button_user = machine.Pin(badger2040.BUTTON_USER, machine.Pin.IN, machine.Pin.PULL_UP) - - -message = None -message_y = 60 - - -def button(pin): - global message - if message is not None: - return - if pin == button_a: - message = "Button a" - return - if pin == button_b: - message = "Button b" - return - if pin == button_c: - message = "Button c" - return - if pin == button_up: - message = "Button Up" - return - if pin == button_down: - message = "Button Down" - return - if pin == button_user: - message = "Button Usr" - return - - -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - -button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_user.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - - -while True: - if message is not None: - display.pen(15) - display.clear() - display.pen(0) - display.thickness(4) - display.text(message, 6, message_y, 1.4) - for _ in range(2): - display.update() - message = None - time.sleep(0.1) diff --git a/micropython/examples/badger2040/clock.py b/micropython/examples/badger2040/clock.py deleted file mode 100644 index 0865780b..00000000 --- a/micropython/examples/badger2040/clock.py +++ /dev/null @@ -1,154 +0,0 @@ -import time -import machine -import badger2040 - -# We're going to keep the badger on, so slow down the system clock if on battery -badger2040.system_speed(badger2040.SYSTEM_SLOW) - -rtc = machine.RTC() -display = badger2040.Badger2040() -display.led(128) -display.update_speed(badger2040.UPDATE_TURBO) -display.font("gothic") - -cursors = ["year", "month", "day", "hour", "minute"] -set_clock = False -cursor = 0 -last = 0 - -# Set up the buttons -button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) - -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) - - -def days_in_month(month, year): - if month == 2 and ((year % 4 == 0 and year % 100 != 0) or year % 400 == 0): - return 29 - return (31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31)[month - 1] - - -# Button handling function -def button(pin): - global last, set_clock, cursor, year, month, day, hour, minute - - time.sleep(0.01) - if not pin.value(): - return - - if button_a.value() and button_c.value(): - machine.reset() - - adjust = 0 - changed = False - - if pin == button_b: - set_clock = not set_clock - changed = True - if not set_clock: - rtc.datetime((year, month, day, 0, hour, minute, second, 0)) - - if set_clock: - if pin == button_c: - cursor += 1 - cursor %= len(cursors) - - if pin == button_a: - cursor -= 1 - cursor %= len(cursors) - - if pin == button_up: - adjust = 1 - - if pin == button_down: - adjust = -1 - - if cursors[cursor] == "year": - year += adjust - year = max(year, 2022) - day = min(day, days_in_month(month, year)) - if cursors[cursor] == "month": - month += adjust - month = min(max(month, 1), 12) - day = min(day, days_in_month(month, year)) - if cursors[cursor] == "day": - day += adjust - day = min(max(day, 1), days_in_month(month, year)) - if cursors[cursor] == "hour": - hour += adjust - hour %= 24 - if cursors[cursor] == "minute": - minute += adjust - minute %= 60 - - if set_clock or changed: - draw_clock() - - -# Register the button handling function with the buttons -button_down.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_up.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - - -def draw_clock(): - hms = "{:02}:{:02}:{:02}".format(hour, minute, second) - ymd = "{:04}/{:02}/{:02}".format(year, month, day) - - hms_width = display.measure_text(hms, 1.8) - hms_offset = int((badger2040.WIDTH / 2) - (hms_width / 2)) - h_width = display.measure_text(hms[0:2], 1.8) - mi_width = display.measure_text(hms[3:5], 1.8) - mi_offset = display.measure_text(hms[0:3], 1.8) - - ymd_width = display.measure_text(ymd, 1.0) - ymd_offset = int((badger2040.WIDTH / 2) - (ymd_width / 2)) - y_width = display.measure_text(ymd[0:4], 1.0) - m_width = display.measure_text(ymd[5:7], 1.0) - m_offset = display.measure_text(ymd[0:5], 1.0) - d_width = display.measure_text(ymd[8:10], 1.0) - d_offset = display.measure_text(ymd[0:8], 1.0) - - display.pen(15) - display.clear() - display.pen(0) - display.thickness(5) - display.text(hms, hms_offset, 40, 1.8) - display.thickness(3) - display.text(ymd, ymd_offset, 100, 1.0) - - if set_clock: - if cursors[cursor] == "year": - display.line(ymd_offset, 120, ymd_offset + y_width, 120) - if cursors[cursor] == "month": - display.line(ymd_offset + m_offset, 120, ymd_offset + m_offset + m_width, 120) - if cursors[cursor] == "day": - display.line(ymd_offset + d_offset, 120, ymd_offset + d_offset + d_width, 120) - - if cursors[cursor] == "hour": - display.line(hms_offset, 70, hms_offset + h_width, 70) - if cursors[cursor] == "minute": - display.line(hms_offset + mi_offset, 70, hms_offset + mi_offset + mi_width, 70) - - display.update() - - -year, month, day, wd, hour, minute, second, _ = rtc.datetime() - -if (year, month, day) == (2021, 1, 1): - rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0)) - -last_second = second - -while True: - if not set_clock: - year, month, day, wd, hour, minute, second, _ = rtc.datetime() - if second != last_second: - draw_clock() - last_second = second - time.sleep(0.01) diff --git a/micropython/examples/badger2040/conway.py b/micropython/examples/badger2040/conway.py deleted file mode 100644 index 3f8c67de..00000000 --- a/micropython/examples/badger2040/conway.py +++ /dev/null @@ -1,215 +0,0 @@ -import math -import time -from random import random - -import machine - -import badger2040 - -# Overclock the RP2040 to run the sim faster -badger2040.system_speed(badger2040.SYSTEM_TURBO) - -# ------------------------------ -# Program setup -# ------------------------------ - -# Global constants -CELL_SIZE = 6 # Size of cell in pixels -INITIAL_DENSITY = 0.3 # Density of cells at start - -# Create a new Badger and set it to update TURBO -screen = badger2040.Badger2040() -screen.led(128) -screen.update_speed(badger2040.UPDATE_TURBO) - -restart = False # should sim be restarted - -# ------------------------------ -# Button functions -# ------------------------------ - - -# Button handling function -def button(pin): - global restart - # if 'a' button is pressed, restart the sim - if pin == button_a: - restart = True - - -# Set up button -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - -# ------------------------------ -# Screen functions -# ------------------------------ - - -# Remove everything from the screen -def init_screen(): - screen.update_speed(badger2040.UPDATE_NORMAL) - screen.pen(15) - screen.clear() - screen.update() - screen.update_speed(badger2040.UPDATE_TURBO) - - -# ------------------------------ -# Classes -# ------------------------------ - -# Define a 'cell' -class Cell: - def __init__(self): - self._alive = False - - def make_alive(self): - self._alive = True - - def make_dead(self): - self._alive = False - - def is_alive(self): - return self._alive - - -# Define the whole board -class Board: - def __init__(self): - self._rows = math.floor(badger2040.WIDTH / CELL_SIZE) - self._columns = math.floor(badger2040.HEIGHT / CELL_SIZE) - self._grid = [[Cell() for _ in range(self._columns)] for _ in range(self._rows)] - - self._initialise_board() - - # Draw the board to the screen - def draw_board(self): - row_idx = 0 - column_idx = 0 - - for row in self._grid: - column_idx = 0 - for cell in row: - if cell.is_alive(): - screen.pen(0) - else: - screen.pen(15) - screen.rectangle( - row_idx * CELL_SIZE, column_idx * CELL_SIZE, CELL_SIZE, CELL_SIZE - ) - column_idx += 1 - row_idx += 1 - - screen.update() - - # Generate the first iteration of the board - def _initialise_board(self): - for row in self._grid: - for cell in row: - if random() <= INITIAL_DENSITY: - cell.make_alive() - - # Get the neighbour cells for a given cell - def get_neighbours(self, current_row, current_column): - # Cells either side of current cell - neighbour_min = -1 - neighbour_max = 2 - neighbours = [] - - for row in range(neighbour_min, neighbour_max): - for column in range(neighbour_min, neighbour_max): - neighbour_row = current_row + row - neighbour_column = current_column + column - # Don't count the current cell - if not ( - neighbour_row == current_row and neighbour_column == current_column - ): - # It's a toroidal world so go all the way round if necessary - if (neighbour_row) < 0: - neighbour_row = self._rows - 1 - elif (neighbour_row) >= self._rows: - neighbour_row = 0 - - if (neighbour_column) < 0: - neighbour_column = self._columns - 1 - elif (neighbour_column) >= self._columns: - neighbour_column = 0 - - neighbours.append(self._grid[neighbour_row][neighbour_column]) - return neighbours - - # Calculate the next generation - def create_next_generation(self): - to_alive = [] - to_dead = [] - changed = False - - for row in range(len(self._grid)): - for column in range(len(self._grid[row])): - # Get all the neighours that are alive - alive_neighbours = [] - for neighbour_cell in self.get_neighbours(row, column): - if neighbour_cell.is_alive(): - alive_neighbours.append(neighbour_cell) - - current_cell = self._grid[row][column] - # Apply the Conway GoL rules (B3/S23) - if current_cell.is_alive(): - if len(alive_neighbours) < 2 or len(alive_neighbours) > 3: - to_dead.append(current_cell) - if len(alive_neighbours) == 3 or len(alive_neighbours) == 2: - to_alive.append(current_cell) - else: - if len(alive_neighbours) == 3: - to_alive.append(current_cell) - - for cell in to_alive: - if not cell.is_alive(): - # The board has changed since the previous generation - changed = True - cell.make_alive() - - for cell in to_dead: - if cell.is_alive(): - # The board has changed since the previous generation - changed = True - cell.make_dead() - - return changed - - -# ------------------------------ -# Main program loop -# ------------------------------ - - -def main(): - global restart - - init_screen() - board = Board() - board.draw_board() - time.sleep(0.5) - - while True: - # The 'a' button has been pressed so restart sim - if restart: - init_screen() - restart = False - board = Board() - board.draw_board() - time.sleep(0.5) - # The board didn't update since the previous generation - if not board.create_next_generation(): - screen.update_speed(badger2040.UPDATE_NORMAL) - board.draw_board() - screen.update_speed(badger2040.UPDATE_TURBO) - time.sleep(5) - restart = True - # Draw the next generation - else: - board.draw_board() - - -main() diff --git a/micropython/examples/badger2040/ebook.py b/micropython/examples/badger2040/ebook.py deleted file mode 100644 index 7f21239e..00000000 --- a/micropython/examples/badger2040/ebook.py +++ /dev/null @@ -1,263 +0,0 @@ -import badger2040 -import time -import gc -import badger_os - -# **** Put the name of your text file here ***** -text_file = "book.txt" # File must be on the MicroPython device - - -try: - open(text_file, "r") -except OSError: - try: - # If the specified file doesn't exist, - # pre-populate with Wind In The Willows - import witw - with open(text_file, "wb") as f: - f.write(witw.data()) - f.flush() - time.sleep(0.1) - del witw - except ImportError: - pass - - -gc.collect() - -# Global Constants -WIDTH = badger2040.WIDTH -HEIGHT = badger2040.HEIGHT - -ARROW_THICKNESS = 3 -ARROW_WIDTH = 18 -ARROW_HEIGHT = 14 -ARROW_PADDING = 2 - -TEXT_PADDING = 4 -TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH - -FONTS = ["sans", "gothic", "cursive", "serif"] -FONT_THICKNESSES = [2, 1, 1, 2] -# ------------------------------ -# Drawing functions -# ------------------------------ - - -# Draw a upward arrow -def draw_up(x, y, width, height, thickness, padding): - border = (thickness // 4) + padding - display.line(x + border, y + height - border, - x + (width // 2), y + border) - display.line(x + (width // 2), y + border, - x + width - border, y + height - border) - - -# Draw a downward arrow -def draw_down(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw the frame of the reader -def draw_frame(): - display.pen(15) - display.clear() - display.pen(12) - display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) - display.pen(0) - display.thickness(ARROW_THICKNESS) - if state["current_page"] > 0: - draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Global variables -state = { - "last_offset": 0, - "current_page": 0, - "font_idx": 0, - "text_size": 0.5, - "offsets": [] -} -badger_os.state_load("ebook", state) - -text_spacing = int(34 * state["text_size"]) - - -# Create a new Badger and set it to update FAST -display = badger2040.Badger2040() -display.led(128) -display.update_speed(badger2040.UPDATE_FAST) - - -# ------------------------------ -# Render page -# ------------------------------ - -def render_page(): - row = 0 - line = "" - pos = ebook.tell() - next_pos = pos - add_newline = False - display.font(FONTS[state["font_idx"]]) - - while True: - # Read a full line and split it into words - words = ebook.readline().split(" ") - - # Take the length of the first word and advance our position - next_word = words[0] - if len(words) > 1: - next_pos += len(next_word) + 1 - else: - next_pos += len(next_word) # This is the last word on the line - - # Advance our position further if the word contains special characters - if '\u201c' in next_word: - next_word = next_word.replace('\u201c', '\"') - next_pos += 2 - if '\u201d' in next_word: - next_word = next_word.replace('\u201d', '\"') - next_pos += 2 - if '\u2019' in next_word: - next_word = next_word.replace('\u2019', '\'') - next_pos += 2 - - # Rewind the file back from the line end to the start of the next word - ebook.seek(next_pos) - - # Strip out any new line characters from the word - next_word = next_word.strip() - - # If an empty word is encountered assume that means there was a blank line - if len(next_word) == 0: - add_newline = True - - # Append the word to the current line and measure its length - appended_line = line - if len(line) > 0 and len(next_word) > 0: - appended_line += " " - appended_line += next_word - appended_length = display.measure_text(appended_line, state["text_size"]) - - # Would this appended line be longer than the text display area, or was a blank line spotted? - if appended_length >= TEXT_WIDTH or add_newline: - - # Yes, so write out the line prior to the append - print(line) - display.pen(0) - display.thickness(FONT_THICKNESSES[0]) - display.text(line, TEXT_PADDING, (row * text_spacing) + (text_spacing // 2) + TEXT_PADDING, state["text_size"]) - - # Clear the line and move on to the next row - line = "" - row += 1 - - # Have we reached the end of the page? - if (row * text_spacing) + text_spacing >= HEIGHT: - print("+++++") - display.update() - - # Reset the position to the start of the word that made this line too long - ebook.seek(pos) - return - else: - # Set the line to the word and advance the current position - line = next_word - pos = next_pos - - # A new line was spotted, so advance a row - if add_newline: - print("") - row += 1 - if (row * text_spacing) + text_spacing >= HEIGHT: - print("+++++") - display.update() - return - add_newline = False - else: - # The appended line was not too long, so set it as the line and advance the current position - line = appended_line - pos = next_pos - - -# ------------------------------ -# Main program loop -# ------------------------------ - -launch = True -changed = False - -# Open the book file -ebook = open(text_file, "r") -if len(state["offsets"]) > state["current_page"]: - ebook.seek(state["offsets"][state["current_page"]]) -else: - state["current_page"] = 0 - state["offsets"] = [] - -while True: - # Was the next page button pressed? - if display.pressed(badger2040.BUTTON_DOWN): - state["current_page"] += 1 - - changed = True - - # Was the previous page button pressed? - if display.pressed(badger2040.BUTTON_UP): - if state["current_page"] > 0: - state["current_page"] -= 1 - if state["current_page"] == 0: - ebook.seek(0) - else: - ebook.seek(state["offsets"][state["current_page"] - 1]) # Retrieve the start position of the last page - changed = True - - if display.pressed(badger2040.BUTTON_A): - state["text_size"] += 0.1 - if state["text_size"] > 0.8: - state["text_size"] = 0.5 - text_spacing = int(34 * state["text_size"]) - state["offsets"] = [] - ebook.seek(0) - state["current_page"] = 0 - changed = True - - if display.pressed(badger2040.BUTTON_B): - state["font_idx"] += 1 - if (state["font_idx"] >= len(FONTS)): - state["font_idx"] = 0 - state["offsets"] = [] - ebook.seek(0) - state["current_page"] = 0 - changed = True - - if launch and not changed: - if state["current_page"] > 0 and len(state["offsets"]) > state["current_page"] - 1: - ebook.seek(state["offsets"][state["current_page"] - 1]) - changed = True - launch = False - - if changed: - draw_frame() - render_page() - - # Is the next page one we've not displayed before? - if state["current_page"] >= len(state["offsets"]): - state["offsets"].append(ebook.tell()) # Add its start position to the state["offsets"] list - badger_os.state_save("ebook", state) - - changed = False - - display.halt() diff --git a/micropython/examples/badger2040/fonts.py b/micropython/examples/badger2040/fonts.py deleted file mode 100644 index bc420a48..00000000 --- a/micropython/examples/badger2040/fonts.py +++ /dev/null @@ -1,134 +0,0 @@ -import badger2040 -import badger_os - -# Global Constants -FONT_NAMES = ( - ("sans", 0.7, 2), - ("gothic", 0.7, 2), - ("cursive", 0.7, 2), - ("serif", 0.7, 2), - ("serif_italic", 0.7, 2), - ("bitmap6", 3, 1), - ("bitmap8", 2, 1), - ("bitmap14_outline", 1, 1) -) - -WIDTH = badger2040.WIDTH -HEIGHT = badger2040.HEIGHT - -MENU_TEXT_SIZE = 0.5 -MENU_SPACING = 16 -MENU_WIDTH = 84 -MENU_PADDING = 5 - -TEXT_INDENT = MENU_WIDTH + 10 - -ARROW_THICKNESS = 3 -ARROW_WIDTH = 18 -ARROW_HEIGHT = 14 -ARROW_PADDING = 2 - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw a upward arrow -def draw_up(x, y, width, height, thickness, padding): - border = (thickness // 4) + padding - display.line(x + border, y + height - border, - x + (width // 2), y + border) - display.line(x + (width // 2), y + border, - x + width - border, y + height - border) - - -# Draw a downward arrow -def draw_down(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw the frame of the reader -def draw_frame(): - display.pen(15) - display.clear() - display.pen(12) - display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) - display.pen(0) - display.thickness(ARROW_THICKNESS) - draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - -# Draw the fonts and menu -def draw_fonts(): - display.font("bitmap8") - display.thickness(1) - for i in range(len(FONT_NAMES)): - name, size, thickness = FONT_NAMES[i] - display.pen(0) - if i == state["selected_font"]: - display.rectangle(0, i * MENU_SPACING, MENU_WIDTH, MENU_SPACING) - display.pen(15) - - display.text(name, MENU_PADDING, (i * MENU_SPACING) + int((MENU_SPACING - 8) / 2), MENU_TEXT_SIZE) - - name, size, thickness = FONT_NAMES[state["selected_font"]] - display.font(name) - display.thickness(thickness) - - y = 0 if name.startswith("bitmap") else 10 - - display.pen(0) - for line in ("The quick", "brown fox", "jumps over", "the lazy dog.", "0123456789", "!\"£$%^&*()"): - display.text(line, TEXT_INDENT, y, size) - y += 22 - - display.thickness(1) - - display.update() - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Global variables -state = {"selected_font": 0} -badger_os.state_load("fonts", state) - -# Create a new Badger and set it to update FAST -display = badger2040.Badger2040() -display.led(128) -display.update_speed(badger2040.UPDATE_FAST) - -changed = not badger2040.woken_by_button() - -# ------------------------------ -# Main program loop -# ------------------------------ - -while True: - if display.pressed(badger2040.BUTTON_UP): - state["selected_font"] -= 1 - if state["selected_font"] < 0: - state["selected_font"] = len(FONT_NAMES) - 1 - changed = True - if display.pressed(badger2040.BUTTON_DOWN): - state["selected_font"] += 1 - if state["selected_font"] >= len(FONT_NAMES): - state["selected_font"] = 0 - changed = True - - if changed: - draw_frame() - draw_fonts() - badger_os.state_save("fonts", state) - changed = False - - display.halt() diff --git a/micropython/examples/badger2040/help.py b/micropython/examples/badger2040/help.py deleted file mode 100644 index 7d08e4bf..00000000 --- a/micropython/examples/badger2040/help.py +++ /dev/null @@ -1,42 +0,0 @@ -import badger2040 -from badger2040 import WIDTH - -TEXT_SIZE = 0.45 -LINE_HEIGHT = 20 - -display = badger2040.Badger2040() -display.led(128) - -display.pen(0) -display.rectangle(0, 0, WIDTH, 16) -display.thickness(1) -display.pen(15) -display.text("badgerOS", 3, 8, 0.4) -display.text("help", WIDTH - display.measure_text("help", 0.4) - 4, 8, 0.4) - -display.pen(0) - -TEXT_SIZE = 0.62 -y = 20 + int(LINE_HEIGHT / 2) - -display.thickness(2) -display.font("sans") -display.text("Up/Down - Change page", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -display.text("a, b or c - Launch app", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -display.text("a & c - Exit app", 0, y, TEXT_SIZE) -y += LINE_HEIGHT - -y += 8 -display.text("Up/Down & User - Font size", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -display.text("a & User - Toggle invert", 0, y, TEXT_SIZE) -y += LINE_HEIGHT - -display.update() - -# Call halt in a loop, on battery this switches off power. -# On USB, the app will exit when A+C is pressed because the launcher picks that up. -while True: - display.halt() diff --git a/micropython/examples/badger2040/image.py b/micropython/examples/badger2040/image.py deleted file mode 100644 index db31fc15..00000000 --- a/micropython/examples/badger2040/image.py +++ /dev/null @@ -1,127 +0,0 @@ -import os -import sys -import time -import badger2040 -from badger2040 import HEIGHT -import badger_os - - -REAMDE = """ -Images must be 296x128 pixel with 1bit colour depth. - -You can use examples/badger2040/image_converter/convert.py to convert them: - -python3 convert.py --binary --resize image_file_1.png image_file_2.png image_file_3.png - -Create a new "images" directory via Thonny, and upload the .bin files there. -""" - -OVERLAY_BORDER = 40 -OVERLAY_SPACING = 20 -OVERLAY_TEXT_SIZE = 0.5 - -TOTAL_IMAGES = 0 - - -# Turn the act LED on as soon as possible -display = badger2040.Badger2040() -display.led(128) - -# Try to preload BadgerPunk image -try: - os.mkdir("images") - import badgerpunk - with open("images/badgerpunk.bin", "wb") as f: - f.write(badgerpunk.data()) - f.flush() - with open("images/readme.txt", "w") as f: - f.write(REAMDE) - f.flush() - del badgerpunk -except (OSError, ImportError): - pass - -# Load images -try: - IMAGES = [f for f in os.listdir("/images") if f.endswith(".bin")] - TOTAL_IMAGES = len(IMAGES) -except OSError: - pass - - -image = bytearray(int(296 * 128 / 8)) - -state = { - "current_image": 0, - "show_info": True -} - - -def show_image(n): - file = IMAGES[n] - name = file.split(".")[0] - open("images/{}".format(file), "r").readinto(image) - display.image(image) - - if state["show_info"]: - name_length = display.measure_text(name, 0.5) - display.pen(0) - display.rectangle(0, HEIGHT - 21, name_length + 11, 21) - display.pen(15) - display.rectangle(0, HEIGHT - 20, name_length + 10, 20) - display.pen(0) - display.text(name, 5, HEIGHT - 10, 0.5) - - for i in range(TOTAL_IMAGES): - x = 286 - y = int((128 / 2) - (TOTAL_IMAGES * 10 / 2) + (i * 10)) - display.pen(0) - display.rectangle(x, y, 8, 8) - if state["current_image"] != i: - display.pen(15) - display.rectangle(x + 1, y + 1, 6, 6) - - display.update() - - -if TOTAL_IMAGES == 0: - display.pen(15) - display.clear() - badger_os.warning(display, "To run this demo, create an /images directory on your device and upload some 1bit 296x128 pixel images.") - time.sleep(4.0) - sys.exit() - - -badger_os.state_load("image", state) - -changed = not badger2040.woken_by_button() - - -while True: - if display.pressed(badger2040.BUTTON_UP): - if state["current_image"] > 0: - state["current_image"] -= 1 - changed = True - if display.pressed(badger2040.BUTTON_DOWN): - if state["current_image"] < TOTAL_IMAGES - 1: - state["current_image"] += 1 - changed = True - if display.pressed(badger2040.BUTTON_A): - state["show_info"] = not state["show_info"] - changed = True - if display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C): - display.pen(15) - display.clear() - badger_os.warning(display, "To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/") - display.update() - print(state["current_image"]) - time.sleep(4) - changed = True - - if changed: - badger_os.state_save("image", state) - show_image(state["current_image"]) - changed = False - - # Halt the Badger to save power, it will wake up if any of the front buttons are pressed - display.halt() diff --git a/micropython/examples/badger2040/info.py b/micropython/examples/badger2040/info.py deleted file mode 100644 index 3fedefe6..00000000 --- a/micropython/examples/badger2040/info.py +++ /dev/null @@ -1,42 +0,0 @@ -import badger2040 -from badger2040 import WIDTH - -TEXT_SIZE = 0.45 -LINE_HEIGHT = 16 - -display = badger2040.Badger2040() -display.led(128) - -display.pen(0) -display.rectangle(0, 0, WIDTH, 16) -display.thickness(1) -display.pen(15) -display.text("badgerOS", 3, 8, 0.4) -display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 8, 0.4) - -display.pen(0) - -y = 16 + int(LINE_HEIGHT / 2) - -display.text("Made by Pimoroni, powered by MicroPython", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -display.text("Dual-core RP2040, 133MHz, 264KB RAM", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -display.text("2MB Flash (1MB OS, 1MB Storage)", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -display.text("296x128 pixel Black/White e-Ink", 0, y, TEXT_SIZE) -y += LINE_HEIGHT -y += LINE_HEIGHT - -display.thickness(2) -display.text("For more info:", 0, y, TEXT_SIZE) -display.thickness(1) -y += LINE_HEIGHT -display.text("https://pimoroni.com/badger2040", 0, y, TEXT_SIZE) - -display.update() - -# Call halt in a loop, on battery this switches off power. -# On USB, the app will exit when A+C is pressed because the launcher picks that up. -while True: - display.halt() diff --git a/micropython/examples/badger2040/launcher.py b/micropython/examples/badger2040/launcher.py deleted file mode 100644 index 8c043dc9..00000000 --- a/micropython/examples/badger2040/launcher.py +++ /dev/null @@ -1,241 +0,0 @@ -import gc -import time -import math -import badger2040 -from badger2040 import WIDTH -import launchericons -import badger_os - -# Reduce clock speed to 48MHz -badger2040.system_speed(badger2040.SYSTEM_NORMAL) - -changed = False -exited_to_launcher = False -woken_by_button = badger2040.woken_by_button() # Must be done before we clear_pressed_to_wake - -if badger2040.pressed_to_wake(badger2040.BUTTON_A) and badger2040.pressed_to_wake(badger2040.BUTTON_C): - # Pressing A and C together at start quits app - exited_to_launcher = badger_os.state_clear_running() -else: - # Otherwise restore previously running app - badger_os.state_launch() - -# for e.g. 2xAAA batteries, try max 3.4 min 3.0 -MAX_BATTERY_VOLTAGE = 4.0 -MIN_BATTERY_VOLTAGE = 3.2 - -display = badger2040.Badger2040() -display.led(128) - -state = { - "page": 0, - "font_size": 1, - "inverted": False, - "running": "launcher" -} - -badger_os.state_load("launcher", state) - -display.invert(state["inverted"]) - -icons = bytearray(launchericons.data()) -icons_width = 576 - -examples = [ - ("_clock", 0), - ("_fonts", 1), - ("_ebook", 2), - ("_image", 3), - ("_list", 4), - ("_badge", 5), - ("_qrgen", 8), - ("_info", 6), - ("_help", 7), -] - -font_sizes = (0.5, 0.7, 0.9) - -# Approximate center lines for buttons A, B and C -centers = (41, 147, 253) - -MAX_PAGE = math.ceil(len(examples) / 3) - - -def map_value(input, in_min, in_max, out_min, out_max): - return (((input - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min - - -def draw_battery(level, x, y): - # Outline - display.thickness(1) - display.pen(15) - display.rectangle(x, y, 19, 10) - # Terminal - display.rectangle(x + 19, y + 3, 2, 4) - display.pen(0) - display.rectangle(x + 1, y + 1, 17, 8) - if level < 1: - display.pen(0) - display.line(x + 3, y, x + 3 + 10, y + 10) - display.line(x + 3 + 1, y, x + 3 + 11, y + 10) - display.pen(15) - display.line(x + 2 + 2, y - 1, x + 4 + 12, y + 11) - display.line(x + 2 + 3, y - 1, x + 4 + 13, y + 11) - return - # Battery Bars - display.pen(15) - for i in range(4): - if level / 4 > (1.0 * i) / 4: - display.rectangle(i * 4 + x + 2, y + 2, 3, 6) - - -def draw_disk_usage(x): - _, f_used, _ = badger_os.get_disk_usage() - - display.image( - bytearray( - ( - 0b00000000, - 0b00111100, - 0b00111100, - 0b00111100, - 0b00111000, - 0b00000000, - 0b00000000, - 0b00000001, - ) - ), - 8, - 8, - x, - 4, - ) - display.pen(15) - display.rectangle(x + 10, 3, 80, 10) - display.pen(0) - display.rectangle(x + 11, 4, 78, 8) - display.pen(15) - display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6) - display.text("{:.2f}%".format(f_used), x + 91, 8, 0.4) - - -def render(): - display.pen(15) - display.clear() - display.pen(0) - display.thickness(2) - - max_icons = min(3, len(examples[(state["page"] * 3):])) - - for i in range(max_icons): - x = centers[i] - label, icon = examples[i + (state["page"] * 3)] - label = label[1:].replace("_", " ") - display.pen(0) - display.icon(icons, icon, icons_width, 64, x - 32, 24) - w = display.measure_text(label, font_sizes[state["font_size"]]) - display.text(label, x - int(w / 2), 16 + 80, font_sizes[state["font_size"]]) - - for i in range(MAX_PAGE): - x = 286 - y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10)) - display.pen(0) - display.rectangle(x, y, 8, 8) - if state["page"] != i: - display.pen(15) - display.rectangle(x + 1, y + 1, 6, 6) - - display.pen(0) - display.rectangle(0, 0, WIDTH, 16) - display.thickness(1) - draw_disk_usage(90) - vbat = badger_os.get_battery_level() - bat = int(map_value(vbat, MIN_BATTERY_VOLTAGE, MAX_BATTERY_VOLTAGE, 0, 4)) - draw_battery(bat, WIDTH - 22 - 3, 3) - display.pen(15) - display.text("badgerOS", 3, 8, 0.4) - - display.update() - - -def wait_for_user_to_release_buttons(): - pr = display.pressed - while pr(badger2040.BUTTON_A) or pr(badger2040.BUTTON_B) or pr(badger2040.BUTTON_C) or pr(badger2040.BUTTON_UP) or pr(badger2040.BUTTON_DOWN): - time.sleep(0.01) - - -def launch_example(index): - wait_for_user_to_release_buttons() - - file = examples[(state["page"] * 3) + index][0] - - for k in locals().keys(): - if k not in ("gc", "file", "badger_os"): - del locals()[k] - - gc.collect() - - badger_os.launch(file) - - -def button(pin): - global changed - changed = True - - if not display.pressed(badger2040.BUTTON_USER): # User button is NOT held down - if pin == badger2040.BUTTON_A: - launch_example(0) - if pin == badger2040.BUTTON_B: - launch_example(1) - if pin == badger2040.BUTTON_C: - launch_example(2) - if pin == badger2040.BUTTON_UP: - if state["page"] > 0: - state["page"] -= 1 - render() - if pin == badger2040.BUTTON_DOWN: - if state["page"] < MAX_PAGE - 1: - state["page"] += 1 - render() - else: # User button IS held down - if pin == badger2040.BUTTON_UP: - state["font_size"] += 1 - if state["font_size"] == len(font_sizes): - state["font_size"] = 0 - render() - if pin == badger2040.BUTTON_DOWN: - state["font_size"] -= 1 - if state["font_size"] < 0: - state["font_size"] = 0 - render() - if pin == badger2040.BUTTON_A: - state["inverted"] = not state["inverted"] - display.invert(state["inverted"]) - render() - - -if exited_to_launcher or not woken_by_button: - wait_for_user_to_release_buttons() - display.update_speed(badger2040.UPDATE_MEDIUM) - render() - -display.update_speed(badger2040.UPDATE_FAST) - -while True: - if display.pressed(badger2040.BUTTON_A): - button(badger2040.BUTTON_A) - if display.pressed(badger2040.BUTTON_B): - button(badger2040.BUTTON_B) - if display.pressed(badger2040.BUTTON_C): - button(badger2040.BUTTON_C) - - if display.pressed(badger2040.BUTTON_UP): - button(badger2040.BUTTON_UP) - if display.pressed(badger2040.BUTTON_DOWN): - button(badger2040.BUTTON_DOWN) - - if changed: - badger_os.state_save("launcher", state) - changed = False - - display.halt() diff --git a/micropython/examples/badger2040/led.py b/micropython/examples/badger2040/led.py deleted file mode 100644 index f37e9e19..00000000 --- a/micropython/examples/badger2040/led.py +++ /dev/null @@ -1,15 +0,0 @@ -# Blinky badger fun! - -import badger2040 -import time - -badger = badger2040.Badger2040() - -while True: - # increase badger.led brightness from 0 to 255 and back down to zero - for i in range(0, 255): - badger.led(i) - time.sleep_ms(10) - for i in range(255, 0, -1): - badger.led(i) - time.sleep_ms(10) diff --git a/micropython/examples/badger2040/list.py b/micropython/examples/badger2040/list.py deleted file mode 100644 index f7ce2e28..00000000 --- a/micropython/examples/badger2040/list.py +++ /dev/null @@ -1,315 +0,0 @@ -import binascii - -import badger2040 -import badger_os - -# **** Put your list title here ***** -list_title = "Checklist" -list_file = "checklist.txt" - - -# Global Constants -WIDTH = badger2040.WIDTH -HEIGHT = badger2040.HEIGHT - -ARROW_THICKNESS = 3 -ARROW_WIDTH = 18 -ARROW_HEIGHT = 14 -ARROW_PADDING = 2 - -MAX_ITEM_CHARS = 26 -TITLE_TEXT_SIZE = 0.7 -ITEM_TEXT_SIZE = 0.6 -ITEM_SPACING = 20 - -LIST_START = 40 -LIST_PADDING = 2 -LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH -LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT - - -# Default list items - change the list items by editing checklist.txt -list_items = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"] -save_checklist = False - -try: - with open("checklist.txt", "r") as f: - raw_list_items = f.read() - - if raw_list_items.find(" X\n") != -1: - # Have old style checklist, preserve state and note we should resave the list to remove the Xs - list_items = [] - state = { - "current_item": 0, - "checked": [] - } - for item in raw_list_items.strip().split("\n"): - if item.endswith(" X"): - state["checked"].append(True) - item = item[:-2] - else: - state["checked"].append(False) - list_items.append(item) - state["items_hash"] = binascii.crc32("\n".join(list_items)) - - badger_os.state_save("list", state) - save_checklist = True - else: - list_items = [item.strip() for item in raw_list_items.strip().split("\n")] - -except OSError: - save_checklist = True - -if save_checklist: - with open("checklist.txt", "w") as f: - for item in list_items: - f.write(item + "\n") - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw the list of items -def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns): - item_x = 0 - item_y = 0 - current_col = 0 - for i in range(start_item, len(items)): - if i == highlighted_item: - display.pen(12) - display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height) - display.pen(0) - display.text(items[i], item_x + x + item_height, item_y + y, ITEM_TEXT_SIZE) - draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2) - item_y += item_height - if item_y >= height - (item_height // 2): - item_x += width // columns - item_y = 0 - current_col += 1 - if current_col >= columns: - return - - -# Draw a upward arrow -def draw_up(x, y, width, height, thickness, padding): - border = (thickness // 4) + padding - display.line(x + border, y + height - border, - x + (width // 2), y + border) - display.line(x + (width // 2), y + border, - x + width - border, y + height - border) - - -# Draw a downward arrow -def draw_down(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw a left arrow -def draw_left(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + width - border, y + border, - x + border, y + (height // 2)) - display.line(x + border, y + (height // 2), - x + width - border, y + height - border) - - -# Draw a right arrow -def draw_right(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + width - border, y + (height // 2)) - display.line(x + width - border, y + (height // 2), - x + border, y + height - border) - - -# Draw a tick -def draw_tick(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + ((height * 2) // 3), - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw a cross -def draw_cross(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, x + width - border, y + height - border) - display.line(x + width - border, y + border, x + border, y + height - border) - - -# Draw a checkbox with or without a tick -def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding): - border = (thickness // 2) + padding - display.pen(background) - display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2)) - display.pen(foreground) - display.thickness(thickness) - display.line(x + border, y + border, x + size - border, y + border) - display.line(x + border, y + border, x + border, y + size - border) - display.line(x + size - border, y + border, x + size - border, y + size - border) - display.line(x + border, y + size - border, x + size - border, y + size - border) - if tick: - draw_tick(x, y, size, size, thickness, 2 + border) - - -# ------------------------------ -# Program setup -# ------------------------------ - -changed = not badger2040.woken_by_button() -state = { - "current_item": 0, -} -badger_os.state_load("list", state) -items_hash = binascii.crc32("\n".join(list_items)) -if "items_hash" not in state or state["items_hash"] != items_hash: - # Item list changed, or not yet written reset the list - state["current_item"] = 0 - state["items_hash"] = items_hash - state["checked"] = [False] * len(list_items) - changed = True - -# Global variables -items_per_page = 0 - -# Create a new Badger and set it to update FAST -display = badger2040.Badger2040() -display.led(128) -if changed: - display.update_speed(badger2040.UPDATE_FAST) -else: - display.update_speed(badger2040.UPDATE_TURBO) - -# Find out what the longest item is -longest_item = 0 -for i in range(len(list_items)): - while True: - item = list_items[i] - item_length = display.measure_text(item, ITEM_TEXT_SIZE) - if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING: - list_items[i] = item[:-1] - else: - break - longest_item = max(longest_item, display.measure_text(list_items[i], ITEM_TEXT_SIZE)) - - -# And use that to calculate the number of columns we can fit onscreen and how many items that would give -list_columns = 1 -while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)): - list_columns += 1 - -items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns - - -# ------------------------------ -# Main program loop -# ------------------------------ - -while True: - if len(list_items) > 0: - if display.pressed(badger2040.BUTTON_A): - if state["current_item"] > 0: - page = state["current_item"] // items_per_page - state["current_item"] = max(state["current_item"] - (items_per_page) // list_columns, 0) - if page != state["current_item"] // items_per_page: - display.update_speed(badger2040.UPDATE_FAST) - changed = True - if display.pressed(badger2040.BUTTON_B): - state["checked"][state["current_item"]] = not state["checked"][state["current_item"]] - changed = True - if display.pressed(badger2040.BUTTON_C): - if state["current_item"] < len(list_items) - 1: - page = state["current_item"] // items_per_page - state["current_item"] = min(state["current_item"] + (items_per_page) // list_columns, len(list_items) - 1) - if page != state["current_item"] // items_per_page: - display.update_speed(badger2040.UPDATE_FAST) - changed = True - if display.pressed(badger2040.BUTTON_UP): - if state["current_item"] > 0: - state["current_item"] -= 1 - changed = True - if display.pressed(badger2040.BUTTON_DOWN): - if state["current_item"] < len(list_items) - 1: - state["current_item"] += 1 - changed = True - - if changed: - badger_os.state_save("list", state) - - display.pen(15) - display.clear() - - display.pen(12) - display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) - display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT) - - y = LIST_PADDING + 12 - display.pen(0) - display.thickness(3) - display.text(list_title, LIST_PADDING, y, TITLE_TEXT_SIZE) - - y += 12 - display.pen(0) - display.thickness(2) - display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y) - - if len(list_items) > 0: - page_item = 0 - if items_per_page > 0: - page_item = (state["current_item"] // items_per_page) * items_per_page - - # Draw the list - display.pen(0) - display.thickness(2) - draw_list(list_items, state["checked"], page_item, state["current_item"], LIST_PADDING, LIST_START, - LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns) - - # Draw the interaction button icons - display.pen(0) - display.thickness(ARROW_THICKNESS) - - # Previous item - if state["current_item"] > 0: - draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - # Next item - if state["current_item"] < (len(list_items) - 1): - draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - # Previous column - if state["current_item"] > 0: - draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - # Next column - if state["current_item"] < (len(list_items) - 1): - draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - if state["checked"][state["current_item"]]: - # Tick off item - draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - else: - # Untick item - draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - else: - # Say that the list is empty - empty_text = "Nothing Here" - text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE) - display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), ITEM_TEXT_SIZE) - - display.update() - display.update_speed(badger2040.UPDATE_TURBO) - changed = False - - display.halt() diff --git a/micropython/examples/badger2040/micropython-builtins.cmake b/micropython/examples/badger2040/micropython-builtins.cmake deleted file mode 100644 index 68c04aee..00000000 --- a/micropython/examples/badger2040/micropython-builtins.cmake +++ /dev/null @@ -1,55 +0,0 @@ -function (convert_image TARGET IMAGE) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${IMAGE}.py - - COMMAND - cd ${CMAKE_CURRENT_LIST_DIR}/assets && python3 ../../../../examples/badger2040/image_converter/convert.py --out_dir ${CMAKE_CURRENT_BINARY_DIR}/../modules --py ${IMAGE}.png - - DEPENDS ${CMAKE_CURRENT_LIST_DIR}/assets/${IMAGE}.png - ) - target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${IMAGE}.py) -endfunction() - -function (convert_raw TARGET SRC DST) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py - - COMMAND - cd ${CMAKE_CURRENT_LIST_DIR}/assets && python3 ../../../../examples/badger2040/image_converter/data_to_py.py ${CMAKE_CURRENT_LIST_DIR}/assets/${SRC} ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py - - DEPENDS ${CMAKE_CURRENT_LIST_DIR}/assets/${SRC} - ) - target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py) -endfunction() - -function (copy_module TARGET SRC DST) - add_custom_command( - OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py - - COMMAND - cp ${SRC} ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py - - DEPENDS ${SRC} - ) - - target_sources(${TARGET} INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/../modules/${DST}.py) -endfunction() - -convert_image(usermod_badger2040 badge_image) -convert_image(usermod_badger2040 badgerpunk) -convert_image(usermod_badger2040 launchericons) - -convert_raw(usermod_badger2040 289-0-wind-in-the-willows-abridged.txt witw) - -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/assets/boot.py boot) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/launcher.py _launcher) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/clock.py _clock) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/fonts.py _fonts) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/ebook.py _ebook) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/image.py _image) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/list.py _list) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badge.py _badge) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/help.py _help) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/info.py _info) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/qrgen.py _qrgen) -copy_module(usermod_badger2040 ${CMAKE_CURRENT_LIST_DIR}/badger_os.py badger_os) diff --git a/micropython/examples/badger2040/pin_interrupt.py b/micropython/examples/badger2040/pin_interrupt.py deleted file mode 100644 index 3220dd42..00000000 --- a/micropython/examples/badger2040/pin_interrupt.py +++ /dev/null @@ -1,65 +0,0 @@ -import badger2040 -import machine - -display = badger2040.Badger2040() - -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) - -display.thickness(10) -display.pen(0) -display.line(0, 5, 295, 5) -display.line(0, 123, 295, 123) - -display.thickness(1) -for x in range(14): - display.line(x * 20, 10, x * 20, 118) - -display.line(0, 0, 295, 127) -display.line(0, 127, 295, 0) - -display.font("sans") -display.thickness(5) -display.text("Hello World", 10, 30, 1.0) -display.pen(7) -display.text("Hello World", 10, 60, 1.0) -display.pen(11) -display.text("Hello World", 10, 90, 1.0) - -display.update() - -dirty = False -pressed = None - - -def button(pin): - global dirty, pressed - if pin == button_a: - pressed = "Button A" - dirty = True - return - if pin == button_b: - pressed = "Button B" - dirty = True - return - - -button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=button) -button_b.irq(trigger=machine.Pin.IRQ_RISING, handler=button) - -# This breaks Thonny, since it's no longer possible to Stop the code -# need to press the reset button on the board... -# It will also crash your USB bus, probably, your whole bus... -# @micropython.asm_thumb -# def lightsleep(): -# wfi() - -while True: - if dirty: - display.pen(15) - display.clear() - display.pen(0) - display.text(pressed, 10, 60, 2.0) - display.update() - dirty = False - # machine.lightsleep() # Currently imposible to wake from this on IRQ diff --git a/micropython/examples/badger2040/qrgen.py b/micropython/examples/badger2040/qrgen.py deleted file mode 100644 index de6fcc19..00000000 --- a/micropython/examples/badger2040/qrgen.py +++ /dev/null @@ -1,155 +0,0 @@ -import badger2040 -import qrcode -import time -import os -import badger_os - -# Check that the qrcodes directory exists, if not, make it -try: - os.mkdir("qrcodes") -except OSError: - pass - -# Load all available QR Code Files -try: - CODES = [f for f in os.listdir("/qrcodes") if f.endswith(".txt")] -except OSError: - CODES = [] - -# create demo QR code file if no QR code files exist -if len(CODES) == 0: - try: - new_qr_code_filename = "qrcode.txt" - with open(f"/qrcodes/{new_qr_code_filename}", "w") as text: - text.write("""https://pimoroni.com/badger2040 -Badger 2040 -* 296x128 1-bit e-ink -* six user buttons -* user LED -* 2MB QSPI flash - -Scan this code to learn -more about Badger 2040. -""") - text.flush() - - # Set the CODES list to contain the new_qr_code_filename (created above) - CODES = [new_qr_code_filename] - - except OSError: - CODES = [] - -TOTAL_CODES = len(CODES) - -display = badger2040.Badger2040() - -code = qrcode.QRCode() - - -state = { - "current_qr": 0 -} - - -def set_state_current_index_in_range(): - badger_os.state_load("qrcodes", state) - if state["current_qr"] >= len(CODES): - state["current_qr"] = len(CODES) - 1 # set to last index (zero-based). Note: will set to -1 if currently 0 - if state["current_qr"] < 0: # check that the index is not negative, thus still out of range - state["current_qr"] = 0 - badger_os.state_save("qrcodes", state) - - -def measure_qr_code(size, code): - w, h = code.get_size() - module_size = int(size / w) - return module_size * w, module_size - - -def draw_qr_code(ox, oy, size, code): - size, module_size = measure_qr_code(size, code) - display.pen(15) - display.rectangle(ox, oy, size, size) - display.pen(0) - for x in range(size): - for y in range(size): - if code.get_module(x, y): - display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size) - - -def draw_qr_file(n): - display.led(128) - file = CODES[n] - - try: - with open(f"/qrcodes/{file}", "r") as codetext: - lines = codetext.read().strip().split("\n") - except OSError: - lines = ["", "", "", "", "", "", "", "", "", ""] - - code_text = lines.pop(0) - title_text = lines.pop(0) - detail_text = lines - - # Clear the Display - display.pen(15) # Change this to 0 if a white background is used - display.clear() - display.pen(0) - - code.set_text(code_text) - size, _ = measure_qr_code(128, code) - left = top = int((badger2040.HEIGHT / 2) - (size / 2)) - draw_qr_code(left, top, 128, code) - - left = 128 + 5 - - display.thickness(2) - display.text(title_text, left, 20, 0.5) - display.thickness(1) - - top = 40 - for line in detail_text: - display.text(line, left, top, 0.4) - top += 10 - - if TOTAL_CODES > 1: - for i in range(TOTAL_CODES): - x = 286 - y = int((128 / 2) - (TOTAL_CODES * 10 / 2) + (i * 10)) - display.pen(0) - display.rectangle(x, y, 8, 8) - if state["current_qr"] != i: - display.pen(15) - display.rectangle(x + 1, y + 1, 6, 6) - display.update() - - -set_state_current_index_in_range() -changed = not badger2040.woken_by_button() - -while True: - if TOTAL_CODES > 1: - if display.pressed(badger2040.BUTTON_UP): - if state["current_qr"] > 0: - state["current_qr"] -= 1 - changed = True - - if display.pressed(badger2040.BUTTON_DOWN): - if state["current_qr"] < TOTAL_CODES - 1: - state["current_qr"] += 1 - changed = True - - if display.pressed(badger2040.BUTTON_B) or display.pressed(badger2040.BUTTON_C): - display.pen(15) - display.clear() - badger_os.warning(display, "To add QR codes, connect Badger2040 to a PC, load up Thonny, and see qrgen.py.") - time.sleep(4) - changed = True - - if changed: - draw_qr_file(state["current_qr"]) - badger_os.state_save("qrcodes", state) - changed = False - - # Halt the Badger to save power, it will wake up if any of the front buttons are pressed - display.halt() diff --git a/micropython/examples/badger2040w/WIFI_CONFIG.py b/micropython/examples/badger2040w/WIFI_CONFIG.py deleted file mode 100644 index ed8ec292..00000000 --- a/micropython/examples/badger2040w/WIFI_CONFIG.py +++ /dev/null @@ -1,3 +0,0 @@ -SSID = "" -PSK = "" -COUNTRY = "" # Change to your local two-letter ISO 3166-1 country code diff --git a/micropython/examples/badger2040w/badges/badge.jpg b/micropython/examples/badger2040w/badges/badge.jpg deleted file mode 100644 index 287a43ca98546b172d0367c5f8dcad52d380ac42..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 7878 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 0 and length > width: - text = text[:-1] - else: - text += "" - return text - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw the badge, including user text -def draw_badge(): - display.set_pen(0) - display.clear() - - # Draw badge image - jpeg.open_file(badge_image) - jpeg.decode(WIDTH - IMAGE_WIDTH, 0) - - # Draw a border around the image - display.set_pen(0) - display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - 1, 0) - display.line(WIDTH - IMAGE_WIDTH, 0, WIDTH - IMAGE_WIDTH, HEIGHT - 1) - display.line(WIDTH - IMAGE_WIDTH, HEIGHT - 1, WIDTH - 1, HEIGHT - 1) - display.line(WIDTH - 1, 0, WIDTH - 1, HEIGHT - 1) - - # Uncomment this if a white background is wanted behind the company - # display.set_pen(15) - # display.rectangle(1, 1, TEXT_WIDTH, COMPANY_HEIGHT - 1) - - # Draw the company - display.set_pen(15) # Change this to 0 if a white background is used - display.set_font("serif") - display.text(company, LEFT_PADDING, (COMPANY_HEIGHT // 2) + 1, WIDTH, COMPANY_TEXT_SIZE) - - # Draw a white background behind the name - display.set_pen(15) - display.rectangle(1, COMPANY_HEIGHT + 1, TEXT_WIDTH, NAME_HEIGHT) - - # Draw the name, scaling it based on the available width - display.set_pen(0) - display.set_font("sans") - name_size = 2.0 # A sensible starting scale - while True: - name_length = display.measure_text(name, name_size) - if name_length >= (TEXT_WIDTH - NAME_PADDING) and name_size >= 0.1: - name_size -= 0.01 - else: - display.text(name, (TEXT_WIDTH - name_length) // 2, (NAME_HEIGHT // 2) + COMPANY_HEIGHT + 1, WIDTH, name_size) - break - - # Draw a white backgrounds behind the details - display.set_pen(15) - display.rectangle(1, HEIGHT - DETAILS_HEIGHT * 2, TEXT_WIDTH, DETAILS_HEIGHT - 1) - display.rectangle(1, HEIGHT - DETAILS_HEIGHT, TEXT_WIDTH, DETAILS_HEIGHT - 1) - - # Draw the first detail's title and text - display.set_pen(0) - display.set_font("sans") - name_length = display.measure_text(detail1_title, DETAILS_TEXT_SIZE) - display.text(detail1_title, LEFT_PADDING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE) - display.text(detail1_text, 5 + name_length + DETAIL_SPACING, HEIGHT - ((DETAILS_HEIGHT * 3) // 2), WIDTH, DETAILS_TEXT_SIZE) - - # Draw the second detail's title and text - name_length = display.measure_text(detail2_title, DETAILS_TEXT_SIZE) - display.text(detail2_title, LEFT_PADDING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE) - display.text(detail2_text, LEFT_PADDING + name_length + DETAIL_SPACING, HEIGHT - (DETAILS_HEIGHT // 2), WIDTH, DETAILS_TEXT_SIZE) - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Create a new Badger and set it to update NORMAL -display = badger2040w.Badger2040W() -display.led(128) -display.set_update_speed(badger2040w.UPDATE_NORMAL) -display.set_thickness(2) - -jpeg = jpegdec.JPEG(display.display) - -# Open the badge file -try: - badge = open(BADGE_PATH, "r") -except OSError: - with open(BADGE_PATH, "w") as f: - f.write(DEFAULT_TEXT) - f.flush() - badge = open(BADGE_PATH, "r") - -# Read in the next 6 lines -company = badge.readline() # "mustelid inc" -name = badge.readline() # "H. Badger" -detail1_title = badge.readline() # "RP2040" -detail1_text = badge.readline() # "2MB Flash" -detail2_title = badge.readline() # "E ink" -detail2_text = badge.readline() # "296x128px" -badge_image = badge.readline() # /badges/badge.jpg - -# Truncate all of the text (except for the name as that is scaled) -company = truncatestring(company, COMPANY_TEXT_SIZE, TEXT_WIDTH) - -detail1_title = truncatestring(detail1_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) -detail1_text = truncatestring(detail1_text, DETAILS_TEXT_SIZE, - TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail1_title, DETAILS_TEXT_SIZE)) - -detail2_title = truncatestring(detail2_title, DETAILS_TEXT_SIZE, TEXT_WIDTH) -detail2_text = truncatestring(detail2_text, DETAILS_TEXT_SIZE, - TEXT_WIDTH - DETAIL_SPACING - display.measure_text(detail2_title, DETAILS_TEXT_SIZE)) - - -# ------------------------------ -# Main program -# ------------------------------ - -draw_badge() - -while True: - if display.pressed(badger2040w.BUTTON_A) or display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C) or display.pressed(badger2040w.BUTTON_UP) or display.pressed(badger2040w.BUTTON_DOWN): - badger_os.warning(display, "To change the text, connect Badger2040 to a PC, load up Thonny, and modify badge.txt") - time.sleep(4) - - draw_badge() - - display.update() - - # If on battery, halt the Badger to save power, it will wake up if any of the front buttons are pressed - display.halt() diff --git a/micropython/examples/badger2040w/examples/clock.py b/micropython/examples/badger2040w/examples/clock.py deleted file mode 100644 index 12175438..00000000 --- a/micropython/examples/badger2040w/examples/clock.py +++ /dev/null @@ -1,94 +0,0 @@ -import time -import machine -import ntptime -import badger2040w - - -display = badger2040w.Badger2040W() -display.set_update_speed(2) -display.set_thickness(4) - -WIDTH, HEIGHT = display.get_bounds() - -try: - display.connect() - if display.isconnected(): - ntptime.settime() -except (RuntimeError, OSError): - pass # no WiFI - -rtc = machine.RTC() - -display.set_font("gothic") - - -def draw_clock(): - global second_offset, second_unit_offset - - hms = "{:02}:{:02}:{:02}".format(hour, minute, second) - ymd = "{:04}/{:02}/{:02}".format(year, month, day) - - hms_width = display.measure_text(hms, 1.8) - hms_offset = int((WIDTH / 2) - (hms_width / 2)) - - ymd_width = display.measure_text(ymd, 1.0) - ymd_offset = int((WIDTH / 2) - (ymd_width / 2)) - - display.set_pen(15) - display.clear() - display.set_pen(0) - - display.text(hms, hms_offset, 40, 0, 1.8) - display.text(ymd, ymd_offset, 100, 0, 1.0) - - display.set_update_speed(2) - display.update() - display.set_update_speed(3) - - hms = "{:02}:{:02}:".format(hour, minute) - second_offset = hms_offset + display.measure_text(hms, 1.8) - hms = "{:02}:{:02}:{}".format(hour, minute, second // 10) - second_unit_offset = hms_offset + display.measure_text(hms, 1.8) - - -def draw_second(): - global second_offset, second_unit_offset - - display.set_pen(15) - display.rectangle(second_offset, 8, 75, 56) - display.set_pen(0) - - if second // 10 != last_second // 10: - s = "{:02}".format(second) - display.text(s, second_offset, 40, 0, 1.8) - display.partial_update(second_offset, 8, 75, 56) - - s = "{}".format(second // 10) - second_unit_offset = second_offset + display.measure_text(s, 1.8) - - else: - s = "{}".format(second % 10) - display.text(s, second_unit_offset, 40, 0, 1.8) - display.partial_update(second_unit_offset, 8, 75 - (second_unit_offset - second_offset), 56) - - -year, month, day, wd, hour, minute, second, _ = rtc.datetime() - -if (year, month, day) == (2021, 1, 1): - rtc.datetime((2022, 2, 28, 0, 12, 0, 0, 0)) - -last_second = second -last_minute = minute -draw_clock() - - -while True: - year, month, day, wd, hour, minute, second, _ = rtc.datetime() - if second != last_second: - if minute != last_minute: - draw_clock() - last_minute = minute - else: - draw_second() - last_second = second - time.sleep(0.01) diff --git a/micropython/examples/badger2040w/examples/ebook.py b/micropython/examples/badger2040w/examples/ebook.py deleted file mode 100644 index 31fa27b0..00000000 --- a/micropython/examples/badger2040w/examples/ebook.py +++ /dev/null @@ -1,244 +0,0 @@ -import badger2040w -import gc -import badger_os - -# **** Put the name of your text file here ***** -text_file = "/books/289-0-wind-in-the-willows-abridged.txt" # File must be on the MicroPython device - -gc.collect() - -# Global Constants -WIDTH = badger2040w.WIDTH -HEIGHT = badger2040w.HEIGHT - -ARROW_THICKNESS = 3 -ARROW_WIDTH = 18 -ARROW_HEIGHT = 14 -ARROW_PADDING = 2 - -TEXT_PADDING = 4 -TEXT_WIDTH = WIDTH - TEXT_PADDING - TEXT_PADDING - ARROW_WIDTH - -FONTS = ["sans", "gothic", "cursive", "serif"] -THICKNESSES = [2, 1, 1, 2] -# ------------------------------ -# Drawing functions -# ------------------------------ - - -# Draw a upward arrow -def draw_up(x, y, width, height, thickness, padding): - border = (thickness // 4) + padding - display.line(x + border, y + height - border, - x + (width // 2), y + border) - display.line(x + (width // 2), y + border, - x + width - border, y + height - border) - - -# Draw a downward arrow -def draw_down(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw the frame of the reader -def draw_frame(): - display.set_pen(15) - display.clear() - display.set_pen(12) - display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) - display.set_pen(0) - if state["current_page"] > 0: - draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Global variables -state = { - "last_offset": 0, - "current_page": 0, - "font_idx": 0, - "text_size": 0.5, - "offsets": [] -} -badger_os.state_load("ebook", state) - -text_spacing = int(34 * state["text_size"]) - - -# Create a new Badger and set it to update FAST -display = badger2040w.Badger2040W() -display.led(128) -display.set_update_speed(badger2040w.UPDATE_FAST) - - -# ------------------------------ -# Render page -# ------------------------------ - -def render_page(): - row = 0 - line = "" - pos = ebook.tell() - next_pos = pos - add_newline = False - display.set_font(FONTS[state["font_idx"]]) - display.set_thickness(THICKNESSES[state["font_idx"]]) - - while True: - # Read a full line and split it into words - words = ebook.readline().split(" ") - - # Take the length of the first word and advance our position - next_word = words[0] - if len(words) > 1: - next_pos += len(next_word) + 1 - else: - next_pos += len(next_word) # This is the last word on the line - - # Advance our position further if the word contains special characters - if '\u201c' in next_word: - next_word = next_word.replace('\u201c', '\"') - next_pos += 2 - if '\u201d' in next_word: - next_word = next_word.replace('\u201d', '\"') - next_pos += 2 - if '\u2019' in next_word: - next_word = next_word.replace('\u2019', '\'') - next_pos += 2 - - # Rewind the file back from the line end to the start of the next word - ebook.seek(next_pos) - - # Strip out any new line characters from the word - next_word = next_word.strip() - - # If an empty word is encountered assume that means there was a blank line - if len(next_word) == 0: - add_newline = True - - # Append the word to the current line and measure its length - appended_line = line - if len(line) > 0 and len(next_word) > 0: - appended_line += " " - appended_line += next_word - appended_length = display.measure_text(appended_line, state["text_size"]) - - # Would this appended line be longer than the text display area, or was a blank line spotted? - if appended_length >= TEXT_WIDTH or add_newline: - - # Yes, so write out the line prior to the append - print(line) - display.set_pen(0) - display.text(line, TEXT_PADDING, (row * text_spacing) + (text_spacing // 2) + TEXT_PADDING, WIDTH, state["text_size"]) - - # Clear the line and move on to the next row - line = "" - row += 1 - - # Have we reached the end of the page? - if (row * text_spacing) + text_spacing >= HEIGHT: - print("+++++") - display.update() - - # Reset the position to the start of the word that made this line too long - ebook.seek(pos) - return - else: - # Set the line to the word and advance the current position - line = next_word - pos = next_pos - - # A new line was spotted, so advance a row - if add_newline: - print("") - row += 1 - if (row * text_spacing) + text_spacing >= HEIGHT: - print("+++++") - display.update() - return - add_newline = False - else: - # The appended line was not too long, so set it as the line and advance the current position - line = appended_line - pos = next_pos - - -# ------------------------------ -# Main program loop -# ------------------------------ - -launch = True -changed = False - -# Open the book file -ebook = open(text_file, "r") -if len(state["offsets"]) > state["current_page"]: - ebook.seek(state["offsets"][state["current_page"]]) -else: - state["current_page"] = 0 - state["offsets"] = [] - -while True: - # Was the next page button pressed? - if display.pressed(badger2040w.BUTTON_DOWN): - state["current_page"] += 1 - - changed = True - - # Was the previous page button pressed? - if display.pressed(badger2040w.BUTTON_UP): - if state["current_page"] > 0: - state["current_page"] -= 1 - if state["current_page"] == 0: - ebook.seek(0) - else: - ebook.seek(state["offsets"][state["current_page"] - 1]) # Retrieve the start position of the last page - changed = True - - if display.pressed(badger2040w.BUTTON_A): - state["text_size"] += 0.1 - if state["text_size"] > 0.8: - state["text_size"] = 0.5 - text_spacing = int(34 * state["text_size"]) - state["offsets"] = [] - ebook.seek(0) - state["current_page"] = 0 - changed = True - - if display.pressed(badger2040w.BUTTON_B): - state["font_idx"] += 1 - if (state["font_idx"] >= len(FONTS)): - state["font_idx"] = 0 - state["offsets"] = [] - ebook.seek(0) - state["current_page"] = 0 - changed = True - - if launch and not changed: - if state["current_page"] > 0 and len(state["offsets"]) > state["current_page"] - 1: - ebook.seek(state["offsets"][state["current_page"] - 1]) - changed = True - launch = False - - if changed: - draw_frame() - render_page() - - # Is the next page one we've not displayed before? - if state["current_page"] >= len(state["offsets"]): - state["offsets"].append(ebook.tell()) # Add its start position to the state["offsets"] list - badger_os.state_save("ebook", state) - - changed = False - - display.halt() diff --git a/micropython/examples/badger2040w/examples/fonts.py b/micropython/examples/badger2040w/examples/fonts.py deleted file mode 100644 index 30699ad8..00000000 --- a/micropython/examples/badger2040w/examples/fonts.py +++ /dev/null @@ -1,129 +0,0 @@ -import badger2040w -import badger_os - -# Global Constants -FONT_NAMES = ( - ("sans", 0.7, 2), - ("gothic", 0.7, 2), - ("cursive", 0.7, 2), - ("serif", 0.7, 2), - ("serif_italic", 0.7, 2), - ("bitmap6", 3, 1), - ("bitmap8", 2, 1), - ("bitmap14_outline", 1, 1) -) - -WIDTH = badger2040w.WIDTH -HEIGHT = badger2040w.HEIGHT - -MENU_TEXT_SIZE = 0.5 -MENU_SPACING = 16 -MENU_WIDTH = 84 -MENU_PADDING = 5 - -TEXT_INDENT = MENU_WIDTH + 10 - -ARROW_THICKNESS = 3 -ARROW_WIDTH = 18 -ARROW_HEIGHT = 14 -ARROW_PADDING = 2 - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw a upward arrow -def draw_up(x, y, width, height, thickness, padding): - border = (thickness // 4) + padding - display.line(x + border, y + height - border, - x + (width // 2), y + border) - display.line(x + (width // 2), y + border, - x + width - border, y + height - border) - - -# Draw a downward arrow -def draw_down(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw the frame of the reader -def draw_frame(): - display.set_pen(15) - display.clear() - display.set_pen(12) - display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) - display.set_pen(0) - draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - -# Draw the fonts and menu -def draw_fonts(): - display.set_font("bitmap8") - for i in range(len(FONT_NAMES)): - name, size, thickness = FONT_NAMES[i] - display.set_pen(0) - if i == state["selected_font"]: - display.rectangle(0, i * MENU_SPACING, MENU_WIDTH, MENU_SPACING) - display.set_pen(15) - - display.text(name, MENU_PADDING, (i * MENU_SPACING) + int((MENU_SPACING - 8) / 2), WIDTH, MENU_TEXT_SIZE) - - name, size, thickness = FONT_NAMES[state["selected_font"]] - display.set_font(name) - - y = 0 if name.startswith("bitmap") else 10 - - display.set_pen(0) - for line in ("The quick", "brown fox", "jumps over", "the lazy dog.", "0123456789", "!\"£$%^&*()"): - display.text(line, TEXT_INDENT, y, WIDTH, size) - y += 22 - - display.update() - - -# ------------------------------ -# Program setup -# ------------------------------ - -# Global variables -state = {"selected_font": 0} -badger_os.state_load("fonts", state) - -# Create a new Badger and set it to update FAST -display = badger2040w.Badger2040W() -display.led(128) -display.set_update_speed(badger2040w.UPDATE_FAST) - -changed = not badger2040w.woken_by_button() - -# ------------------------------ -# Main program loop -# ------------------------------ - -while True: - if display.pressed(badger2040w.BUTTON_UP): - state["selected_font"] -= 1 - if state["selected_font"] < 0: - state["selected_font"] = len(FONT_NAMES) - 1 - changed = True - if display.pressed(badger2040w.BUTTON_DOWN): - state["selected_font"] += 1 - if state["selected_font"] >= len(FONT_NAMES): - state["selected_font"] = 0 - changed = True - - if changed: - draw_frame() - draw_fonts() - badger_os.state_save("fonts", state) - changed = False - - display.halt() diff --git a/micropython/examples/badger2040w/examples/help.py b/micropython/examples/badger2040w/examples/help.py deleted file mode 100644 index f51b0403..00000000 --- a/micropython/examples/badger2040w/examples/help.py +++ /dev/null @@ -1,41 +0,0 @@ -import badger2040w -from badger2040w import WIDTH - -TEXT_SIZE = 0.45 -LINE_HEIGHT = 20 - -display = badger2040w.Badger2040W() -display.led(128) -display.set_thickness(2) - -# Clear to white -display.set_pen(15) -display.clear() - -display.set_font("bitmap8") -display.set_pen(0) -display.rectangle(0, 0, WIDTH, 16) -display.set_pen(15) -display.text("badgerOS", 3, 4, WIDTH, 1) -display.text("help", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1) - -display.set_font("sans") -display.set_pen(0) - -TEXT_SIZE = 0.62 -y = 20 + int(LINE_HEIGHT / 2) - -display.set_font("sans") -display.text("Up/Down - Change page", 0, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -display.text("a, b or c - Launch app", 0, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -display.text("a & c - Exit app", 0, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT - -display.update() - -# Call halt in a loop, on battery this switches off power. -# On USB, the app will exit when A+C is pressed because the launcher picks that up. -while True: - display.halt() diff --git a/micropython/examples/badger2040w/examples/icon-badge.jpg b/micropython/examples/badger2040w/examples/icon-badge.jpg deleted file mode 100644 index 0b86070d49d70bde119e5820f1fe26cc408e48c5..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1793 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 bTbDm2f7+e(1-yR_Bmh0c#?07o@c&H!2*S-B diff --git a/micropython/examples/badger2040w/examples/icon-help.jpg b/micropython/examples/badger2040w/examples/icon-help.jpg deleted file mode 100644 index 80c3f6f5d64f21e091841339898293cda98a7473..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2151 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 diff --git a/micropython/examples/badger2040w/examples/icon-info.jpg b/micropython/examples/badger2040w/examples/icon-info.jpg deleted file mode 100644 index 4a43961be38aac54fd2a9f3f33659530899bfac9..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2062 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 XWZLQAXgz#a8QkoH0tJwENZ$SlG0}>b diff --git a/micropython/examples/badger2040w/examples/icon-net-info.jpg b/micropython/examples/badger2040w/examples/icon-net-info.jpg deleted file mode 100644 index f581777378dd81ed0b3fe74548a16f4c7ef65d05..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1485 zcmb7;eLT|%9LIm#{A}3R*gV9o%uJNh>~wk&V;*0gCPNgZNOP0PLx`8hS6HUGJanCh zlEqxnbxa6_Jl*8^F-~PJ$wMI}+Rfb`clYOgzTdyT-`D5!c}vD5GXUDr*1;BlKp=pR zbO6aDU=6^a(4Cb^M!FyZ1Z8AEc{p4afs{ug7338ZP>RZElp;n^K>@9b#;9O%I2=+* zO4lE zRC>l@{$21_lw<-x!XQ!*7zVHa1{?VAZjG(!Ga9%LU4?J@*{eg$oMcK=I1wUh^}x)g z+nD+ba`fivQ_-U7Wz(9ESM#;UJcrMO`JbO_4>I!`21jxm({COIrrlNONasYG&jxA; zQ|P$o^6^F`Mv$q~!=KY51}}B*k74tVt~%=|gaTthlT81jn{|W<2e`uk=&uPmN>w1PeU&I-Xk? z`^N;Hzh$%-!kJvMGyVGG{q*+oDm-J$s540dq!3?ya{djpamD#j)IO#Z`92Mj0PCa8 zxLw3gI8NpV?wZhjjNr}NYo(qd;%0ak0%9yF>d(Uh?qKT9^;XMUiTNf4yCu)m+&tEY55Vv6G z)q$*gzxgz}W4otUUEH$TtKZ_-)UB!WRjb-!ct!&BP;I6km&HcZS2)x7zUv&*m6&hz zhkSaL%w|e*_AzsYSK2*zF_u=d$C7Dctg%p_I2w0rP-IXRKH!&Kr|Kl@=p-onwppf* zg%IA%ZX@VYt&BfYTyDc?=U%&Zk_t`MUk-~bLRG=aK##+jxym8;$`UH9Dm;l4W^$m` zZ1o#4H`tzgHh@dGm<*(|Op>DB`d69Xoo6~R<9m+rPSl-@Yg=p%y>zxW{V3&P*B(@# ztqpCm9eFLALRY5gqAjcZJ~nWU3I_AI(-Uh)nB?Ty*uep&tI8uaBG-i7568)LfF2%< zt{9qS_V&8w)TU3%c2o2!MeVC7y8PFD2|2QJS5#6iVj^s>O2@&U0-!E%5jn35>aeIh5n(rkls6;XD3 zSq2|EDq1vb`jXZVY5ygSZ2s6Ga^5{~I@^UQV8Ac>X|e7^_=OdcpX)U`rsU*5Pu$aQ zcx$nyTGLvihS`}NJ;cjbk1CB8cx1fPGZuSO>|a^8WU5niGuhpPur~98mo}r==NAT|^^R_g}Ui&TFYhO8Npq&|q zE+YJj3qnj1`*y)BgE0vU=K3eMX{`1d_BeH^#`oYz<06EA{f_JD zwR7at^aK~-d_VoZDI4+NL>sk5ly!A+qj9pUZfzkvJ~zz!`d!o5$b{L_P7YoNT5&`E iJMFp17@BHYjIO^RUAy24byM1bf|O8Xcj~B;@jn4Im0#Qd diff --git a/micropython/examples/badger2040w/examples/icon-news.jpg b/micropython/examples/badger2040w/examples/icon-news.jpg deleted file mode 100644 index 0c281d340fc15f98c925509d5d68c0382d4d3841..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1987 zcmb7;dpy&R8ppre%w=;MLm}G8Wf(D2$>k?=ix}IY$j>#=+!86PT#~H%Q90#4xoso- z+|NWQ%B3>ovMF+@mJUO?bV@txTwdq=dp^(e$Mbrg*Yo+jMU$d;fTEj|s}leMfq-M; z0z^~5Apimf|7x)$#0`~(LM0@iFexcXX<3-8EF1=h%gHM#%E=?-;c!J&MT9a^MMXtc zL2ZXBa)%O91^LSa1QGv8KxLp%8KfLs4*7pe^cX-$12_N&0U-b|0t7*TL_L6p7!`p0 z!u^kAqyb4Om;_XOv{VE@zo@}b2mt@*9W2IxN-9YqlmTg^jEbrn3azu(++xR0T^!!w zkoU=|1@W88|Jwb_7A#&P5&sSOcbJF|$U;D38VCZg1Bj7h5jb_yK=F~#^JnqO`g)}P zXu5j?7na)|?v{l{XS3aySy}8(2dMtpu7>pk8BZC4LnnBEh14>q2eDuN-otx$oa9`f z_kqB_uK4I)h{k7`@3uBA_U&9h^ki#btsOffWv4t7`NzxEFVAgly^Z4^TTM|{cZmQ; zf#KH0Tb;cFO((~T+XO3%#1f~1Hm%x*rb-y|qSFgxIio7HL*sGa^{%lu@d`7!4>|>j zh5_M~w2oMkAz2=$SHF`GP}vn}T29qvBy0tE6rH(IU1&ZJ-MicIjWTw)W3Hj2v+{6c zhPlDf0L#BjGmqz?q2~yW@yY2bybp*clrNL6YMR|$_I(B=m-E-JF1HdKIIl9iJhLSf z)T`rMsS}sqrd;t4-YNe?f}7g>_xkCK(D6y-Jvk2Be+qhN=f>Sk{`7v}v-COT43okp z!)}|UoR5+jH0E0oy^5VOUK1r+dG5m+QnH6CK4-kN8nyjgo7fSRihd7wT@3L!xN37S zYQ25!&Nq$6n+g6{)r~L>2nvhp$;eVRFmc>y>gf8a$09J zkieV2W3Lw-8dugOeXGcWo0AJAccnEw`kTfDQZ2uQb#^3V!ep@q)6;HFjEhYo{F0KA zBWf=Rg;G)>IFdkW?bCeInIm%NT7^>-_v}h$uX~u6(W`KS3hP{-k8uVV1U^$D?Y?Pq zRe9TjWOpIgB)BT-=MDb(beEX4J@HDmagFHJQWeTf2paI2Ptc4xNQBGY7O=R+mB~-YwW{qn4_E zMT4Z1E9!QPagg^ytY5;pH)NdU^iRGL|WLYtN1AFVz~(5ih#qI)|kN|ddlKp%O$JnAI26zne8j9 zZ)T$9*81%dr)XAQ^aHX2Ov#IF+q$1Cs8{t)bv{eS%}a5twa7+LXrI+^2|+RhcGLI6 zGq-U5>E*eq`wpoj5kRc|F(CrP!xUG2(}V6aLUYbL9r#-PiY*Nt(L}DGKh<(b!yw?% z%zZNVut^#QA>Uy{eS_8GyBoKhga;Rj4v4i@PI z+wmr8RmX$Om358zVQr5F%3r2s8(?QSo4tITmM|eF!sGBC&YVxC$i-dc4abatZpV3! zFN-c;wLfUxfm%MfwXz$sZtAwYt;q>&GmT0tqf-3(QzFwbnv6`3wdTN<@jHb$HINHj zr6=zI%%{nY`2A5cANe^rOnbg#?~9Uj*Ib+6V#_t->-kAHUKZH&yH@UM^6w>(U)ek0 zAY&H}uiL)lL?sEHkF*Iqosn0uWy{e0)p?F?X86g6pJcAZOXHYehTCz(@0vC3rGD1F z#{4B6XV%%P%T4EId)kf63ZmgA(JqZVs=rQbt0Sd*yxVp`htPY>Y?hY3p^&r*VXj(w zlIBQgzuXTkzT|qdx;{>zrCKj3kg#w)S!UlVN{1NCIIF?-hRqvB} z`l-=n-|NE13#neY8u4JPS~p?5ky1Da*33yX8U4hSn=aqZ`RO-Vhq_OA=_v;ZI&!$D|uezpimf+o0A*)f8*#4fM5qy0aXYH0e}%82m*A(1cU(q@~bTHKd`c~ zLje}p@lF#C08lWL1q5PYgZ*0p0w32u79jZeQ2 zZfxzVV=wZbk^jm5HAVd6(0`{B02c&wTnK^y^nik~7ccDHIRp%ADk|bXSeiL+=1+da zMxyG*TP9@xR5TK8FM{-2WPR|YP)rK18&8C3uZ_>RZ99MU-w9J8xKa|f^Fn&1zxP>w zE$y`A@)+>EP7lUy{D`1?60PLv6$DE-MhGWFj>9W^nDRDcJ&A-XzKLe&&vn1 zHotSdaN%;+<0sU-^!cXkuE1MYmUv(?E}oEPoWJSLvYgiBZ4`G*g3!dPm^%z^7viZC zx4-zAKhCQ>-1Nv`I-8R>Nz(n=1h8>BLDoh!C!+Y7&aXsh*_ zQfU4#$GTjwKuscdEsI7_f_o*l05NEU@9fg(tw1_`Z`;FdXM|rhNcQ<_SJiESFFQdz z4YfkaHp-hy?L0Mme93N23F5sMRLkd{?*>$6i7OqzEC+7l(6^R}wSzG#enV9PxCPvT zoo9S^`(vZIQV!Pd03gQZQe!t4DOkLk2jjRgKD?b%vW9|4Fo~30sXDwlAp%V)ugEZL z4=ldutMG^;I618>C^cqe_%GWr$IR?XDt}!`wv41b{oA~20}5fD2|;){iMj|eCG~A2 zW5c7Z!6`#PZ=s*7`ThHqOG5Vzwv_^MC6;jV9 zz(daGP+Iu>y3Td}ZujD1F(bW#h81()y`N^`-xxO6+c!07n#lhteKr+`zQSwFwb2!k zkYXS)r!+OKZFJeZx?XiYtzo68OiSk;Mqb^lUTIJju2z%!RL=WKlH{ZKzW7hNQNon) zCWk*?!tK)QR<9_)vRw;AEL>F=M7uh^;G(KIhOBH))!KnfG$SQBa^m}bXAuZPRFD(h zjq7q~%G_*Z?-4VNvz@lm_FGJXb7_DH#piE?;swGO9F zVAWuP`9xfjCkW$gzb)xJFkprYrVhtH3XLNDCRg0(j~#kzjgtsTK)q7pL+58*qvJFMdG^QBFU1zZH8n*_of#Xb_Fz>TaRz^{| zmNBpQTEC|_kvOb2kgJLem~Ave_k-0m-!x|X*UP7arCo*;^a*)3!AnSF>{zR!`~9C0 ziVMVjMIVP?amM>ZGyCj#?30e(a>d0iA@xq9Qc-yYM zmZ^;tUUp=v15>!)grNceL>sIY!|sHYNGIOz z@2c}ekGWBKTMq%H5ryPb13`Z=w{bXMDoz>2zev%+*4^`He1|4|Oc}1rNeP=5v{a0L z&C}%V)6t>PH$(sFMF@ynVqM6u+1FQL=U5sY!7p7TTvwCw?QAh~^Oa#%+Y}5k{pOF^C%l-^J=J`6t#q33yFb%@jLrE~Rqo<)Ud~sg# zT?yFWD2kDJNVEwy3YXD}*)N(W8Pn+_GACzjPH(ehYGJT`2K%{#_e)9BcJn9$Ys=18 z0}9?Q3vwJW;mkrXs84)4H@Npr$C#`jA)#`0CE)F8zUoiZ`YdwRF6_y9GO@<=EC8+| z#FRR4=SGdif)MSYT%5*N3)f!RI!y^=R(?F(JUJP9JIq4Csz(9hDCmd2BuV!qj6k-! zYYkU@Wq)j)AkgiD-BvE=@u<#~H`nCQv@c$+ry;c#RvL+*-3Ak;M2?OZ1RZCVXPsKQ z1)>#}pBfJGM=LSs%u`_3Bf4`gc;2Btps#x6HFdKv8DgSuyi}3ql*L_Ro%wul1T1sA1_iv28(kmJeOyP}Z}6dgxXr461lTVP?UZl`X;#qW zbuX8uy?)_3`C(dGUF~DL^o1B>c?eoYf6KZT+cuW4h0J$!#Cyn4b39-qdJ*j@&0INa zk&ATWWhhyJ>}&$%nhbviYE1Vf6?~Gg**7%&X;g{XrmcGMER5YqjZWm!K-obgMVsB@E}Z}!&=0BPkB42=dOL!JwTJJWOKhjP z6cs-Ygcl@tKLLVi-Bj7ZuyaCD9tZCA{5 z$}Os}xjUs2h--ahR^;-nSlS`jzz#;2?ceCNDg*(gV-w4s>}RWMkb$L1>zbswkUy+D v>+QZtwmqNr*$npL$r>Le-g%Trv&Rns0BF;5)##8><#XV31Smf>I2!*K9ixKL diff --git a/micropython/examples/badger2040w/examples/icon-weather.jpg b/micropython/examples/badger2040w/examples/icon-weather.jpg deleted file mode 100644 index 35d3bd0032c2eb93c546df0261b2804873149b99..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1591 zcmb79Ydq5n82Wt2EO>wG%rd^^wketO>LeV^x*zLib@XeURCBLIRR;3F$Q z`VO!Mpb*H9mO)O|Fa;P)P7a2E!{rrF2ows5Kq8ftv1lb_j4~35RzqV{ad06+mK2>b&I ziZFRNLN+6y0f@{N0?Nt4|1AI^viS0F1q>EYRm7=j>*96v%*=P#$;9{{FaH}58I8mI zmj$Gw07~Wv!9X#9El_bP)FYx}f%$@bhPy(rD9T{6<6Q5SFLq$p>z(5uEfMAO#aFr~ zRDaV(E}s?Kan58u{$Q*=H8goXtgv;sBcwdXo=R8o#uPMo{y8}3y|EFzxH)!{wSIjn zbJ*Fle=)|8rTZkBaNgq7FPxPdNnJJ^jSz`b`@%JyS0%^B%q^*c{qu&71xX_wg2v+t zJ0i>{bEg?vUN-!1+T|_2Ie5))0pgcVo)1Fy`ymYouL7zAYlSKUq3-!tnOv*5q9p2M zuHOP8EV$;p|4)ucs(Y`F7?C%nvNWqM`8;{pjC4m(7{rgr?xjhZnO!(b#D-gRvM9|H z>$v7C?@vpeOwqm71LyU9RXo}!;s&YzIbyzQ)UMOg@$0y4_RjBG_boy`H!V0ZB+A}F zGtQQ?M^qc)=H904UH289k_b=rJ!iX{Ol-%!T3zS#<@?mfft+{R*Kz`)sLRcD;mx?0 zik*+1Ribih!>Br0fw~QB|Gig6kB?Z+&@^5Myj@Q=^Pl7qo3382t{YV4gyd>aP}SvV zUXGnyqGp(6*{kNX6sXP*Eq?!Lkv2{^D0CLkg~e{VY07;UwBBIJTIY&eT)M@sse`Lf zUgXYzy3x7bVL$QgvoF+&(Le^9U}Vx18@XXj2WwU6;cDVV3*NsKd+@-88x>}C`W!|= zeSIN)&xws{6~da5;op7Yk{(C_yo-+)cWXv~M^V2Ae469FDAB&))rZdPEP4*^oY%}M zO)48(YA=f&JsXg=CZyQYNlPoYruZ!3k*nz_jeSJ66ks~*#|I@x1@Nd7VaeL>NImiI zs}hnjkY}xheAgHb_a6V9;m^1cW8KE~?pEg4^fLdw;F>>iwiTbN3p3%B`mA4&qzUB< z=}oM-H-pV5A7%%!ka_wUB_G^iwr$0`r9hOXK#6$ZJ%q5o59`H?))%TKBWoPOk716U zQAalxJGfsNlmh;8=r<&lm`52SXR?_E!sE$)aomqqC7EiqKBo=9Ert{J>xI}Qk}^f_ zp4rjRAoaWXqVVpys6OwiLMK6AL0pN_T4DPN zYrP-Krx+0r118a)JEul4RhIuL3W&D#P=H|hg))u`ztI&?kn=S$KD!{yc zd;gtj?cpp_XPx>(o_2Xtb>++ObUi!QW1?xEQ*~M6kVBARCktI@<=^9lHO@$Fk0xw4Xltw5%XVr(mF^(SXFN~DHb$ud)zJDyttd^x=99FUr9ihOEW(&pSh-sC%GG9DK4 sWSkOJ!NJ8!OyPHLr*Ado_MD|shb0D|DK5V4`Z?U);DjbPkt`Mb1%MZyBme*a diff --git a/micropython/examples/badger2040w/examples/image.py b/micropython/examples/badger2040w/examples/image.py deleted file mode 100644 index f44478d4..00000000 --- a/micropython/examples/badger2040w/examples/image.py +++ /dev/null @@ -1,119 +0,0 @@ -import os -import sys -import time -import badger2040w -from badger2040w import HEIGHT, WIDTH -import badger_os -import jpegdec - - -REAMDE = """ -Images must be 296x128 pixel JPEGs - -Create a new "images" directory via Thonny, and upload your .jpg files there. -""" - -OVERLAY_BORDER = 40 -OVERLAY_SPACING = 20 -OVERLAY_TEXT_SIZE = 0.5 - -TOTAL_IMAGES = 0 - - -# Turn the act LED on as soon as possible -display = badger2040w.Badger2040W() -display.led(128) - -jpeg = jpegdec.JPEG(display.display) - -# Try to preload BadgerPunk image -try: - os.mkdir("/images") - with open("/images/readme.txt", "w") as f: - f.write(REAMDE) - f.flush() -except (OSError, ImportError): - pass - -# Load images -try: - IMAGES = [f for f in os.listdir("/images") if f.endswith(".jpg")] - TOTAL_IMAGES = len(IMAGES) -except OSError: - pass - - -state = { - "current_image": 0, - "show_info": True -} - - -def show_image(n): - file = IMAGES[n] - name = file.split(".")[0] - jpeg.open_file("/images/{}".format(file)) - jpeg.decode() - - if state["show_info"]: - name_length = display.measure_text(name, 0.5) - display.set_pen(0) - display.rectangle(0, HEIGHT - 21, name_length + 11, 21) - display.set_pen(15) - display.rectangle(0, HEIGHT - 20, name_length + 10, 20) - display.set_pen(0) - display.text(name, 5, HEIGHT - 10, WIDTH, 0.5) - - for i in range(TOTAL_IMAGES): - x = 286 - y = int((128 / 2) - (TOTAL_IMAGES * 10 / 2) + (i * 10)) - display.set_pen(0) - display.rectangle(x, y, 8, 8) - if state["current_image"] != i: - display.set_pen(15) - display.rectangle(x + 1, y + 1, 6, 6) - - display.update() - - -if TOTAL_IMAGES == 0: - display.set_pen(15) - display.clear() - badger_os.warning(display, "To run this demo, create an /images directory on your device and upload some 1bit 296x128 pixel images.") - time.sleep(4.0) - sys.exit() - - -badger_os.state_load("image", state) - -changed = not badger2040w.woken_by_button() - - -while True: - if display.pressed(badger2040w.BUTTON_UP): - if state["current_image"] > 0: - state["current_image"] -= 1 - changed = True - if display.pressed(badger2040w.BUTTON_DOWN): - if state["current_image"] < TOTAL_IMAGES - 1: - state["current_image"] += 1 - changed = True - if display.pressed(badger2040w.BUTTON_A): - state["show_info"] = not state["show_info"] - changed = True - if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C): - display.set_pen(15) - display.clear() - badger_os.warning(display, "To add images connect Badger2040 to a PC, load up Thonny, and see readme.txt in images/") - display.update() - print(state["current_image"]) - time.sleep(4) - changed = True - - if changed: - badger_os.state_save("image", state) - show_image(state["current_image"]) - changed = False - - # Halt the Badger to save power, it will wake up if any of the front buttons are pressed - display.halt() diff --git a/micropython/examples/badger2040w/examples/info.py b/micropython/examples/badger2040w/examples/info.py deleted file mode 100644 index a878edda..00000000 --- a/micropython/examples/badger2040w/examples/info.py +++ /dev/null @@ -1,44 +0,0 @@ -import badger2040w -from badger2040w import WIDTH - -TEXT_SIZE = 1 -LINE_HEIGHT = 15 - -display = badger2040w.Badger2040W() -display.led(128) - -# Clear to white -display.set_pen(15) -display.clear() - -display.set_font("bitmap8") -display.set_pen(0) -display.rectangle(0, 0, WIDTH, 16) -display.set_pen(15) -display.text("badgerOS", 3, 4, WIDTH, 1) -display.text("info", WIDTH - display.measure_text("help", 0.4) - 4, 4, WIDTH, 1) - -display.set_pen(0) - -y = 16 + int(LINE_HEIGHT / 2) - -display.text("Made by Pimoroni, powered by MicroPython", 5, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -display.text("Dual-core RP2040, 133MHz, 264KB RAM", 5, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -display.text("2MB Flash (1MB OS, 1MB Storage)", 5, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -display.text("296x128 pixel Black/White e-Ink", 5, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -y += LINE_HEIGHT - -display.text("For more info:", 5, y, WIDTH, TEXT_SIZE) -y += LINE_HEIGHT -display.text("https://pimoroni.com/badger2040w", 5, y, WIDTH, TEXT_SIZE) - -display.update() - -# Call halt in a loop, on battery this switches off power. -# On USB, the app will exit when A+C is pressed because the launcher picks that up. -while True: - display.halt() diff --git a/micropython/examples/badger2040w/examples/list.py b/micropython/examples/badger2040w/examples/list.py deleted file mode 100644 index 01137a7c..00000000 --- a/micropython/examples/badger2040w/examples/list.py +++ /dev/null @@ -1,312 +0,0 @@ -import binascii - -import badger2040w -import badger_os - -# **** Put your list title here ***** -list_title = "Checklist" -list_file = "checklist.txt" - - -# Global Constantsu -WIDTH = badger2040w.WIDTH -HEIGHT = badger2040w.HEIGHT - -ARROW_THICKNESS = 3 -ARROW_WIDTH = 18 -ARROW_HEIGHT = 14 -ARROW_PADDING = 2 - -MAX_ITEM_CHARS = 26 -TITLE_TEXT_SIZE = 0.7 -ITEM_TEXT_SIZE = 0.6 -ITEM_SPACING = 20 - -LIST_START = 40 -LIST_PADDING = 2 -LIST_WIDTH = WIDTH - LIST_PADDING - LIST_PADDING - ARROW_WIDTH -LIST_HEIGHT = HEIGHT - LIST_START - LIST_PADDING - ARROW_HEIGHT - - -# Default list items - change the list items by editing checklist.txt -list_items = ["Badger", "Badger", "Badger", "Badger", "Badger", "Mushroom", "Mushroom", "Snake"] -save_checklist = False - -try: - with open("checklist.txt", "r") as f: - raw_list_items = f.read() - - if raw_list_items.find(" X\n") != -1: - # Have old style checklist, preserve state and note we should resave the list to remove the Xs - list_items = [] - state = { - "current_item": 0, - "checked": [] - } - for item in raw_list_items.strip().split("\n"): - if item.endswith(" X"): - state["checked"].append(True) - item = item[:-2] - else: - state["checked"].append(False) - list_items.append(item) - state["items_hash"] = binascii.crc32("\n".join(list_items)) - - badger_os.state_save("list", state) - save_checklist = True - else: - list_items = [item.strip() for item in raw_list_items.strip().split("\n")] - -except OSError: - save_checklist = True - -if save_checklist: - with open("checklist.txt", "w") as f: - for item in list_items: - f.write(item + "\n") - - -# ------------------------------ -# Drawing functions -# ------------------------------ - -# Draw the list of items -def draw_list(items, item_states, start_item, highlighted_item, x, y, width, height, item_height, columns): - item_x = 0 - item_y = 0 - current_col = 0 - for i in range(start_item, len(items)): - if i == highlighted_item: - display.set_pen(12) - display.rectangle(item_x, item_y + y - (item_height // 2), width // columns, item_height) - display.set_pen(0) - display.text(items[i], item_x + x + item_height, item_y + y, WIDTH, ITEM_TEXT_SIZE) - draw_checkbox(item_x, item_y + y - (item_height // 2), item_height, 15, 0, 2, item_states[i], 2) - item_y += item_height - if item_y >= height - (item_height // 2): - item_x += width // columns - item_y = 0 - current_col += 1 - if current_col >= columns: - return - - -# Draw a upward arrow -def draw_up(x, y, width, height, thickness, padding): - border = (thickness // 4) + padding - display.line(x + border, y + height - border, - x + (width // 2), y + border) - display.line(x + (width // 2), y + border, - x + width - border, y + height - border) - - -# Draw a downward arrow -def draw_down(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw a left arrow -def draw_left(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + width - border, y + border, - x + border, y + (height // 2)) - display.line(x + border, y + (height // 2), - x + width - border, y + height - border) - - -# Draw a right arrow -def draw_right(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, - x + width - border, y + (height // 2)) - display.line(x + width - border, y + (height // 2), - x + border, y + height - border) - - -# Draw a tick -def draw_tick(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + ((height * 2) // 3), - x + (width // 2), y + height - border) - display.line(x + (width // 2), y + height - border, - x + width - border, y + border) - - -# Draw a cross -def draw_cross(x, y, width, height, thickness, padding): - border = (thickness // 2) + padding - display.line(x + border, y + border, x + width - border, y + height - border) - display.line(x + width - border, y + border, x + border, y + height - border) - - -# Draw a checkbox with or without a tick -def draw_checkbox(x, y, size, background, foreground, thickness, tick, padding): - border = (thickness // 2) + padding - display.set_pen(background) - display.rectangle(x + border, y + border, size - (border * 2), size - (border * 2)) - display.set_pen(foreground) - display.line(x + border, y + border, x + size - border, y + border) - display.line(x + border, y + border, x + border, y + size - border) - display.line(x + size - border, y + border, x + size - border, y + size - border) - display.line(x + border, y + size - border, x + size - border, y + size - border) - if tick: - draw_tick(x, y, size, size, thickness, 2 + border) - - -# ------------------------------ -# Program setup -# ------------------------------ - -changed = not badger2040w.woken_by_button() -state = { - "current_item": 0, -} -badger_os.state_load("list", state) -items_hash = binascii.crc32("\n".join(list_items)) -if "items_hash" not in state or state["items_hash"] != items_hash: - # Item list changed, or not yet written reset the list - state["current_item"] = 0 - state["items_hash"] = items_hash - state["checked"] = [False] * len(list_items) - changed = True - -# Global variables -items_per_page = 0 - -# Create a new Badger and set it to update FAST -display = badger2040w.Badger2040W() -display.led(128) -display.set_font("sans") -display.set_thickness(2) -if changed: - display.set_update_speed(badger2040w.UPDATE_FAST) -else: - display.set_update_speed(badger2040w.UPDATE_TURBO) - -# Find out what the longest item is -longest_item = 0 -for i in range(len(list_items)): - while True: - item = list_items[i] - item_length = display.measure_text(item, ITEM_TEXT_SIZE) - if item_length > 0 and item_length > LIST_WIDTH - ITEM_SPACING: - list_items[i] = item[:-1] - else: - break - longest_item = max(longest_item, display.measure_text(list_items[i], ITEM_TEXT_SIZE)) - - -# And use that to calculate the number of columns we can fit onscreen and how many items that would give -list_columns = 1 -while longest_item + ITEM_SPACING < (LIST_WIDTH // (list_columns + 1)): - list_columns += 1 - -items_per_page = ((LIST_HEIGHT // ITEM_SPACING) + 1) * list_columns - - -# ------------------------------ -# Main program loop -# ------------------------------ - -while True: - if len(list_items) > 0: - if display.pressed(badger2040w.BUTTON_A): - if state["current_item"] > 0: - page = state["current_item"] // items_per_page - state["current_item"] = max(state["current_item"] - (items_per_page) // list_columns, 0) - if page != state["current_item"] // items_per_page: - display.update_speed(badger2040w.UPDATE_FAST) - changed = True - if display.pressed(badger2040w.BUTTON_B): - state["checked"][state["current_item"]] = not state["checked"][state["current_item"]] - changed = True - if display.pressed(badger2040w.BUTTON_C): - if state["current_item"] < len(list_items) - 1: - page = state["current_item"] // items_per_page - state["current_item"] = min(state["current_item"] + (items_per_page) // list_columns, len(list_items) - 1) - if page != state["current_item"] // items_per_page: - display.update_speed(badger2040w.UPDATE_FAST) - changed = True - if display.pressed(badger2040w.BUTTON_UP): - if state["current_item"] > 0: - state["current_item"] -= 1 - changed = True - if display.pressed(badger2040w.BUTTON_DOWN): - if state["current_item"] < len(list_items) - 1: - state["current_item"] += 1 - changed = True - - if changed: - badger_os.state_save("list", state) - - display.set_pen(15) - display.clear() - - display.set_pen(12) - display.rectangle(WIDTH - ARROW_WIDTH, 0, ARROW_WIDTH, HEIGHT) - display.rectangle(0, HEIGHT - ARROW_HEIGHT, WIDTH, ARROW_HEIGHT) - - y = LIST_PADDING + 12 - display.set_pen(0) - display.text(list_title, LIST_PADDING, y, WIDTH, TITLE_TEXT_SIZE) - - y += 12 - display.set_pen(0) - display.line(LIST_PADDING, y, WIDTH - LIST_PADDING - ARROW_WIDTH, y) - - if len(list_items) > 0: - page_item = 0 - if items_per_page > 0: - page_item = (state["current_item"] // items_per_page) * items_per_page - - # Draw the list - display.set_pen(0) - draw_list(list_items, state["checked"], page_item, state["current_item"], LIST_PADDING, LIST_START, - LIST_WIDTH, LIST_HEIGHT, ITEM_SPACING, list_columns) - - # Draw the interaction button icons - display.set_pen(0) - - # Previous item - if state["current_item"] > 0: - draw_up(WIDTH - ARROW_WIDTH, (HEIGHT // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - # Next item - if state["current_item"] < (len(list_items) - 1): - draw_down(WIDTH - ARROW_WIDTH, ((HEIGHT * 3) // 4) - (ARROW_HEIGHT // 2), - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - # Previous column - if state["current_item"] > 0: - draw_left((WIDTH // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - # Next column - if state["current_item"] < (len(list_items) - 1): - draw_right(((WIDTH * 6) // 7) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_WIDTH, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - - if state["checked"][state["current_item"]]: - # Tick off item - draw_cross((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - else: - # Untick item - draw_tick((WIDTH // 2) - (ARROW_WIDTH // 2), HEIGHT - ARROW_HEIGHT, - ARROW_HEIGHT, ARROW_HEIGHT, ARROW_THICKNESS, ARROW_PADDING) - else: - # Say that the list is empty - empty_text = "Nothing Here" - text_length = display.measure_text(empty_text, ITEM_TEXT_SIZE) - display.text(empty_text, ((LIST_PADDING + LIST_WIDTH) - text_length) // 2, (LIST_HEIGHT // 2) + LIST_START - (ITEM_SPACING // 4), WIDTH, ITEM_TEXT_SIZE) - - display.update() - display.set_update_speed(badger2040w.UPDATE_TURBO) - changed = False - - display.halt() diff --git a/micropython/examples/badger2040w/examples/net_info.py b/micropython/examples/badger2040w/examples/net_info.py deleted file mode 100644 index 083db599..00000000 --- a/micropython/examples/badger2040w/examples/net_info.py +++ /dev/null @@ -1,48 +0,0 @@ -import badger2040w as badger2040 -from badger2040w import WIDTH -import network - -TEXT_SIZE = 1 -LINE_HEIGHT = 16 - -# Display Setup -display = badger2040.Badger2040W() -display.led(128) - -# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :). -display.connect() -net = network.WLAN(network.STA_IF).ifconfig() - -# Page Header -display.set_pen(15) -display.clear() -display.set_pen(0) - -display.set_pen(0) -display.rectangle(0, 0, WIDTH, 20) -display.set_pen(15) -display.text("badgerOS", 3, 4) -display.text("Network Details", WIDTH - display.measure_text("Network Details") - 4, 4) -display.set_pen(0) - -y = 35 + int(LINE_HEIGHT / 2) - -if net: - display.text("> LOCAL IP: {}".format(net[0]), 0, y, WIDTH) - y += LINE_HEIGHT - display.text("> Subnet: {}".format(net[1]), 0, y, WIDTH) - y += LINE_HEIGHT - display.text("> Gateway: {}".format(net[2]), 0, y, WIDTH) - y += LINE_HEIGHT - display.text("> DNS: {}".format(net[3]), 0, y, WIDTH) -else: - display.text("> No network connection!", 0, y, WIDTH) - y += LINE_HEIGHT - display.text("> Check details in WIFI_CONFIG.py", 0, y, WIDTH) - -display.update() - -# Call halt in a loop, on battery this switches off power. -# On USB, the app will exit when A+C is pressed because the launcher picks that up. -while True: - display.halt() diff --git a/micropython/examples/badger2040w/examples/news.py b/micropython/examples/badger2040w/examples/news.py deleted file mode 100644 index 4f280c08..00000000 --- a/micropython/examples/badger2040w/examples/news.py +++ /dev/null @@ -1,215 +0,0 @@ -import badger2040w as badger2040 -from badger2040w import WIDTH -import machine -from urllib import urequest -import gc -import qrcode -import badger_os - -# URLS to use (Entertainment, Science and Technology) -URL = ["http://feeds.bbci.co.uk/news/entertainment_and_arts/rss.xml", - "http://feeds.bbci.co.uk/news/science_and_environment/rss.xml", - "http://feeds.bbci.co.uk/news/technology/rss.xml"] - -code = qrcode.QRCode() - -state = { - "current_page": 0, - "feed": 2 -} - -badger_os.state_load("news", state) - -# Display Setup -display = badger2040.Badger2040W() -display.led(128) -display.set_update_speed(2) - -# Setup buttons -button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_b = machine.Pin(badger2040.BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_down = machine.Pin(badger2040.BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN) -button_up = machine.Pin(badger2040.BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN) - - -def read_until(stream, char): - result = b"" - while True: - c = stream.read(1) - if c == char: - return result - result += c - - -def discard_until(stream, c): - while stream.read(1) != c: - pass - - -def parse_xml_stream(s, accept_tags, group_by, max_items=3): - tag = [] - text = b"" - count = 0 - current = {} - while True: - char = s.read(1) - if len(char) == 0: - break - - if char == b"<": - next_char = s.read(1) - - # Discard stuff like ") - continue - - # Detect ") # Discard ]> - gc.collect() - - elif next_char == b"/": - current_tag = read_until(s, b">") - top_tag = tag[-1] - - # Populate our result dict - if top_tag in accept_tags: - current[top_tag.decode("utf-8")] = text.decode("utf-8") - - # If we've found a group of items, yield the dict - elif top_tag == group_by: - yield current - current = {} - count += 1 - if count == max_items: - return - tag.pop() - text = b"" - gc.collect() - continue - - else: - current_tag = read_until(s, b">") - tag += [next_char + current_tag.split(b" ")[0]] - text = b"" - gc.collect() - - else: - text += char - - -def measure_qr_code(size, code): - w, h = code.get_size() - module_size = int(size / w) - return module_size * w, module_size - - -def draw_qr_code(ox, oy, size, code): - size, module_size = measure_qr_code(size, code) - display.set_pen(15) - display.rectangle(ox, oy, size, size) - display.set_pen(0) - for x in range(size): - for y in range(size): - if code.get_module(x, y): - display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size) - - -# A function to get the data from an RSS Feed, this in case BBC News. -def get_rss(url): - try: - stream = urequest.urlopen(url) - output = list(parse_xml_stream(stream, [b"title", b"description", b"guid", b"pubDate"], b"item")) - return output - - except OSError as e: - print(e) - return False - - -# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :). -display.connect() - -print(state["feed"]) -feed = get_rss(URL[state["feed"]]) - - -def draw_page(): - - # Clear the display - display.set_pen(15) - display.clear() - display.set_pen(0) - - # Draw the page header - display.set_font("bitmap6") - display.set_pen(0) - display.rectangle(0, 0, WIDTH, 20) - display.set_pen(15) - display.text("News", 3, 4) - display.text("Page: " + str(state["current_page"] + 1), WIDTH - display.measure_text("Page: ") - 4, 4) - display.set_pen(0) - - display.set_font("bitmap8") - - # Draw articles from the feed if they're available. - if feed: - page = state["current_page"] - display.set_pen(0) - display.text(feed[page]["title"], 2, 30, WIDTH - 130, 2) - code.set_text(feed[page]["guid"]) - draw_qr_code(WIDTH - 100, 25, 100, code) - - else: - display.set_pen(0) - display.rectangle(0, 60, WIDTH, 25) - display.set_pen(15) - display.text("Unable to display news! Check your network settings in WIFI_CONFIG.py", 5, 65, WIDTH, 1) - - display.update() - - -draw_page() - -while 1: - - changed = False - - if button_down.value(): - if state["current_page"] < 2: - state["current_page"] += 1 - changed = True - - if button_up.value(): - if state["current_page"] > 0: - state["current_page"] -= 1 - changed = True - - if button_a.value(): - state["feed"] = 0 - state["current_page"] = 0 - feed = get_rss(URL[state["feed"]]) - badger_os.state_save("news", state) - changed = True - - if button_b.value(): - state["feed"] = 1 - state["current_page"] = 0 - feed = get_rss(URL[state["feed"]]) - badger_os.state_save("news", state) - changed = True - - if button_c.value(): - state["feed"] = 2 - state["current_page"] = 0 - feed = get_rss(URL[state["feed"]]) - badger_os.state_save("news", state) - changed = True - - if changed: - draw_page() diff --git a/micropython/examples/badger2040w/examples/qrgen.py b/micropython/examples/badger2040w/examples/qrgen.py deleted file mode 100644 index d4617989..00000000 --- a/micropython/examples/badger2040w/examples/qrgen.py +++ /dev/null @@ -1,139 +0,0 @@ -import badger2040w -import qrcode -import time -import os -import badger_os - -# Check that the qrcodes directory exists, if not, make it -try: - os.mkdir("/qrcodes") -except OSError: - pass - -# Check that there is a qrcode.txt, if not preload -try: - text = open("/qrcodes/qrcode.txt", "r") -except OSError: - text = open("/qrcodes/qrcode.txt", "w") - text.write("""https://pimoroni.com/badger2040w -Badger 2040 W -* 296x128 1-bit e-ink -* 2.4GHz wireless -* five user buttons -* user LED -* 2MB QSPI flash - -Scan this code to learn -more about Badger 2040 W. -""") - text.flush() - text.seek(0) - -# Load all available QR Code Files -try: - CODES = [f for f in os.listdir("/qrcodes") if f.endswith(".txt")] - TOTAL_CODES = len(CODES) -except OSError: - pass - - -print(f'There are {TOTAL_CODES} QR Codes available:') -for codename in CODES: - print(f'File: {codename}') - -display = badger2040w.Badger2040W() - -code = qrcode.QRCode() - -state = { - "current_qr": 0 -} - - -def measure_qr_code(size, code): - w, h = code.get_size() - module_size = int(size / w) - return module_size * w, module_size - - -def draw_qr_code(ox, oy, size, code): - size, module_size = measure_qr_code(size, code) - display.set_pen(15) - display.rectangle(ox, oy, size, size) - display.set_pen(0) - for x in range(size): - for y in range(size): - if code.get_module(x, y): - display.rectangle(ox + x * module_size, oy + y * module_size, module_size, module_size) - - -def draw_qr_file(n): - display.led(128) - file = CODES[n] - codetext = open("/qrcodes/{}".format(file), "r") - - lines = codetext.read().strip().split("\n") - code_text = lines.pop(0) - title_text = lines.pop(0) - detail_text = lines - - # Clear the Display - display.set_pen(15) # Change this to 0 if a white background is used - display.clear() - display.set_pen(0) - - code.set_text(code_text) - size, _ = measure_qr_code(128, code) - left = top = int((badger2040w.HEIGHT / 2) - (size / 2)) - draw_qr_code(left, top, 128, code) - - left = 128 + 5 - - display.text(title_text, left, 20, badger2040w.WIDTH, 2) - - top = 40 - for line in detail_text: - display.text(line, left, top, badger2040w.WIDTH, 1) - top += 10 - - if TOTAL_CODES > 1: - for i in range(TOTAL_CODES): - x = 286 - y = int((128 / 2) - (TOTAL_CODES * 10 / 2) + (i * 10)) - display.set_pen(0) - display.rectangle(x, y, 8, 8) - if state["current_qr"] != i: - display.set_pen(15) - display.rectangle(x + 1, y + 1, 6, 6) - display.update() - - -badger_os.state_load("qrcodes", state) -changed = not badger2040w.woken_by_button() - -while True: - if TOTAL_CODES > 1: - if display.pressed(badger2040w.BUTTON_UP): - if state["current_qr"] > 0: - state["current_qr"] -= 1 - changed = True - - if display.pressed(badger2040w.BUTTON_DOWN): - if state["current_qr"] < TOTAL_CODES - 1: - state["current_qr"] += 1 - changed = True - - if display.pressed(badger2040w.BUTTON_B) or display.pressed(badger2040w.BUTTON_C): - display.set_pen(15) - display.clear() - badger_os.warning(display, "To add QR codes, connect Badger 2040 W to a PC, load up Thonny, and add files to /qrcodes directory.") - time.sleep(4) - changed = True - - if changed: - draw_qr_file(state["current_qr"]) - badger_os.state_save("qrcodes", state) - changed = False - - # Halt the Badger to save power, it will wake up if any of the front buttons are pressed - display.halt() diff --git a/micropython/examples/badger2040w/examples/weather.py b/micropython/examples/badger2040w/examples/weather.py deleted file mode 100644 index aa35bede..00000000 --- a/micropython/examples/badger2040w/examples/weather.py +++ /dev/null @@ -1,106 +0,0 @@ -# This example grabs current weather details from Open Meteo and displays them on Badger 2040 W. -# Find out more about the Open Meteo API at https://open-meteo.com - -import badger2040w as badger2040 -from badger2040w import WIDTH -import urequests -import jpegdec - -# Set your latitude/longitude here (find yours by right clicking in Google Maps!) -LAT = 53.38609085276884 -LNG = -1.4239983439328177 -TIMEZONE = "auto" # determines time zone from lat/long - -URL = "http://api.open-meteo.com/v1/forecast?latitude=" + str(LAT) + "&longitude=" + str(LNG) + "¤t_weather=true&timezone=" + TIMEZONE - -# Display Setup -display = badger2040.Badger2040W() -display.led(128) -display.set_update_speed(2) - -jpeg = jpegdec.JPEG(display.display) - -# Connects to the wireless network. Ensure you have entered your details in WIFI_CONFIG.py :). -display.connect() - - -def get_data(): - global weathercode, temperature, windspeed, winddirection, date, time - print(f"Requesting URL: {URL}") - r = urequests.get(URL) - # open the json data - j = r.json() - print("Data obtained!") - print(j) - - # parse relevant data from JSON - current = j["current_weather"] - temperature = current["temperature"] - windspeed = current["windspeed"] - winddirection = calculate_bearing(current["winddirection"]) - weathercode = current["weathercode"] - date, time = current["time"].split("T") - - r.close() - - -def calculate_bearing(d): - # calculates a compass direction from the wind direction in degrees - dirs = ['N', 'NNE', 'NE', 'ENE', 'E', 'ESE', 'SE', 'SSE', 'S', 'SSW', 'SW', 'WSW', 'W', 'WNW', 'NW', 'NNW'] - ix = round(d / (360. / len(dirs))) - return dirs[ix % len(dirs)] - - -def draw_page(): - # Clear the display - display.set_pen(15) - display.clear() - display.set_pen(0) - - # Draw the page header - display.set_font("bitmap6") - display.set_pen(0) - display.rectangle(0, 0, WIDTH, 20) - display.set_pen(15) - display.text("Weather", 3, 4) - display.set_pen(0) - - display.set_font("bitmap8") - - if temperature is not None: - # Choose an appropriate icon based on the weather code - # Weather codes from https://open-meteo.com/en/docs - # Weather icons from https://fontawesome.com/ - if weathercode in [71, 73, 75, 77, 85, 86]: # codes for snow - jpeg.open_file("/icons/icon-snow.jpg") - elif weathercode in [51, 53, 55, 56, 57, 61, 63, 65, 66, 67, 80, 81, 82]: # codes for rain - jpeg.open_file("/icons/icon-rain.jpg") - elif weathercode in [1, 2, 3, 45, 48]: # codes for cloud - jpeg.open_file("/icons/icon-cloud.jpg") - elif weathercode in [0]: # codes for sun - jpeg.open_file("/icons/icon-sun.jpg") - elif weathercode in [95, 96, 99]: # codes for storm - jpeg.open_file("/icons/icon-storm.jpg") - jpeg.decode(13, 40, jpegdec.JPEG_SCALE_FULL) - display.set_pen(0) - display.text(f"Temperature: {temperature}°C", int(WIDTH / 3), 28, WIDTH - 105, 2) - display.text(f"Wind Speed: {windspeed}kmph", int(WIDTH / 3), 48, WIDTH - 105, 2) - display.text(f"Wind Direction: {winddirection}", int(WIDTH / 3), 68, WIDTH - 105, 2) - display.text(f"Last update: {date}, {time}", int(WIDTH / 3), 88, WIDTH - 105, 2) - - else: - display.set_pen(0) - display.rectangle(0, 60, WIDTH, 25) - display.set_pen(15) - display.text("Unable to display weather! Check your network settings in WIFI_CONFIG.py", 5, 65, WIDTH, 1) - - display.update() - - -get_data() -draw_page() - -# Call halt in a loop, on battery this switches off power. -# On USB, the app will exit when A+C is pressed because the launcher picks that up. -while True: - display.halt() diff --git a/micropython/examples/badger2040w/icons/icon-cloud.jpg b/micropython/examples/badger2040w/icons/icon-cloud.jpg deleted file mode 100644 index b1b1e706f20d5c30ead97beab47c45e66c1012c4..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2405 zcmbVL2~<;O7QXK#k1VW#u*eaJfM^MfD5z*rHVXn;AOzV|3IPNLB0FdWg1EFgpuz-^ z)Z=k|DAj9_ve21=90bS z6VPyXadQC-!ypiSfRy0Z+?<_*y?CB3ZreUW0Ra45j373VY6TE0OiJLnI&u610y(tj zfWZ<_0~~Zi1c`CmeO&nPUYmZ1vXR}hRNVF6wErGZ4GT{c0AL&xb`ZoRBq96>!s}9# z;uN?LVYVPLBn;sz2wNne0uk<2_(R{~Q3c+!fN=zYoxtZgBW-MiIeUJELw|(@kqNOV z#|Gt?hQ$ie{kZ>I9Hzhr6gV~}8P&F63WX}+LSG+rnxc0pxPlvO2QT12C?rD^#6S{Q zqEm=GiNHf~r}yyn7x-R?6^d9Quoq$>WPuNg8K4|wi@i;ZuwJv^!c?39hyjwE zS`I+V2beoal5a{#a_&3;o* zNJ7ZM?@-V;9uWaBSq`8Y0HD+0#S^)%VqY{exQ1#zeZgCH1eRb^H7Z#J?4Safgz2MWdloP|+X7})|w=#NOC z{Zg#h&xYZsMkN}Z!Bj>G)f#|f6beqID5^%;=_n3V7NNOpwWE@jcL>cmp1mgPR0-Y0 z>3X9!@B0Z;>(GRQ45p5*-V*)gW-C^HU~aQ^-Fn*%8=bd&Db;=Zs!*NudOm*%@)r(6zCjhBw3^9C4s0T#lS zT;j;EZ`SIsa;b4wlo+l%8f`y`bD+KO8{I$xVK6a17L+icB_j^kXU`iqGusW0?bNM# z@IasxW$6LF;_T~L$JewSQRf6OAzkc102{n$5}Kkk!%NcQev#bJfBw7ka>I_5mZguc zKKD#jS#RxmGV8Q?m+Q4kY)Gj0hbGZx9n=NOsEyUrSrvWJ`@_dt&t3}Hc6wcHL0*-Q zqq$YsDTA%%9Ss@{2kBHVqMj|U+$pAe*Nr%O|5RHImMzT@3!+2 z-8-5cCrt3a1ey8UxQmP~@v%t~#@gS+%TuSFCZZehMZ#(9yU8Xn;~zj$mlX!av(rP^E)v*vw!%-S<6~(dJ%!!avopInyus6&WsT? zLc4s2r3+)k6w}0B`i(As;~kuFr`RwlHc-l|tDX4xvQ5h7<&}PW%{+E=Ty5sKT09(` zj~?AM#BHT();QSRlg>1D`b=la??}Eo+W$>)GuGw>;)}-eB0*{fx*ZpL0ZkW}!dQ*O-co z3I;wvE8scbz1yfqc*VkQS-HHZ+u-Kf?W=;SJoZhNbKER?YtXMdob218sJrbowj_=fg=5&#fXMFOu@Ie42rZNsP+8QU8TxP|vem{)HrF tAk1o4-@iWHWJVElW5Rp|7RP6X&C9rY_lbdSQTpY#+qEzjv}9!8zX6q%Nyq>I diff --git a/micropython/examples/badger2040w/icons/icon-rain.jpg b/micropython/examples/badger2040w/icons/icon-rain.jpg deleted file mode 100644 index e0d536d5ad20963d36852fc17c062aa7088b89bc..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3324 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 T8mhDetU><2@KA6Z8GigPi%&B2 diff --git a/micropython/examples/badger2040w/icons/icon-snow.jpg b/micropython/examples/badger2040w/icons/icon-snow.jpg deleted file mode 100644 index db18190d91d3ee3b13eb11bc6bb73fc0d3846536..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 4008 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 C5O>)C diff --git a/micropython/examples/badger2040w/icons/icon-storm.jpg b/micropython/examples/badger2040w/icons/icon-storm.jpg deleted file mode 100644 index b01a93712ab8beee8b2210795a688a880e44f54f..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 3055 zcmbVO2UJvN7QQoYhTa*PvOo|l2tg4WMi{ChARQElNSOhoN)d=O4N9>@iXa+fuu+C0 zA|h%WG!&H(3(`A8i6}6Pk&H6K+kY@ebM~xzcK5#ao!j31?tkBZ9^QkGfXognYbziS z2;hMZz{iMJt8`iT7nI6;6zLt;>Eiy~ksK?`$rMo%qtslqm}20L&74e*5+2!arZ20io)Lz*aX zLUyw+#4lNlcR*3TC@Kj2P=p19Ln!zx#)DuDkPnj2y^W%;Ggwp+B+LNFLpc6c8$dV* zfPV_d=ZkTie*pj+0B8*R93RdA*z^wRPkq*D6#+=60^Df&tn?v3z?^jUll zhVDc<9e`5;Ah{br{t1AX=f}Pwo4^hiy8&EKuWZ`^3eEy74?wxSzQ9`q1$^q;fAsmQ ze|SHb14bkYP9!9Bl10d55{WD(EG#4Rh^R&(VG&U=apX`Z14IIb5lNV!YUG`W>_Czw%YC)hR7l>@M_6+|#o$m@vB)yB zntKXPPuW`Qd?OEwiYY27t1Qu8zGCGn9mDk-Hg4K%WNu+;wQalg4rdovH+Qsfe*QFi zKw!|msOXpjv2pR=eV=;dXj*zkW_C{Q>Ad_i1!pf@yma|WNoiU6wc6`-H|lRT+`9jB zQ*%q}gNKivbv*Cv>h9_78yy?}?ZwN9-(OA6a^C*&ZthR+`ws$M1i(Jh`o!#Cc%dc` zh$Iq55*F|x5M$AW$&$!ltre0pbrkm5FRy8ENQ7dRRa|pVblEy5wt{cuQ!zy?!%^*7 z0kuVD{~fWz{};1Q#6I)t0||_P77vpJ6W}{Dq<^jEuEc>yNp|5XRkg8ik4CfnXFFLr z#x>Pm9u;L*E|#~c%Czd_=DAy01dpWoaaR>zVHHcCrh&#Ytx zK98{}X}EcAU+TA<&AL6Vt}5SRmWGitbhlgVlb1Kl zTWbz3Got>Y+*cFy?Vpw@-a%RZSP<~7xkqpy2XmK>>ZdL7PB-*yH*fxKj!Bz47cS9f z`oha|vs_Ak_QvUveqGO{L0Rlqnp#=cYJgLHG@0#bFB12Cv%{{q{?Vc05x!z*8Na$@ z($9sXdh6>~J{(^kxv~RvyBSVOO-&e>nB5_a;~>RzW{2gBJrVG9>Gr*PY#2HeRFEaeYd|dSgCfOQn#^3>xBL4 z0*av#HJ+|Ezy(*Ll<^(|A~f6*fEiPueb&is z=n+s4W(;80v`CUfGI+xXHLNb7HV(Ks(oQkEOD; z-*HB4@>S0bwsxAe4_AMas(VcBL5cw@+=Rq6pUdMPHDvW!_1{ZoABt;FYAzi($JD5= ze`2S5z)FSYbUu398XJk}3R}l3oyTn(A<4!;s5%vgdXrI|r>s%sg(oU{le@Q_OF ziRo&MTLqjy-5wZlnx>oX_~|WOOZ&wlooZt6E_C@kwKF`rednX`ozE+-91Lb|xp{UK ztM`Ay zNp5TByrDV=9m|!1jLgn$2wXzEL!#UmUpPWpzbx{gNLaMpeJ=&NmqFYA$Ik z*Ul=5$z{gxyV~-Mc-QZK8f3x;=7PBRY*$OTe4OWq$&r!z4&K%guFu`)x>FjviZfp^ z`h&tUUPvC3tocTP-&uef!DlkdJVV%Fj$ z<5Ga+vX%5Es%VOd2O2c#HgB#@$yDq3FvPVjP*4`7U2G#u$-BkLV{yBu!eSI6)C{kk z-oBc6Rfn@mf@3wyD?h0XykdrQIm=hQ-`$*lB6(Dsg~Jh4hG>4q`s%Nxr>xhf*3Rpd zCk)w|zqz()Xdm`Z#y`#)`Ef{}&y4AxQB80uYEn~W)4E>& zT;@fKu}g~YZr@!T-&rgBR?+GvZSVWOa~ZMe*j#d>8n9>XKNfmrEYCil6JE?cxFglG hx2GSwvHqb}wzcjr%>{)SbUNMFS}P^`@7i|_@A zNi4Qs0L0Z08}Q%;A$}y%`+vZ*A{@Mq(GUU>&%@0Iaw9>k7W^0N{};?+^TMDH4f<#W zgmK{d=r2Ct01@Vka9C&*+}pZ{7)k|l_PfKc7JO8JJz#>pzy+uQe-H&iKq!a=hVaXQ znh4+q?be@&r>w`jz$kwh6#`f=Vh`YgFyOZy4@5P9K2Sd9HX_K>WL<@lvIYS6vrxF8 z4FLW;0ITPO!j)p7aJ2*g%u@hvaz4g$ivTct3-#wd>a+?0kUa%JQ`bkGe=Y#crvcdT zINXotxBedte4~Sc0C-&ifV39?3ikjY9Q=?sXcO7NaaX2g%N5JF7#H9#QQj!EoNog5*IcXW9jHINT zq8w3yL?)A^WR*53k~YYb$RyDsC=86j;v{f536iv=H0gg9;Y~mk2bRDRgCYVn5rrY5 zgk69N8xaTROEhAC2nr4ND25l8AV@-oMmc~+VK8VcMzm|_eFEA6mWY#AH?|T}aP`A$ z93z<|W)_QUTGzId-3A3(rvAJn34)^124#x2&Su>$dbI63=w{}h+3c~kvv*)Rx_j(D z;0X)I3J44eW``V!h>VJki9P<+$x~k^pH4|VlXd>v?3~;SdHE%mOUueDDzAK3SKrXs z)ZFsJ^^VT2?w;OTeYfuq4L^7|^62rCiOH$wzr2|K_2ta`>xDOO7nhLbcOqUWfcZe{ zPiFtZ3nl@D#$qv8yoeVH9RnW>5sOnd7L&Jf#rqvo&@f39Cs}6}*S1S&nz{+d{=7kg zq84pJdtO9so!Ng!Eb0GZ_9wBAyq*9l3RyCSU=(uCQX9^86(+Yedv@2T zBEj8sihb(b4XZ2cJIAHuvj3(VxMR>t%PHBM?4LwjsNxS^{(FnGCAG}AcI-V_rQNr| z@NVIRFQt<^&PbuV+XM%50*)I*g?R6FG9h;v1RQXcs%DPKmuA(=0ohT7HA4D$&EuJA z7eP%@ar69imx@<;{f%aMi|Egss;FWi=*b{?lPk$O*wE}R9r7&IsQGOuAqb(SGUVGh zHK$t5=jmrS+v63UA}99_=D%jE6LQ=g4a<_uva!diY%MyU?_VyB*}(HoU=-y8T~H*W zKc&>Ojqsiz5W6xd1WGeG@1hF=rRwZS%|zSnvsV;u8-CxFk;Ht)3eSA5s5!&NEPn&j zLIAp$cM-_W`LvFr6nWMOU~lBHuD_? z%)#Kr)zUbNxS>MnxE)AE=WcVPaWaje@N&qWe4kBu-juVooWw3o)@P}*Yl!IrqRO=P zu(_Wl)yM@uDg**&2D16$(%iQ1Mvkw`_l)%m$H z|NOy=!&_qSVMkT+Na$Or1<&^+(>00d6DzbM&6~^wyMF4qEV#OOc%wu}(7nLuj!sk6 zoWu)XXRyv^X`cK2(E{LGSyG+X`o}ggLIzTORrrPzg&4l~yzO-ATjkO-54NxJ4*p1T zm29ZnOYX~}d!#rZx^u75XMA*vWbfA?di2>C`kbVol}bT8om+lFPEP3h-m1OUnEv8H zb>46v%3>$YhF`0f(`QoB({H4P5j;s?9D*s?tyQq-wE9h}5?@wusq9#V&yj0F5H#i+ zav<}GO{JIj&61^mpwjF{OrP3l;x@;c;(5v^6XI;|p)9Fa3k7?Bm*2bMwbtWHio+xI zZY{$cT4j8FD7W#T!*3Hqvsa7!0)I(rFFhJE_af7Vcum~ej8F_18oy$eHm^xUtZeLG z*~Q;h(9^0n^qWDe8q!2snB~r~m<f(UndE}^X+^S63lZ&sxzzQ-aB;C!E*}cxKG52BeZ4S`?9EhRVFKLh#rlkQI`kU@ z%!21)CL+7CkMD?#P8KS}PETw*v(3V}vR}2?xrohs_NXMq)jvZy>{RCUQfu0+81A{# z{uAkd-)>3e3PHPt5R4b+j@8>$amV9TeSD5E2)_qutBU1>iFt-L+^g(kE2oC2E1T;$ z^sK%#!ryPzg6ZMLeQ5Bq$$>;6AccuKyl9w9d#3qEho_vKwJH&H_%)^~c2q-r7*v8- z?wZ6;D?8WvazEpy?Kb1PHji)&$_riVhoa&&_tg$-ByHDW)GFp2ZL&Yyt;wTCvRQ{6 zTk!q90+#_qH&8UXPh+V!mz35=H!((ieRTC{x5MG+Qq1j0oUnw(MG)T^>b~q z)tJ9gP}A!Rj$D$PkIUs&zHGjBN0oPnORD#BoVT!k@$^=P=0!#OEjkizaU}_i3%5mQ zAw2CX7$@8Ce0_obO^WX+3-z+mmrugJHMZBPJ=jeesVij?e`ql-k=PuSF4>px#o3}F znTP8~;qoFf4|mH%vR9(`-U50u-|$!!a%sAYl2g|dJ|ON`&Tx?`fcTtS9bZlT+^Gcez<0VoIFaS=fsH7GkTfXtmih$p-vrkK?;sV z>6s?>3R|?mYAs_tcQ;|Rm=h&Sj@3IFk9u!)J^$#PJBccNtSZMrfzCHO)L9x;$|Y|5 zmc6F3FUX;ms|3_V4su>FvN(f$KF(E$^`3H=-_@K#dlp#z;*xw#pj62V=<3s}QSIUs UXUEN_Tjk=|n0FGQtOy_f6Fh^dAOHXW diff --git a/micropython/examples/badger2040w/images/README.txt b/micropython/examples/badger2040w/images/README.txt deleted file mode 100644 index c9a6e267..00000000 --- a/micropython/examples/badger2040w/images/README.txt +++ /dev/null @@ -1,3 +0,0 @@ -Images must be 296x128 pixel JPEGs - -Create a new "images" directory via Thonny, and upload your .jpg files there. diff --git a/micropython/examples/badger2040w/images/badgerpunk.jpg b/micropython/examples/badger2040w/images/badgerpunk.jpg deleted file mode 100644 index 73f32be9525032d80bfb9bcb2b967daa1f496c36..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9264 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 0: - state["page"] -= 1 - render() - if pin == badger2040.BUTTON_DOWN: - if state["page"] < MAX_PAGE - 1: - state["page"] += 1 - render() - - -if exited_to_launcher or not woken_by_button: - wait_for_user_to_release_buttons() - display.set_update_speed(badger2040.UPDATE_MEDIUM) - render() - -display.set_update_speed(badger2040.UPDATE_FAST) - -while True: - if display.pressed(badger2040.BUTTON_A): - button(badger2040.BUTTON_A) - if display.pressed(badger2040.BUTTON_B): - button(badger2040.BUTTON_B) - if display.pressed(badger2040.BUTTON_C): - button(badger2040.BUTTON_C) - - if display.pressed(badger2040.BUTTON_UP): - button(badger2040.BUTTON_UP) - if display.pressed(badger2040.BUTTON_DOWN): - button(badger2040.BUTTON_DOWN) - - if changed: - badger_os.state_save("launcher", state) - changed = False - - display.halt() diff --git a/micropython/examples/badger2040w/lib/badger2040w.py b/micropython/examples/badger2040w/lib/badger2040w.py deleted file mode 100644 index 8b733503..00000000 --- a/micropython/examples/badger2040w/lib/badger2040w.py +++ /dev/null @@ -1,181 +0,0 @@ -import machine -import micropython -from picographics import PicoGraphics, DISPLAY_INKY_PACK -import network -from network_manager import NetworkManager -import WIFI_CONFIG -import uasyncio -import time -import gc -import wakeup - - -BUTTON_DOWN = 11 -BUTTON_A = 12 -BUTTON_B = 13 -BUTTON_C = 14 -BUTTON_UP = 15 -BUTTON_USER = None # User button not available on W - -BUTTON_MASK = 0b11111 << 11 - -SYSTEM_VERY_SLOW = 0 -SYSTEM_SLOW = 1 -SYSTEM_NORMAL = 2 -SYSTEM_FAST = 3 -SYSTEM_TURBO = 4 - -UPDATE_NORMAL = 0 -UPDATE_MEDIUM = 1 -UPDATE_FAST = 2 -UPDATE_TURBO = 3 - -LED = 22 -ENABLE_3V3 = 10 -BUSY = 26 - -WIDTH = 296 -HEIGHT = 128 - -SYSTEM_FREQS = [ - 4000000, - 12000000, - 48000000, - 133000000, - 250000000 -] - -BUTTONS = { - BUTTON_DOWN: machine.Pin(BUTTON_DOWN, machine.Pin.IN, machine.Pin.PULL_DOWN), - BUTTON_A: machine.Pin(BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN), - BUTTON_B: machine.Pin(BUTTON_B, machine.Pin.IN, machine.Pin.PULL_DOWN), - BUTTON_C: machine.Pin(BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN), - BUTTON_UP: machine.Pin(BUTTON_UP, machine.Pin.IN, machine.Pin.PULL_DOWN), -} - -WAKEUP_MASK = 0 - - -def woken_by_button(): - return wakeup.get_gpio_state() & BUTTON_MASK > 0 - - -def pressed_to_wake(button): - return wakeup.get_gpio_state() & (1 << button) > 0 - - -def reset_pressed_to_wake(): - wakeup.reset_gpio_state() - - -def pressed_to_wake_get_once(button): - global WAKEUP_MASK - result = (wakeup.get_gpio_state() & ~WAKEUP_MASK & (1 << button)) > 0 - WAKEUP_MASK |= (1 << button) - return result - - -def system_speed(speed): - try: - machine.freq(SYSTEM_FREQS[speed]) - except IndexError: - pass - - -class Badger2040W(): - def __init__(self): - self.display = PicoGraphics(DISPLAY_INKY_PACK) - self._led = machine.PWM(machine.Pin(LED)) - self._led.freq(1000) - self._led.duty_u16(0) - self._update_speed = 0 - - def __getattr__(self, item): - # Glue to redirect calls to PicoGraphics - return getattr(self.display, item) - - def update(self): - t_start = time.ticks_ms() - self.display.update() - t_elapsed = time.ticks_ms() - t_start - - delay_ms = [4700, 2600, 900, 250][self._update_speed] - - if t_elapsed < delay_ms: - time.sleep((delay_ms - t_elapsed) / 1000) - - def set_update_speed(self, speed): - self.display.set_update_speed(speed) - self._update_speed = speed - - def led(self, brightness): - brightness = max(0, min(255, brightness)) - self._led.duty_u16(int(brightness * 256)) - - def invert(self, invert): - raise RuntimeError("Display invert not supported in PicoGraphics.") - - def thickness(self, thickness): - raise RuntimeError("Thickness not supported in PicoGraphics.") - - def halt(self): - time.sleep(0.05) - enable = machine.Pin(ENABLE_3V3, machine.Pin.OUT) - enable.off() - while not self.pressed_any(): - pass - - def pressed(self, button): - return BUTTONS[button].value() == 1 or pressed_to_wake_get_once(button) - - def pressed_any(self): - for button in BUTTONS.values(): - if button.value(): - return True - return False - - @micropython.native - def icon(self, data, index, data_w, icon_size, x, y): - s_x = (index * icon_size) % data_w - s_y = int((index * icon_size) / data_w) - - for o_y in range(icon_size): - for o_x in range(icon_size): - o = ((o_y + s_y) * data_w) + (o_x + s_x) - bm = 0b10000000 >> (o & 0b111) - if data[o >> 3] & bm: - self.display.pixel(x + o_x, y + o_y) - - def image(self, data, w, h, x, y): - for oy in range(h): - row = data[oy] - for ox in range(w): - if row & 0b1 == 0: - self.display.pixel(x + ox, y + oy) - row >>= 1 - - def status_handler(self, mode, status, ip): - print(mode, status, ip) - self.display.set_pen(15) - self.display.clear() - self.display.set_pen(0) - if status: - self.display.text("Connected!", 10, 10, 300, 0.5) - self.display.text(ip, 10, 30, 300, 0.5) - else: - self.display.text("Connecting...", 10, 10, 300, 0.5) - self.update() - - def isconnected(self): - return network.WLAN(network.STA_IF).isconnected() - - def ip_address(self): - return network.WLAN(network.STA_IF).ifconfig()[0] - - def connect(self): - if WIFI_CONFIG.COUNTRY == "": - raise RuntimeError("You must populate WIFI_CONFIG.py for networking.") - self.display.set_update_speed(2) - network_manager = NetworkManager(WIFI_CONFIG.COUNTRY, status_handler=self.status_handler) - uasyncio.get_event_loop().run_until_complete(network_manager.client(WIFI_CONFIG.SSID, WIFI_CONFIG.PSK)) - gc.collect() diff --git a/micropython/examples/badger2040w/lib/badger_os.py b/micropython/examples/badger2040w/lib/badger_os.py deleted file mode 100644 index 3eaaec63..00000000 --- a/micropython/examples/badger2040w/lib/badger_os.py +++ /dev/null @@ -1,188 +0,0 @@ -"""Keep track of app state in persistent flash storage.""" - -import os -import gc -import time -import json -import machine -import badger2040w as badger2040 - - -def get_battery_level(): - return 0 - # Battery measurement - vbat_adc = machine.ADC(badger2040.PIN_BATTERY) - vref_adc = machine.ADC(badger2040.PIN_1V2_REF) - vref_en = machine.Pin(badger2040.PIN_VREF_POWER) - vref_en.init(machine.Pin.OUT) - vref_en.value(0) - - # Enable the onboard voltage reference - vref_en.value(1) - - # Calculate the logic supply voltage, as will be lower that the usual 3.3V when running off low batteries - vdd = 1.24 * (65535 / vref_adc.read_u16()) - vbat = ( - (vbat_adc.read_u16() / 65535) * 3 * vdd - ) # 3 in this is a gain, not rounding of 3.3V - - # Disable the onboard voltage reference - vref_en.value(0) - - # Convert the voltage to a level to display onscreen - return vbat - - -def get_disk_usage(): - # f_bfree and f_bavail should be the same? - # f_files, f_ffree, f_favail and f_flag are unsupported. - f_bsize, f_frsize, f_blocks, f_bfree, _, _, _, _, _, f_namemax = os.statvfs("/") - - f_total_size = f_frsize * f_blocks - f_total_free = f_bsize * f_bfree - f_total_used = f_total_size - f_total_free - - f_used = 100 / f_total_size * f_total_used - f_free = 100 / f_total_size * f_total_free - - return f_total_size, f_used, f_free - - -def state_running(): - state = {"running": "launcher"} - state_load("launcher", state) - return state["running"] - - -def state_clear_running(): - running = state_running() - state_modify("launcher", {"running": "launcher"}) - return running != "launcher" - - -def state_set_running(app): - state_modify("launcher", {"running": app}) - - -def state_launch(): - app = state_running() - if app is not None and app != "launcher": - launch(app) - - -def state_delete(app): - try: - os.remove("/state/{}.json".format(app)) - except OSError: - pass - - -def state_save(app, data): - try: - with open("/state/{}.json".format(app), "w") as f: - f.write(json.dumps(data)) - f.flush() - except OSError: - import os - try: - os.stat("/state") - except OSError: - os.mkdir("/state") - state_save(app, data) - - -def state_modify(app, data): - state = {} - state_load(app, state) - state.update(data) - state_save(app, state) - - -def state_load(app, defaults): - try: - data = json.loads(open("/state/{}.json".format(app), "r").read()) - if type(data) is dict: - defaults.update(data) - return True - except (OSError, ValueError): - pass - - state_save(app, defaults) - return False - - -def launch(file): - state_set_running(file) - - gc.collect() - - button_a = machine.Pin(badger2040.BUTTON_A, machine.Pin.IN, machine.Pin.PULL_DOWN) - button_c = machine.Pin(badger2040.BUTTON_C, machine.Pin.IN, machine.Pin.PULL_DOWN) - - def quit_to_launcher(pin): - if button_a.value() and button_c.value(): - machine.reset() - - button_a.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) - button_c.irq(trigger=machine.Pin.IRQ_RISING, handler=quit_to_launcher) - - try: - __import__(file) - - except ImportError: - # If the app doesn't exist, notify the user - warning(None, f"Could not launch: {file}") - time.sleep(4.0) - except Exception as e: - # If the app throws an error, catch it and display! - print(e) - warning(None, str(e)) - time.sleep(4.0) - - # If the app exits or errors, do not relaunch! - state_clear_running() - machine.reset() # Exit back to launcher - - -# Draw an overlay box with a given message within it -def warning(display, message, width=badger2040.WIDTH - 20, height=badger2040.HEIGHT - 20, line_spacing=20, text_size=0.6): - print(message) - - if display is None: - display = badger2040.Badger2040W() - display.led(128) - - # Draw a light grey background - display.set_pen(12) - display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height) - - width -= 20 - height -= 20 - - display.set_pen(15) - display.rectangle((badger2040.WIDTH - width) // 2, (badger2040.HEIGHT - height) // 2, width, height) - - # Take the provided message and split it up into - # lines that fit within the specified width - words = message.split(" ") - - lines = [] - current_line = "" - for word in words: - if display.measure_text(current_line + word + " ", text_size) < width: - current_line += word + " " - else: - lines.append(current_line.strip()) - current_line = word + " " - lines.append(current_line.strip()) - - display.set_pen(0) - - # Display each line of text from the message, centre-aligned - num_lines = len(lines) - for i in range(num_lines): - length = display.measure_text(lines[i], text_size) - current_line = (i * line_spacing) - ((num_lines - 1) * line_spacing) // 2 - display.text(lines[i], (badger2040.WIDTH - length) // 2, (badger2040.HEIGHT // 2) + current_line, badger2040.WIDTH, text_size) - - display.update() diff --git a/micropython/examples/badger2040w/lib/network_manager.py b/micropython/examples/badger2040w/lib/network_manager.py deleted file mode 100644 index fb21c2c4..00000000 --- a/micropython/examples/badger2040w/lib/network_manager.py +++ /dev/null @@ -1,108 +0,0 @@ -import rp2 -import network -import machine -import uasyncio - - -class NetworkManager: - _ifname = ("Client", "Access Point") - - def __init__(self, country="GB", client_timeout=60, access_point_timeout=5, status_handler=None, error_handler=None): - rp2.country(country) - self._ap_if = network.WLAN(network.AP_IF) - self._sta_if = network.WLAN(network.STA_IF) - - self._mode = network.STA_IF - self._client_timeout = client_timeout - self._access_point_timeout = access_point_timeout - self._status_handler = status_handler - self._error_handler = error_handler - self.UID = ("{:02X}" * 8).format(*machine.unique_id()) - - def isconnected(self): - return self._sta_if.isconnected() or self._ap_if.isconnected() - - def config(self, var): - if self._sta_if.active(): - return self._sta_if.config(var) - else: - if var == "password": - return self.UID - return self._ap_if.config(var) - - def mode(self): - if self._sta_if.isconnected(): - return self._ifname[0] - if self._ap_if.isconnected(): - return self._ifname[1] - return None - - def ifaddress(self): - if self._sta_if.isconnected(): - return self._sta_if.ifconfig()[0] - if self._ap_if.isconnected(): - return self._ap_if.ifconfig()[0] - return '0.0.0.0' - - def disconnect(self): - if self._sta_if.isconnected(): - self._sta_if.disconnect() - if self._ap_if.isconnected(): - self._ap_if.disconnect() - - async def wait(self, mode): - while not self.isconnected(): - self._handle_status(mode, None) - await uasyncio.sleep_ms(1000) - - def _handle_status(self, mode, status): - if callable(self._status_handler): - self._status_handler(self._ifname[mode], status, self.ifaddress()) - - def _handle_error(self, mode, msg): - if callable(self._error_handler): - if self._error_handler(self._ifname[mode], msg): - return - raise RuntimeError(msg) - - async def client(self, ssid, psk): - if self._sta_if.isconnected(): - self._handle_status(network.STA_IF, True) - return - - self._ap_if.disconnect() - self._ap_if.active(False) - - self._sta_if.active(True) - self._sta_if.config(pm=0xa11140) - self._sta_if.connect(ssid, psk) - - try: - await uasyncio.wait_for(self.wait(network.STA_IF), self._client_timeout) - self._handle_status(network.STA_IF, True) - - except uasyncio.TimeoutError: - self._sta_if.active(False) - self._handle_status(network.STA_IF, False) - self._handle_error(network.STA_IF, "WIFI Client Failed") - - async def access_point(self): - if self._ap_if.isconnected(): - self._handle_status(network.AP_IF, True) - return - - self._sta_if.disconnect() - self._sta_if.active(False) - - self._ap_if.ifconfig(("10.10.1.1", "255.255.255.0", "10.10.1.1", "10.10.1.1")) - self._ap_if.config(password=self.UID) - self._ap_if.active(True) - - try: - await uasyncio.wait_for(self.wait(network.AP_IF), self._access_point_timeout) - self._handle_status(network.AP_IF, True) - - except uasyncio.TimeoutError: - self._sta_if.active(False) - self._handle_status(network.AP_IF, False) - self._handle_error(network.AP_IF, "WIFI Client Failed") diff --git a/micropython/examples/badger2040w/main.py b/micropython/examples/badger2040w/main.py deleted file mode 100644 index 967457fd..00000000 --- a/micropython/examples/badger2040w/main.py +++ /dev/null @@ -1 +0,0 @@ -import launcher # noqa F401 diff --git a/micropython/examples/badger2040w/readme.md b/micropython/examples/badger2040w/readme.md deleted file mode 100644 index d8da7f48..00000000 --- a/micropython/examples/badger2040w/readme.md +++ /dev/null @@ -1,113 +0,0 @@ -# Badger 2040 W MicroPython Examples - -:warning: This code has been deprecated in favour of a dedicated Badger 2040 project: https://github.com/pimoroni/badger2040 - -- [About Badger 2040 W](#about-badger-2040-w) -- [Badger 2040 W and PicoGraphics](#badger-2040-w-and-picographics) -- [Examples](#examples) - - [Badge](#badge) - - [Clock](#clock) - - [Ebook](#ebook) - - [Fonts](#fonts) - - [Help](#help) - - [Image](#image) - - [Info](#info) - - [List](#list) - - [Net Info](#net-info) - - [News](#news) - - [Qrgen](#qrgen) - - [Weather](#weather) -- [Other Resources](#other-resources) - - -## About Badger 2040 W - -Badger 2040 W is a programmable E Paper/eInk/EPD badge with 2.4GHz wireless connectivity, powered by Raspberry Pi Pico W. It can go into a deep sleep mode between updates to preserve battery. - -- :link: [Badger 2040 W store page](https://shop.pimoroni.com/products/badger-2040-w) - -Badger 2040 W ships with MicroPython firmware pre-loaded, but you can download the most recent version at the link below (you'll want the `pimoroni-badger2040w` .uf2). If you download the `-with-examples` file, it will come with examples built in. - -- [MicroPython releases](https://github.com/pimoroni/pimoroni-pico/releases) -- [Installing MicroPython](../../../setting-up-micropython.md) - -## Badger 2040 W and PicoGraphics - -The easiest way to start displaying cool stuff on Badger is by using our `badger2040w` module (which contains helpful functions for interacting with the board hardware) and our PicoGraphics library (which contains a bunch of functions for drawing on the E Ink display). - -- [Badger 2040 W function reference](../../modules/badger2040w/README.md) -- [PicoGraphics function reference](../../modules/picographics/README.md) - -## Examples - -Find out more about how to use these examples in our Learn guide: - -- [Getting Started with Badger 2040 W](https://learn.pimoroni.com/article/getting-started-with-badger-2040-w) - -### Badge -[badge.py](examples/badge.py) - -Customisable name badge example. - -### Clock -[clock.py](examples/clock.py) - -Clock example with (optional) NTP synchronization and partial screen updates. - -### Ebook -[ebook.py](examples/ebook.py) - -View text files on Badger. - -### Fonts -[fonts.py](examples/fonts.py) - -View all the built in fonts. - -### Help -[help.py](examples/help.py) - -How to navigate the launcher. - -### Image -[image.py](examples/image.py) - -Display .jpegs on Badger. - -### Info -[info.py](examples/info.py) - -Info about Badger 2040 W. - -### List -[list.py](examples/list.py) - -A checklist to keep track of to-dos or shopping. - -### Net Info -[net_info.py](examples/net_info.py) - -Show IP address and other wireless connection details. - -### News -[news.py](examples/news.py) - -View BBC news headlines. - -### Qrgen -[qrgen.py](examples/qrgen.py) - -Display QR codes and associated text. - -### Weather -[weather.py](examples/weather.py) - -Display current weather data from the [Open-Meteo weather API](https://open-meteo.com/) - -## Other Resources - -Here are some cool Badger 2040 W community projects and resources that you might find useful / inspirational! Note that code at the links below has not been tested by us and we're not able to offer support with it. - -- :link: [Send messages to Badger via webform](https://github.com/techcree/Badger2040W/tree/main/webform) -- :link: [3D printed Badger 2040 W enclosure](https://kaenner.de/badger2040w) -- :link: [Badger Pixel Client for a Raspberry Pi Pixel Server](https://github.com/penguintutor/badger-pixel-client) \ No newline at end of file diff --git a/micropython/examples/badger2040w/uf2-manifest.txt b/micropython/examples/badger2040w/uf2-manifest.txt deleted file mode 100644 index 715515cd..00000000 --- a/micropython/examples/badger2040w/uf2-manifest.txt +++ /dev/null @@ -1,10 +0,0 @@ -*.py -lib/*.py -examples/*.jpg -examples/*.py -images/*.jpg -images/*.txt -badges/*.txt -badges/*.jpg -books/*.txt -icons/*.jpg \ No newline at end of file