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 b5147dc7..00000000 Binary files a/micropython/examples/badger2040/assets/badge_image.png and /dev/null differ diff --git a/micropython/examples/badger2040/assets/badgerpunk.png b/micropython/examples/badger2040/assets/badgerpunk.png deleted file mode 100644 index f7568a2e..00000000 Binary files a/micropython/examples/badger2040/assets/badgerpunk.png and /dev/null differ diff --git a/micropython/examples/badger2040/assets/boot.py b/micropython/examples/badger2040/assets/boot.py deleted file mode 100644 index 76b5ef6d..00000000 --- a/micropython/examples/badger2040/assets/boot.py +++ /dev/null @@ -1,6 +0,0 @@ -try: - open("main.py", "r") -except OSError: - with open("main.py", "w") as f: - f.write("import _launcher") - f.flush() diff --git a/micropython/examples/badger2040/assets/launchericons.png b/micropython/examples/badger2040/assets/launchericons.png deleted file mode 100644 index da93e0a0..00000000 Binary files a/micropython/examples/badger2040/assets/launchericons.png and /dev/null differ diff --git a/micropython/examples/badger2040/badge.py b/micropython/examples/badger2040/badge.py deleted file mode 100644 index a72a674b..00000000 --- a/micropython/examples/badger2040/badge.py +++ /dev/null @@ -1,183 +0,0 @@ -import time -import badger2040 -import badger_os - -# Global Constants -WIDTH = badger2040.WIDTH -HEIGHT = badger2040.HEIGHT - -IMAGE_WIDTH = 104 - -COMPANY_HEIGHT = 30 -DETAILS_HEIGHT = 20 -NAME_HEIGHT = HEIGHT - COMPANY_HEIGHT - (DETAILS_HEIGHT * 2) - 2 -TEXT_WIDTH = WIDTH - IMAGE_WIDTH - 1 - -COMPANY_TEXT_SIZE = 0.6 -DETAILS_TEXT_SIZE = 0.5 - -LEFT_PADDING = 5 -NAME_PADDING = 20 -DETAIL_SPACING = 10 - -DEFAULT_TEXT = """mustelid inc -H. Badger -RP2040 -2MB Flash -E ink -296x128px""" - -BADGE_IMAGE = bytearray(int(IMAGE_WIDTH * HEIGHT / 8)) - -try: - open("badge-image.bin", "rb").readinto(BADGE_IMAGE) -except OSError: - try: - import badge_image - BADGE_IMAGE = bytearray(badge_image.data()) - del badge_image - except ImportError: - pass - - -# ------------------------------ -# Utility functions -# ------------------------------ - -# Reduce the size of a string until it fits within a given width -def truncatestring(text, text_size, width): - while True: - length = display.measure_text(text, text_size) - if length > 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 287a43ca..00000000 Binary files a/micropython/examples/badger2040w/badges/badge.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/badges/badge.txt b/micropython/examples/badger2040w/badges/badge.txt deleted file mode 100644 index 1295a461..00000000 --- a/micropython/examples/badger2040w/badges/badge.txt +++ /dev/null @@ -1,7 +0,0 @@ -mustelid inc -H. Badger -RP2040 -2MB Flash -E ink -296x128px -/badges/badge.jpg \ No newline at end of file diff --git a/micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt b/micropython/examples/badger2040w/books/289-0-wind-in-the-willows-abridged.txt deleted file mode 100644 index f6243fd9..00000000 --- a/micropython/examples/badger2040w/books/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/badger2040w/examples/badge.py b/micropython/examples/badger2040w/examples/badge.py deleted file mode 100644 index 3377d79c..00000000 --- a/micropython/examples/badger2040w/examples/badge.py +++ /dev/null @@ -1,172 +0,0 @@ -import time -import badger2040w -import badger_os -import jpegdec - -# Global Constants -WIDTH = badger2040w.WIDTH -HEIGHT = badger2040w.HEIGHT - -IMAGE_WIDTH = 104 - -COMPANY_HEIGHT = 30 -DETAILS_HEIGHT = 20 -NAME_HEIGHT = HEIGHT - COMPANY_HEIGHT - (DETAILS_HEIGHT * 2) - 2 -TEXT_WIDTH = WIDTH - IMAGE_WIDTH - 1 - -COMPANY_TEXT_SIZE = 0.6 -DETAILS_TEXT_SIZE = 0.5 - -LEFT_PADDING = 5 -NAME_PADDING = 20 -DETAIL_SPACING = 10 - -BADGE_PATH = "/badges/badge.txt" - -DEFAULT_TEXT = """mustelid inc -H. Badger -RP2040 -2MB Flash -E ink -296x128px -/badges/badge.jpg -""" - -# ------------------------------ -# Utility functions -# ------------------------------ - - -# Reduce the size of a string until it fits within a given width -def truncatestring(text, text_size, width): - while True: - length = display.measure_text(text, text_size) - if length > 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 0b86070d..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-badge.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-clock.jpg b/micropython/examples/badger2040w/examples/icon-clock.jpg deleted file mode 100644 index 48c37df1..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-clock.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-ebook.jpg b/micropython/examples/badger2040w/examples/icon-ebook.jpg deleted file mode 100644 index 4e7551fc..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-ebook.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-fonts.jpg b/micropython/examples/badger2040w/examples/icon-fonts.jpg deleted file mode 100644 index cef072f6..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-fonts.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-help.jpg b/micropython/examples/badger2040w/examples/icon-help.jpg deleted file mode 100644 index 80c3f6f5..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-help.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-image.jpg b/micropython/examples/badger2040w/examples/icon-image.jpg deleted file mode 100644 index e8ab644a..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-image.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-info.jpg b/micropython/examples/badger2040w/examples/icon-info.jpg deleted file mode 100644 index 4a43961b..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-info.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-list.jpg b/micropython/examples/badger2040w/examples/icon-list.jpg deleted file mode 100644 index e9552dda..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-list.jpg and /dev/null differ 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 f5817773..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-net-info.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-news.jpg b/micropython/examples/badger2040w/examples/icon-news.jpg deleted file mode 100644 index 0c281d34..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-news.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-qrgen.jpg b/micropython/examples/badger2040w/examples/icon-qrgen.jpg deleted file mode 100644 index 1f31e668..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-qrgen.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/examples/icon-weather.jpg b/micropython/examples/badger2040w/examples/icon-weather.jpg deleted file mode 100644 index 35d3bd00..00000000 Binary files a/micropython/examples/badger2040w/examples/icon-weather.jpg and /dev/null differ 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 b1b1e706..00000000 Binary files a/micropython/examples/badger2040w/icons/icon-cloud.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/icons/icon-rain.jpg b/micropython/examples/badger2040w/icons/icon-rain.jpg deleted file mode 100644 index e0d536d5..00000000 Binary files a/micropython/examples/badger2040w/icons/icon-rain.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/icons/icon-snow.jpg b/micropython/examples/badger2040w/icons/icon-snow.jpg deleted file mode 100644 index db18190d..00000000 Binary files a/micropython/examples/badger2040w/icons/icon-snow.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/icons/icon-storm.jpg b/micropython/examples/badger2040w/icons/icon-storm.jpg deleted file mode 100644 index b01a9371..00000000 Binary files a/micropython/examples/badger2040w/icons/icon-storm.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/icons/icon-sun.jpg b/micropython/examples/badger2040w/icons/icon-sun.jpg deleted file mode 100644 index 6c3703de..00000000 Binary files a/micropython/examples/badger2040w/icons/icon-sun.jpg and /dev/null differ 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 73f32be9..00000000 Binary files a/micropython/examples/badger2040w/images/badgerpunk.jpg and /dev/null differ diff --git a/micropython/examples/badger2040w/launcher.py b/micropython/examples/badger2040w/launcher.py deleted file mode 100644 index 941e21a8..00000000 --- a/micropython/examples/badger2040w/launcher.py +++ /dev/null @@ -1,183 +0,0 @@ -import gc -import os -import time -import math -import badger2040w as badger2040 -import badger_os -import jpegdec - -APP_DIR = "/examples" -FONT_SIZE = 2 - -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() - badger2040.reset_pressed_to_wake() -else: - # Otherwise restore previously running app - badger_os.state_launch() - - -display = badger2040.Badger2040W() -display.set_font("bitmap8") -display.led(128) - -jpeg = jpegdec.JPEG(display.display) - -state = { - "page": 0, - "running": "launcher" -} - -badger_os.state_load("launcher", state) - -examples = [x[:-3] for x in os.listdir("/examples") if x.endswith(".py")] - -# Approximate center lines for buttons A, B and C -centers = (41, 147, 253) - -MAX_PAGE = math.ceil(len(examples) / 3) - -WIDTH = 296 - - -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_disk_usage(x): - _, f_used, _ = badger_os.get_disk_usage() - - display.set_pen(15) - display.image( - bytearray( - ( - 0b00000000, - 0b00111100, - 0b00111100, - 0b00111100, - 0b00111000, - 0b00000000, - 0b00000000, - 0b00000001, - ) - ), - 8, - 8, - x, - 4, - ) - display.rectangle(x + 10, 3, 80, 10) - display.set_pen(0) - display.rectangle(x + 11, 4, 78, 8) - display.set_pen(15) - display.rectangle(x + 12, 5, int(76 / 100.0 * f_used), 6) - display.text("{:.2f}%".format(f_used), x + 91, 4, WIDTH, 1.0) - - -def render(): - display.set_pen(15) - display.clear() - display.set_pen(0) - - max_icons = min(3, len(examples[(state["page"] * 3):])) - - for i in range(max_icons): - x = centers[i] - label = examples[i + (state["page"] * 3)] - icon_label = label.replace("_", "-") - icon = f"{APP_DIR}/icon-{icon_label}.jpg" - label = label.replace("_", " ") - jpeg.open_file(icon) - jpeg.decode(x - 26, 30) - display.set_pen(0) - w = display.measure_text(label, FONT_SIZE) - display.text(label, int(x - (w / 2)), 16 + 80, WIDTH, FONT_SIZE) - - for i in range(MAX_PAGE): - x = 286 - y = int((128 / 2) - (MAX_PAGE * 10 / 2) + (i * 10)) - display.set_pen(0) - display.rectangle(x, y, 8, 8) - if state["page"] != i: - display.set_pen(15) - display.rectangle(x + 1, y + 1, 6, 6) - - display.set_pen(0) - display.rectangle(0, 0, WIDTH, 16) - draw_disk_usage(90) - display.set_pen(15) - display.text("badgerOS", 4, 4, WIDTH, 1.0) - - display.update() - - -def wait_for_user_to_release_buttons(): - while display.pressed_any(): - time.sleep(0.01) - - -def launch_example(index): - wait_for_user_to_release_buttons() - - file = examples[(state["page"] * 3) + index] - file = f"{APP_DIR}/{file}" - - 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 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() - - -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