<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Rick Carlino</title>
    <description>The latest articles on DEV Community by Rick Carlino (@rickcarlino).</description>
    <link>https://dev.to/rickcarlino</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F594048%2F3b3b3aea-ea7c-4a48-accc-2cdfd7c2c916.png</url>
      <title>DEV Community: Rick Carlino</title>
      <link>https://dev.to/rickcarlino</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/rickcarlino"/>
    <language>en</language>
    <item>
      <title>Tools and Practices I Use In Every Real-World Software Project</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Tue, 23 Mar 2021 13:34:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/tools-and-practices-i-use-in-every-real-world-software-project-2fde</link>
      <guid>https://dev.to/rickcarlino/tools-and-practices-i-use-in-every-real-world-software-project-2fde</guid>
      <description>&lt;p&gt;There are very few books written for junior-to-mid level developers that answer the question "How do I run a real-world software project?". Industry best practices often arise as the result of cross-pollination and institutional/tacit knowledge rather than explicitly prescribed rules that you can read about in a book.&lt;/p&gt;

&lt;p&gt;For developers working alone or in small organizations such as startups, these norms may not be obvious. Knowing which tools one needs to deploy a production-scale application is crucial knowledge.&lt;/p&gt;

&lt;p&gt;In 2019 I published the article "&lt;a href="https://rickcarlino.com/2019/11/02/software-tools-for-hobby-sized-projects-html.html"&gt;Software Tools for Hobby-Scale Projects&lt;/a&gt;." It is still one of my most popular blog entries. This post will explore the same idea within a professional context and hopefully help new or solo developers get guidance on tools and practices for new projects at small to mid-scale organizations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Objective:&lt;/strong&gt; Provide a list of tools and practices that apply to a majority of real-world software projects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Intended audience:&lt;/strong&gt; Developers familiar with software authorship wishing to learn about real-world software deployments and practices.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 12 Factor Methodology
&lt;/h2&gt;

&lt;p&gt;If you run an application with real customers, you should use &lt;a href="https://12factor.net/"&gt;the 12-Factor Methodology&lt;/a&gt;. The 12-Factor Methodology is a set of practices that improve commercial software development and will make your software easier to manage over the long term. Many recommendations are simple yet overlooked (example: "Store config in the environment"). If your application runs on Docker or Heroku, you may already practice many of the 12 factors. If you have not yet read the entire document, I recommend giving it a look. It's a straightforward read and offers a great set of practices for structuring new and existing projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Reliable Version Control System
&lt;/h2&gt;

&lt;p&gt;Software development is costly. The result of that process is computer source code. As the organization and its related software projects grow in complexity, you will need a reliable way to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Create backups of the project source code.&lt;/li&gt;
&lt;li&gt;Revert problematic changes to the project.&lt;/li&gt;
&lt;li&gt;Figure out who last modified a particular part of the codebase.&lt;/li&gt;
&lt;li&gt;View historical versions of the project.&lt;/li&gt;
&lt;li&gt;Merge changes from two developers who created parallel versions of the project.&lt;/li&gt;
&lt;li&gt;Figure out what changed between different versions of a project.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Most (but unfortunately not all) developers in the software industry have adopted version control systems (VCS) to solve the issues noted. For all of my software projects, I use Git as my VCS, which is the current industry leader. Alternatives such as &lt;a href="https://pijul.org/"&gt;Pijuul&lt;/a&gt;, &lt;a href="https://fossil-scm.org/home/doc/trunk/www/index.wiki"&gt;Fossil&lt;/a&gt;, and &lt;a href="https://en.wikipedia.org/wiki/Apache_Subversion"&gt;Subversion&lt;/a&gt; are also available.&lt;/p&gt;

&lt;p&gt;For some, choosing to use version control on a project may seem obvious that it does not even require mention. Unfortunately, there are still companies out there that like to host zip files on FTP servers as a form of pseudo-version control. Often this situation is the result of a developer's unwillingness to learn a version control system. Opting out of VCS is inappropriate in all cases.&lt;/p&gt;

&lt;p&gt;Choosing to build an in-house version control system (or opting out of version control) will cost you and your organization time and money. You will not create a solution that is more robust than Git. You will lose parts of your source code and historical information about the project. A good VCS can fix severe problems like data loss in seconds. Conversely, without a good VCS in place, certain classes of issues may take days or weeks to resolve if they are fixable at all.&lt;/p&gt;

&lt;p&gt;You should use Git on every professional software project. You can find alternatives to Git if you genuinely don't like it, but you must use some turn-key version control system and not build your own. Failing to use a real VCS will result in a loss of time and data.&lt;/p&gt;

&lt;p&gt;Although I've yet to find a version control system that is easy (or enjoyable) to grasp at first, you still need to eat your vegetables. The benefits of having a version control system cannot be understated, and that's why it appears in the top half of this list. You need to invest the time to learn it, reap the benefits, and move on.&lt;/p&gt;

&lt;p&gt;You can find a good starting point &lt;a href="https://lab.github.com/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Source Code Hosting
&lt;/h2&gt;

&lt;p&gt;Even if you are the only developer on a project, it is still a good idea to host redundant copies of source code somewhere other than your local machine. In the early days of the internet, it was not uncommon to hear horror stories of shareware projects that ceased development for no reason other than the lead developer had lost the source code. The advent of free and cheap source code hosting has made this type of disaster less common.&lt;/p&gt;

&lt;p&gt;Additionally, if you are working on the project with other developers, you will want to discuss and review changes to the Git repository as they happen. Many source code hosting tools offer extras such as features to review and discuss incoming changes easier.&lt;/p&gt;

&lt;p&gt;The most popular options are:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/"&gt;Github&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.com/"&gt;Gitlab&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://sourcehut.org/"&gt;Sourcehut&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bitbucket.org/product"&gt;Bitbucket&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitea.io/"&gt;Gitea (self-hosted)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git-scm.com/book/en/v2/Git-on-the-Server-The-Protocols"&gt;Use Git's internal server tools (the DIY option)&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The vast majority of developers will choose Github as the current industry leader. Github offers a broad feature set and decent free plans. The market for hosting solutions widened in recent years, with several alternatives gaining traction among developers that wish to avoid Microsoft products.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; You will need shared source code backups no matter your project or team size. Many companies that offer source code hosting offer additional features alongside the hosting such as webhooks and pull requests that make the product offerings extremely useful.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Database Backup System
&lt;/h2&gt;

&lt;p&gt;This one is obvious but overlooked. Your backup system needs to be automated- it's too easy to forget, and the consequences are disastrous (see the previous section about version control backups). Once you have a backup system that works, perform periodic "fire drills" to ensure that you can handle backups properly in an actual database failure. If your backup system is cloud-based, be sure to create redundant hard copies periodically. There is no guarantee that your &lt;a href="https://blog.malwarebytes.com/malwarebytes-news/2021/03/ovh-cloud-datacenter-destroyed-by-fire/"&gt;data center will not burn to the ground&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I currently manage my database backups with Heroku. There are too many options to name in this space. Your main concern when shopping for a backup system should always be reliability.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Database backups prevent disasters and are easy to set up, but you need to regularly make sure they will work in an emergency.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Testing Framework
&lt;/h2&gt;

&lt;p&gt;During a project's lifetime, the scope and importance of features will only increase, and so will the need for stability. Project maintainers ensure the reliability of a codebase by testing it. In the early days of a software project, it is easy to ensure things work. You can manually click buttons and pass in data. Project maturity brings an inevitable challenge- there is no way your team can manually test every change before a release. The number of ways data can be passed and combined makes it mathematically impossible to cover every possible use case within a single release cycle. How can you be sure that a recent update will not break other parts of the application?&lt;/p&gt;

&lt;p&gt;For decades, software developers have solved this challenge by writing a second software project to go alongside the main project. This second codebase is known as a "test suite," and it will automate away the process of testing the main application. Sometimes, the test suite will click actual buttons on the screen. These sorts of tests are known as "integration tests." A more common approach is to only test functions and modules in isolation. This second approach is known as "unit testing." Unit testing is more common in the wild because it produces consistent test output, is fast to run, and is easy to setup. Although unit testing is easier to manage, its main criticism is that it does not simulate real-world conditions effectively as integration testing.&lt;/p&gt;

&lt;p&gt;Philosophies abound on the most effective way to approach automated testing. There is also extensive jargon and countless books written on the subject. If you add a test suite to a project for the first time, do not be discouraged by philosophical debates. The most important aspect of a test suite is that it exists. Testing is an art that takes time to master, and the best way to increase your project's reliability is to begin writing a large volume of automated tests as soon as possible. For a delightful satire article on the subject, see: "&lt;a href="https://boyter.org/posts/expert-excuses-for-not-writing-unit-tests/"&gt;Expert Excuses for not Writing Unit Tests.&lt;/a&gt;"&lt;/p&gt;

&lt;p&gt;Once you are committed to the idea of automated testing, you must pick a library to automate the boring parts. The options are language-specific, and every language ecosystem has a good set of options available. The ubiquity of high-quality testing frameworks means you should not attempt to create an in-house testing framework.&lt;/p&gt;

&lt;p&gt;These days, I use &lt;a href="https://jestjs.io/"&gt;Jest&lt;/a&gt; for Javascript, &lt;a href="https://rspec.info/"&gt;RSpec&lt;/a&gt; for Ruby, and &lt;a href="https://hexdocs.pm/ex_unit/ExUnit.html"&gt;ExUnit&lt;/a&gt; for Elixir.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Manually testing a product before each deployment is mathematically impossible for small teams. Startups and solo projects need a way to test the product for defects in an automated manner.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Test Coverage Reporter
&lt;/h2&gt;

&lt;p&gt;Once you have a large volume of tests, you will find that they detect many problems that humans could not have noticed. Getting a project to that point takes considerable effort. A codebase will receive new features and remove old ones as it matures. If left unchecked, a test suite's usefulness will deteriorate with time until it no longer is a helpful tool for defect prevention. Developers need a way to ensure that every line of code added to a project has accompanying tests.&lt;/p&gt;

&lt;p&gt;The term "test coverage" is used in the software industry to determine what percent of application code is touched by test code. Under ideal circumstances, your application test coverage numbers should only ever go up. For real-world applications with thousands of lines of code, enforcing test coverage is difficult, even in teams where everyone is motivated to write tests. Luckily, there are tools available to record test coverage trends. Running these tools before merging new code is effective in maintaining a test suite's usefulness.&lt;/p&gt;

&lt;p&gt;I use &lt;a href="https://about.codecov.io/"&gt;CodeCov&lt;/a&gt; and &lt;a href="https://coveralls.io/"&gt;Coveralls&lt;/a&gt; to manage code coverage metrics. Both tools are excellent industry leaders, though I find that each product has strengths and weaknesses depending on the project's language. I recommend trying both and deciding for yourself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Even with the best intentions, a test suite will lose effectiveness over time due to neglect. Measuring test coverage will alert you to these situations and inform you of which tests need updates.&lt;/p&gt;

&lt;h2&gt;
  
  
  Containerized Environments
&lt;/h2&gt;

&lt;p&gt;"Works on My Machine" is a horrible state of affairs in software development and the punchline of many jokes. Running software consistently, reproducibly, and reliably in any environment is a mostly solved problem for small to mid-sized projects. Many of the issues of environment inconsistency (e.g., accidentally running the wrong version of a library) are avoidable by running applications in "containers."&lt;/p&gt;

&lt;p&gt;Below is a list of situations that containerization improves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Running a test-suite in a clean environment, free of state from previous test runs.&lt;/li&gt;
&lt;li&gt;Setting up a development environment for new team members&lt;/li&gt;
&lt;li&gt;Keeping multiple versions of the same application running in parallel (example: test, staging, and production environments).&lt;/li&gt;
&lt;li&gt;Creating temporary sandboxes, such as those required to run tests against proposed changes to a codebase.&lt;/li&gt;
&lt;li&gt;Re-creating an environment from backups after hardware failures&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In 2021, &lt;a href="https://www.docker.com/"&gt;Docker&lt;/a&gt; and &lt;a href="https://docs.docker.com/compose/"&gt;Docker Compose&lt;/a&gt; are the most used solutions. They solve the problems by hosting software in a "container" with a clean slate on every run. When the application restarts, the container is destroyed. No state is saved for the next run unless you explicitly allow it through the use of "storage volumes."&lt;/p&gt;

&lt;p&gt;Currently, I use Docker Compose to manage my containers. Although Docker-based tools still reign as the defacto industry standard for containerization, a cohort of competitors have taken root in recent years. I have not investigated these alternatives because I am still satisfied with Docker and Docker Compose. I welcome comments on this matter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; Running software in containers will prevent most (but not all) environment-specific software problems.&lt;/p&gt;

&lt;h2&gt;
  
  
  Automated Deployment System
&lt;/h2&gt;

&lt;p&gt;A simple way to reduce the severity of bugs is to deploy as often as possible. Anyone who has worked on a large-scale enterprise project with 8-month release cycles will know what I am talking about- massive releases create huge error backlogs and upset customers. The need to batch significant changes into a single release is a relic of a bygone era when software lived on CD-ROMs and floppy disks. Publishing minor incremental releases regularly should be the norm for most projects. There is rarely anything to gain by batching multiple changes into a single release.&lt;/p&gt;

&lt;p&gt;Once you have a reliable test suite that runs in a container with good version control practices, you should automate software releases as much as possible. There are exceptions to this rule, but they are just that- exceptions.&lt;/p&gt;

&lt;p&gt;In the last decade, the industry has seen the rising use of "push to deploy" offerings. The premise of such tools is that you can release your software more frequently (multiple deployments per day) by pushing changes to a version control repository managed by a specialized tool. These tools handle the most common use cases, such as pushing changes, reverting changes, restarting applications, and managing configuration. All actions are completed in a single step and with minimal developer intervention. These tools take time to learn and set up, but it truly is a better way to ship software. High adoption rates are a testament to their effectiveness.&lt;/p&gt;

&lt;p&gt;The ecosystem for push-to-deploy tools is diverse. In the past, I've automated the deployment of micro-projects with &lt;a href="https://dokku.com/"&gt;Dokku&lt;/a&gt;. For projects where reliability is a more significant concern than cost, I use &lt;a href="https://www.heroku.com/"&gt;Heroku&lt;/a&gt;. Many language and platform-specific tools are out there. Research the tools offered by your ecosystem.&lt;/p&gt;

&lt;p&gt;An alternative title for this section was "Continuous Delivery and Integration Systems." I decided against this title because those terms come with extra baggage and may distract from my main point- you need a sound system to publish new versions quickly. CI/CD practices propose many things beyond increasing deployment time. Readers who are unfamiliar with CI/CD are encouraged to research the topic.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TL;DR:&lt;/strong&gt; You should automate most aspects of your deployment process and deploy as frequently as possible to increase reliability.&lt;/p&gt;

&lt;h2&gt;
  
  
  Real-time Error Reporting
&lt;/h2&gt;

&lt;p&gt;What's valid with Pokemon is also true with production error reports: You gotta catch them all. When faced with a software defect, very few users will take the time to report it to you. When they do, they are already upset. Unreported errors aren't good for business since these bugs can translate to lower usage and overall satisfaction.&lt;/p&gt;

&lt;p&gt;Real-time error reporting tools help keep track of errors as they happen. They also give you a head start on fixing the problem. Once captured, the tool immediately reports the error to the appropriate communication channels, such as a team Slack or staff email.&lt;/p&gt;

&lt;p&gt;A good error reporting tool will capture the error and additional information, such as the user that triggered the error and any relevant stack trace(s). In my experience, error reporting tools are universally easy to install and come in a wide range of price points (with free plans available).&lt;/p&gt;

&lt;p&gt;Currently, I use &lt;a href="https://rollbar.com/"&gt;Rollbar&lt;/a&gt; for production-grade projects and &lt;a href="https://github.com/smartinez87/exception_notification"&gt;exception_notifier&lt;/a&gt; for small-scale Rails projects.&lt;/p&gt;

&lt;h2&gt;
  
  
  (Sometimes) Performance Monitoring and Profiling
&lt;/h2&gt;

&lt;p&gt;Identifying performance issues in production is hard. It is especially hard for mature, real-world applications servicing production workloads. In addition to being a complicated process, it is also essential to an application's reliability. The solution is never as simple as &lt;code&gt;npm install performance&lt;/code&gt;. Performance monitoring tools help you untangle the situation by recording statistics about your application's runtime characteristics.&lt;/p&gt;

&lt;p&gt;Typically, you install a library into your application code and deploy the app to production. Once deployed, the performance monitoring solution will store and upload runtime metrics. You can view graphs of the data in a dashboard, hopefully giving you a better picture of application hot spots. These tools are often language and platform-specific. Many Ruby on Rails performance monitoring tools can help identify numerous anti-patterns and mistakes, such as &lt;a href="https://stackoverflow.com/questions/97197/what-is-the-n1-selects-problem-in-orm-object-relational-mapping"&gt;N+1 queries&lt;/a&gt; in ActiveRecord. Although the tools do an excellent job of isolating bottlenecks, it is ultimately the developer's responsibility to devise solutions for each hot spot.&lt;/p&gt;

&lt;p&gt;I can't say I have a favorite performance monitoring tool at the moment. The landscape for performance profiling and monitoring tools appears to have two main kinds. On the one hand, you have high-quality tools that are significantly overpriced, with pricing tiers intended for large enterprises. In my experience, performance monitoring tools are one of the highest-priced services that a software startup will pay for, aside from server hosting. On the other hand, there are cheap or free tools that are only marginally useful and do not mirror their competitors' offerings. I've yet to find a performance monitoring solution that offers a good feature set and affordable pricing plans for startups and small businesses.&lt;/p&gt;

&lt;p&gt;Depending on your project's scale and maturity level, it may be possible to delay the adoption of a performance monitoring tool. In the case of specialized software used by a small userbase, commercial performance monitoring tools might offer more cost than benefit.&lt;/p&gt;

&lt;h2&gt;
  
  
  Something Else?
&lt;/h2&gt;

&lt;p&gt;The tools and practices above build a basis for most real-world applications. Did I miss anything? Feel free to post a comment if you would like to share real-world experiences about tools and practices that make your life easier as a developer.&lt;/p&gt;

&lt;p&gt;Special thanks to &lt;a href="https://devmandan.com/"&gt;Daniel Legut&lt;/a&gt; for proof-reading earlier versions of this article.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What Were Server-Side Image Maps?</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Tue, 02 Mar 2021 13:46:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/what-were-server-side-image-maps-2kke</link>
      <guid>https://dev.to/rickcarlino/what-were-server-side-image-maps-2kke</guid>
      <description>&lt;p&gt;&lt;strong&gt;Author’s note:&lt;/strong&gt; This article explores server-side image maps, a historic web technology. In 2021, the use of server-side image maps is considered a worst practice. Hopefully, no one thinks I am encouraging the use of server-side image maps. Although they provide hours of fun for weekend hobby projects, they are an accessibility nightmare. Please don’t proliferate server-side image maps in real-world projects in 2021! OK, with that out of the way, let’s get started…&lt;/p&gt;

&lt;h1&gt;
  
  
  Setting the Stage
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;I realize that this is another unplanned change that I’m making without getting a consensus or having it added to the spec or whatever.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Marc Andreeson, discussing the addition of server-side image maps to the Mosaic web browser, May 18th, 1993.&lt;/p&gt;

&lt;p&gt;I recently found myself reading over a very old HTML spec and encountered something I had almost completely forgotten about- the ISMAP attribute for IMG tags.&lt;/p&gt;

&lt;p&gt;The &lt;code&gt;ISMAP&lt;/code&gt; attribute allowed prehistoric web developers to convert images to a “server-side image map”. What follows is a brief overview of my re-discovery of this amusing attribute.&lt;/p&gt;

&lt;p&gt;In the year 1993, the web was young. There were no javascript &lt;code&gt;onClick&lt;/code&gt; events, and in fact, there was no Javascript at all. CSS would not show up for another three years. Despite a narrow feature set, web developers were building an exciting vision of what the web could become.&lt;/p&gt;

&lt;p&gt;In the case of server-side image maps, web developers of the era needed a way to create dynamic clickable graphics, and they didn’t have the luxury of Javascript or CSS. Creating an image hyperlink was already possible, but this only allowed one hyperlink destination per image. What if the image was a map of the United States, and you wanted to direct the user to one of 50 pages based on a single click of that image?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.osec.doc.gov/webresources/accessibility/RuleEF.htm"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yKDsTknk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://rickcarlino.com/images/2021/us_map.gif" alt="A screenshot of Netscape Navigator rendering a webpage that has a server-side image map of the United States"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Another use case was the creation of intricate menus for web pages. Since CSS was still in its early days, web developers that wanted a way to build flashy graphics were limited in their options. One workaround that many web designers would deploy was not using HTML for the UI’s graphical elements. Instead, they would design the layout entirely as an image and write a &lt;a href="https://rickcarlino.com/2019/07/20/what-were-cgi-scripts-html.html"&gt;server-side CGI&lt;/a&gt; script that could render a subsequent page based on the X/Y coordinates of the last point clicked on the image. This practice is now frowned upon.&lt;/p&gt;

&lt;p&gt;&lt;a href="http://kfury.com/the-first-apple-homepage"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--S0cdwEsJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/apple_homepage.png" alt="A screenshot of the Apple homepage as seen in the 90s"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Taking this example further, I decided to do some historical re-enactment. What would an interactive drawing app look like in the early 90s? I created this &lt;a href="https://image-map-canvas.herokuapp.com/"&gt;hilariously underpowered&lt;/a&gt; drawing app in one sitting last weekend to illustrate the point. The app does not use Javascript or CSS and allows multi-user interaction with a shared monochrome canvas (barely).&lt;/p&gt;

&lt;p&gt;&lt;a href="https://image-map-canvas.herokuapp.com/"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--DnphfAxd--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/monochrome_canvas_web_app.png" alt="A screenshot of a monochrome canvas app I built. I was trying to draw a bird."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Digging Deeper
&lt;/h1&gt;

&lt;p&gt;Advanced amateur Google research has led me to conclude that the &lt;code&gt;ismap&lt;/code&gt; attribute was first added to the Mosaic browser in the early 90s, circa 1993. At that time, it was added as a non-standard feature.&lt;/p&gt;

&lt;p&gt;Later, in November of 1995, the &lt;code&gt;ismap&lt;/code&gt; attribute was referenced in &lt;a href="https://tools.ietf.org/html/rfc1866"&gt;RFC 1866&lt;/a&gt;, the HTML 2.0 specification. RFC 1866 is the first official standard I can find that references server-side image maps. If anyone can find earlier documents (official or otherwise), please leave a comment on Reddit or Lobste.rs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Problems Presented by Server-Side Image Maps
&lt;/h1&gt;

&lt;p&gt;Server-side image maps disappeared from use for a variety of (good) reasons. The most notable reasons are that server-side image maps are inaccessible to users who cannot use pointing devices or view images. Developers of the era were encouraged to provide clickable hypertext links with computer-readable descriptions alongside the image, though this was rarely practiced. The result was an inaccessible website.&lt;/p&gt;

&lt;p&gt;Another argument against server-side image maps was that they are not offline-first, though I would argue that the days of being able to keep offline backups of a website are far, far behind us.&lt;/p&gt;

&lt;h1&gt;
  
  
  Later Refinements: Client-Side Image Maps
&lt;/h1&gt;

&lt;p&gt;The accessibility challenges of server-side image maps eventually led to the introduction of client-side image maps in HTML 3.2.&lt;/p&gt;

&lt;p&gt;Like their server-side counterparts, client-side image maps allowed developers to create clickable, interactive graphics on HTML documents. Unlike server-side image maps, the map information is entirely contained within the HTML document. This means that screen readers and text-based browsers can parse the data locally and provide an accessible alternative to the graphical image map. This assumes that the developer followed best practices, such as giving descriptive ALT text for each map region.&lt;/p&gt;

&lt;p&gt;Client-side image maps are nested directly within an &lt;code&gt;img&lt;/code&gt; tag using various tags that describe shapes for regions within an image. Since an image map tutorial is beyond this article’s scope, I will provide a link to an MDN tutorial &lt;a href="https://developer.mozilla.org/en-US/docs/Web/HTML/Element/map"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is a screenshot of a &lt;a href="https://accessibility.psu.edu/imagemaps/"&gt;website hosted by Penn State&lt;/a&gt; that explains the accessibility aspects of client-side image maps. I’ve provided screenshots below showing how the image map renders in a graphical browser (Dillo) and a text-based one (Lynx). Because the image map was implemented correctly, I was able to extract relevant information from the image map, even in a text-based browser.&lt;/p&gt;

&lt;p&gt;Rendering the page in Lynx, a text-based browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0EQ_Jli5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/imagemap_lynx.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0EQ_Jli5--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/imagemap_lynx.png" alt="A screenshot of a Linux terminal window running a text-based web browser. The window renders a list of links extracted from an image map."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The same web page, rendered in a graphical web browser:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zPksqtEk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/imagemap2_dillo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zPksqtEk--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/imagemap2_dillo.png" alt="A rendering of the previous web page as seen from a graphical web browser."&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Image Maps Today
&lt;/h1&gt;

&lt;p&gt;As stated previously, &lt;em&gt;server-side&lt;/em&gt; image maps are discouraged in modern websites. On the other hand, &lt;a href="https://stackoverflow.com/questions/3528746/are-image-maps-map-deprecated"&gt;client-side image maps are not a deprecated technology&lt;/a&gt;, but they are rarely seen on modern websites. I attribute this to the fact that Javascript has matured to the point that it can replace image maps with custom client-side code that is tailored specifically to the needs of the application.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Build a Raspberry Pi Linux System the Hard Way</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sat, 23 Jan 2021 20:13:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/build-a-raspbery-pi-linux-system-the-hard-way-4nko</link>
      <guid>https://dev.to/rickcarlino/build-a-raspbery-pi-linux-system-the-hard-way-4nko</guid>
      <description>&lt;p&gt;&lt;strong&gt;INTENDED AUDIENCE:&lt;/strong&gt; Raspberry Pi hobbyists. Software developers with no embedded systems experience.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;READ TIME:&lt;/strong&gt; About 10 minutes, excluding exercises.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GOAL:&lt;/strong&gt; The instructions below will explain how to build a Linux environment for a Raspberry Pi 3B from scratch, focusing on extreme minimalism. I will build most components from source code and use BusyBox as the only user application on the target. The focus is on minimalism for the sake of learning. Optimizations like network boot, secondary bootloaders, compressed filesystems, etc.. will not be covered.&lt;/p&gt;

&lt;h1&gt;
  
  
  Table of Contents
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;Hardware Requirements&lt;/li&gt;
&lt;li&gt;Partition the SD Card&lt;/li&gt;
&lt;li&gt;Download Firmware Blobs&lt;/li&gt;
&lt;li&gt;Create A Toolchain on Host Machine&lt;/li&gt;
&lt;li&gt;Build the Kernel&lt;/li&gt;
&lt;li&gt;Copy Kernel and DTBs to Root Partition&lt;/li&gt;
&lt;li&gt;Configure Kernel and Bootloader&lt;/li&gt;
&lt;li&gt;Create Local Directory for Root Filesystem&lt;/li&gt;
&lt;li&gt;Install Kernel Modules&lt;/li&gt;
&lt;li&gt;Download BusyBox&lt;/li&gt;
&lt;li&gt;Configure BusyBox&lt;/li&gt;
&lt;li&gt;Build BusyBox&lt;/li&gt;
&lt;li&gt;Root Filesystem, Part II&lt;/li&gt;
&lt;li&gt;Power On and Explore the Shell Prompt&lt;/li&gt;
&lt;li&gt;Next Steps&lt;/li&gt;
&lt;li&gt;Key Terms&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Key Terms
&lt;/h1&gt;

&lt;p&gt;&lt;strong&gt;BOOT LOADER&lt;/strong&gt; : A platform specific program that runs before the operating system is loaded. It is responsible for hardware initialization and loading of the OS kernel into memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BOOT PARTITION&lt;/strong&gt; : A disk partition that is used by the bootloader.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;BUSYBOX&lt;/strong&gt; : A single Linux application that emulates many common system utilities, such as &lt;code&gt;cp&lt;/code&gt;, &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;mv&lt;/code&gt;, etc.. Often used in embedded systems.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DEFAULT KERNEL CONFIGURATION&lt;/strong&gt; : A set of default options that are applied to the Linux kernel when it is compiled from source code by a developer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DEVICE TREE BLOBS&lt;/strong&gt; : A binary format used to describe a machine’s device layout. This information is used by the Linux kernel (and its device drivers) to support platform-specific hardware.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;DEVICE TREE OVERLAY&lt;/strong&gt; : Fragments of a device tree that modify the DEVICE TREE BLOB. They are typically used to make small changes or additions to a DEVICE TREE BLOB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;HOST MACHINE&lt;/strong&gt; : In embedded systems, the HOST MACHINE is a computer used for software development that is not the end product of the software development activity.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;KERNEL MODULES&lt;/strong&gt; : Code that can be loaded and unloaded from the kernel at runtime. They add functionality to the kernel (often for hardware management) without the need to reboot the system or modify the kernel itself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LINUX KERNEL&lt;/strong&gt; : Responsible for managing system hardware and resources as well as providing services to userspace applications. Loaded by the BOOT LOADER at system start.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;INIT&lt;/strong&gt; : The first program loaded at start time by the Linux kernel.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;LINUX KERNEL COMMAND LINE&lt;/strong&gt; : A set of options that are passed to the Linux kernel when it is loaded. It often contains information about how to load the root filesystem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;ROOT FILESYSTEM&lt;/strong&gt; : A series of directories that contain essential applications (like &lt;code&gt;init&lt;/code&gt; and a shell) as well as system configuration.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TARGET MACHINE&lt;/strong&gt; : The embedded device that is the final product of embedded systems development. See also: HOST MACHINE.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;USB TTL CABLE&lt;/strong&gt; : A cable that allows you to access the Raspberry Pi’s system shell without needing to attach a keyboard and monitor. &lt;strong&gt;It is required hardware for this tutorial.&lt;/strong&gt; They are very inexpensive.&lt;/p&gt;

&lt;h1&gt;
  
  
  Hardware Requirements
&lt;/h1&gt;

&lt;p&gt;You will need:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A micro SD Card larger than 2 Gigabytes&lt;/li&gt;
&lt;li&gt;A micro SD Card reader&lt;/li&gt;
&lt;li&gt;A Raspberry Pi 3b (The “target machine”)&lt;/li&gt;
&lt;li&gt;An x86-based Ubuntu desktop machine (the “host machine”)&lt;/li&gt;
&lt;li&gt;A &lt;a href="https://rickcarlino.com/2021/01/21/practices-that-make-raspberry-pi-work-easier-html.html"&gt;USB TTL Serial cable&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Partition the SD Card
&lt;/h1&gt;

&lt;p&gt;This section will require the creation of two partitions on a blank SD Card:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;A FAT16 boot partition of at least 32 MB&lt;/li&gt;
&lt;li&gt;An EXT4 root filesystem partition of at least 1 GB&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The boot partition will eventually contain proprietary firmware blobs, device tree blobs, the Linux kernel, and two configuration files.&lt;/p&gt;

&lt;p&gt;The root filesystem will contain kernel modules and userspace programs (such as &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cat&lt;/code&gt;, etc..).&lt;/p&gt;

&lt;p&gt;I recommend using &lt;code&gt;gparted&lt;/code&gt; for partitioning. Here’s a short screencast explaining how to perform this action in GParted:&lt;/p&gt;

&lt;h1&gt;
  
  
  Download Firmware Blobs
&lt;/h1&gt;

&lt;p&gt;Our goal is to build an entire Linux system. Before we can load the kernel, the hardware must be initialized. Hardware initialization is the responsibility of the “boot loader”- platform-specific code that runs before the Linux Kernel is loaded into memory. Every platform will handle the boot loading process differently. In the Raspberry Pi 3b, we must download three files and place them in the boot partition (FAT16) of the SD card. These files are not Open Source, so we cannot compile them ourselves.&lt;/p&gt;

&lt;p&gt;All files are available in &lt;a href="https://github.com/raspberrypi/firmware"&gt;the Raspberry Pi firmware repository&lt;/a&gt;. I will not discuss the topic of boot loaders in depth. You can read more about the boot configuration in &lt;a href="https://www.raspberrypi.org/documentation/configuration/boot_folder.md"&gt;the official documentation&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Before proceeding, add the following files to the FAT16 (boot) partition of your SD card:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://github.com/raspberrypi/firmware/blob/master/boot/bootcode.bin"&gt;bootcode.bin&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/raspberrypi/firmware/blob/master/boot/fixup.dat"&gt;fixup.dat&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://github.com/raspberrypi/firmware/blob/master/boot/start.elf"&gt;start.elf&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Create A Toolchain on Host Machine
&lt;/h1&gt;

&lt;p&gt;At this point, you should have an SD card with an EXT4 partition and a FAT16 boot partition. The boot partition should contain the three proprietary blobs listed in the previous section.&lt;/p&gt;

&lt;p&gt;With the boot loader installed, we’re ready to compile a Linux kernel from source code. Compiling a Linux kernel requires GCC, a &lt;a href="https://gcc.gnu.org/"&gt;C language compiler&lt;/a&gt;. It also requires &lt;a href="https://www.gnu.org/software/binutils/"&gt;binary utilities (“binutils”) for handling assembly language files&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Your host machine may already have GCC and Binutils installed, but there’s a problem- the compiler on the host machine emits x86 binaries. A Raspberry Pi uses an entirely different ARM instruction set. To produce a binary that the RPi can execute, we require a compiler that emits ARM instructions, not x86. We could undoubtedly install Raspberry Pi OS (&lt;a href="https://www.raspberrypi.org/software/"&gt;https://www.raspberrypi.org/software/&lt;/a&gt;) and perform kernel compilation on the target device. This would be a prolonged process, however. For comparison, I have a 10th gen Core i7 Laptop with 8 physical cores, 8 GB of RAM, and a solid-state drive. Compiling the Linux kernel took approximately 20 minutes on this machine, which is still a considerable amount of time. Compilation on a Raspberry Pi would take even longer.&lt;/p&gt;

&lt;p&gt;The better way to compile a Raspberry Pi Linux kernel is via “cross-compilation” through a “cross compiler.” A cross compiler is a compiler that runs on one instruction set but outputs source code in a completely different instruction set than the target. In our case, we need a compiler that runs on an x86 machine but which emits ARM instructions that the RPi can understand.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Installs `arm-linux-gnueabihf-*` compiler, linker, etc..
sudo apt install bc bison crossbuild-essential-armhf flex git libc6-dev libncurses5-dev libssl-dev

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After running the command above, our machine will have a new set of tools available:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What?&lt;/th&gt;
&lt;th&gt;Native tool&lt;/th&gt;
&lt;th&gt;Cross compiler equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Compiler&lt;/td&gt;
&lt;td&gt;gcc&lt;/td&gt;
&lt;td&gt;arm-Linux-gnueabihf-gcc&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linker&lt;/td&gt;
&lt;td&gt;ld&lt;/td&gt;
&lt;td&gt;arm-Linux-gnueabihf-ld&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Assembler&lt;/td&gt;
&lt;td&gt;as&lt;/td&gt;
&lt;td&gt;arm-Linux-gnueabihf-as&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Do you see the pattern? In the next step, we will set a &lt;code&gt;CROSS_COMPILE&lt;/code&gt; environment variable so that applications will compile via &lt;code&gt;arm-Linux-gnueabihf-gcc&lt;/code&gt; rather than the native &lt;code&gt;gcc&lt;/code&gt;. Typically, a cross compiler will offer all the native compiler and Binutils’ executables, such as &lt;code&gt;gcc&lt;/code&gt; and &lt;code&gt;ld&lt;/code&gt;. It will do so, however, with a prefix that denotes the target architecture. In our case, the prefix is &lt;code&gt;arm-Linux-gnueabihf-&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to build a custom toolchain, or build a toolchain from source, look at &lt;a href="https://crosstool-ng.github.io/"&gt;Crosstool-NG&lt;/a&gt;. It is a more advanced way to generate cross compilers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Build the Kernel
&lt;/h1&gt;

&lt;p&gt;Now that we have a working toolchain, we need to find the latest Linux kernel source and compile it.&lt;/p&gt;

&lt;p&gt;Before proceeding, we need to set some environment variables. You must export these variables when performing all steps.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ==== BASH USERS:

# Set the architecture to ARM:
export ARCH=arm

# We want to use ARM v7:
export KERNEL=kernel7

# Set the cross-compiler prefix (explained in previous section):
export CROSS_COMPILE=arm-linux-gnueabihf-

# ==== FISH USERS:
# set -x KERNEL kernel7
# set -x ARCH arm
# set -x CROSS_COMPILE arm-linux-gnueabihf-

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The Raspberry Pi foundation manages &lt;a href="https://github.com/raspberrypi/linux"&gt;its own version of the kernel&lt;/a&gt;. We will clone the source code using Git:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Clone Raspberry Pi Linux kernel
git clone --depth=1 https://github.com/raspberrypi/linux
cd linux

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We must then apply the default configuration for the build system based on the target device (An RPi3b, which uses the BCM2709 chipset):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Apply default config for RPi3
make bcm2709_defconfig

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Some users will want to modify the default kernel configuration. You can accomplish this via &lt;code&gt;make menuconfig&lt;/code&gt;, though it is not required in our use case.&lt;/p&gt;

&lt;p&gt;We are ready to compile the kernel, but we need to determine how many CPU cores our host machine has before we do that. We require this information to enable parallel compilation, which can decrease the compilation time substantially. Perform the following steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Determine the number of CPU cores your machine has vs. &lt;code&gt;lscpu&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Multiply the number from step 1 by 1.5.&lt;/li&gt;
&lt;li&gt;Pass this number to the &lt;code&gt;-j&lt;/code&gt; flag in the next step.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Please note that I have used &lt;code&gt;-j12&lt;/code&gt; in the example below. Your machine may require a different &lt;code&gt;-j&lt;/code&gt; value!&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Compile actual kernel, modules, DTBs
# Takes ~20 minutes on modern i7 with SSD
make -j12 zImage modules dtbs

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now is an excellent time to take a break. Kernel compilation takes a while.&lt;/p&gt;

&lt;h1&gt;
  
  
  Copy Kernel and DTBs to Root Partition
&lt;/h1&gt;

&lt;p&gt;The previous step created several required files:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;zImage&lt;/code&gt;- a compressed binary Linux kernel.&lt;/li&gt;
&lt;li&gt;Device Tree Blobs (DTBs)- metadata that Linux needs to find physical hardware&lt;/li&gt;
&lt;li&gt;Device Tree Overlays- modifications and additions to the core DTBs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We need to move these types of files to the FAT16 boot partition previously created in a specific manner.&lt;/p&gt;

&lt;p&gt;First, find the location of the boot partition (FAT16) created earlier. On my machine, the path is &lt;code&gt;/media/rick/rpi_boot&lt;/code&gt;. It will be different on your device. It will live in the same location as the &lt;code&gt;bootcode.bin&lt;/code&gt;, &lt;code&gt;fixup.dat&lt;/code&gt;, &lt;code&gt;start.elf&lt;/code&gt; files we downloaded earlier.&lt;/p&gt;

&lt;p&gt;Within your boot partition, create a new folder called &lt;code&gt;overlays/&lt;/code&gt; at the root level:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir /media/rick/rpi_boot/overlays

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, run the following within the &lt;code&gt;linux/&lt;/code&gt; source directory of the previous section:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;cp arch/arm/boot/zImage /media/rick/rpi_boot
cp arch/arm/boot/dts/bcm2710-rpi-3-b.dtb /media/rick/rpi_boot
cp arch/arm/boot/dts/overlays/disable-bt.dtbo /media/rick/rpi_boot/overlays

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configure Kernel and Bootloader
&lt;/h1&gt;

&lt;p&gt;The Raspberry Pi uses a &lt;code&gt;config.txt&lt;/code&gt; file to configure the bootloader.&lt;/p&gt;

&lt;p&gt;You can &lt;a href="https://www.raspberrypi.org/documentation/configuration/config-txt/boot.md"&gt;read more about the options here&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Create a config.txt file in the boot (FAT16) partition as follows:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Use the Linux Kernel we compiled earlier.
kernel=zImage

# Enable UART so we can use a TTL cable.
enable_uart=1

# Use the appropriate DTB for our device.
device_tree=bcm2710-rpi-3-b.dtb

# Disable Bluetooth via device tree overlay.
# It's a complicated explanation that you
# can read about here: https://youtu.be/68jbiuf27AY?t=431
# IF YOU SKIP THIS STEP, your serial connection will not
# work correctly.
dtoverlay=disable-bt

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Next, we need to edit &lt;a href="https://www.kernel.org/doc/html/v4.14/admin-guide/kernel-parameters.html"&gt;the Linux command line&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;The Raspberry Pi will grab the kernel command line from cmdline.txt. Like config.txt, it lives in the boot partition (FAT16):&lt;/p&gt;

&lt;p&gt;Create a &lt;code&gt;cmdline.txt&lt;/code&gt; file as follows and save it to the boot partition:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console=tty1 console=serial0,115200 root=/dev/mmcblk0p2 rootfstype=ext4 rootwait

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Create Local Directory for Root Filesystem
&lt;/h1&gt;

&lt;p&gt;Now that the Linux kernel is built and the boot loader is configured, we need to shift our focus to building the root filesystem. The root filesystem is where Linux expects to find executables, kernel modules, system files, and many others. The layout is specified by &lt;a href="https://en.wikipedia.org/wiki/Filesystem_Hierarchy_Standard"&gt;the Linux Filesystem Hierarchy Standard&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We will create a root filesystem in a directory on our host machine. Later, we will copy the final directory structure to the EXT4 partition we made at the beginning of the tutorial.&lt;/p&gt;

&lt;p&gt;I will name this directory &lt;code&gt;root_fs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;mkdir -p root_fs

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use &lt;code&gt;pwd&lt;/code&gt; to determine the absolute path to this directory. Keep this information handy; we will need it in several steps.&lt;/p&gt;

&lt;h1&gt;
  
  
  Install Kernel Modules
&lt;/h1&gt;

&lt;p&gt;The first thing we will put onto the root filesystem is kernel modules, which were compiled alongside the Linux kernel in a previous step.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;cd&lt;/code&gt; back into the directory where the &lt;code&gt;Linux&lt;/code&gt; source code was, but keep the absolute path to your &lt;code&gt;root_fs&lt;/code&gt; directory handy.&lt;/p&gt;

&lt;p&gt;We need to set the INSTALL_MOD_PATH environment variable to the absolute path of the &lt;code&gt;root_fs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;export INSTALL_MOD_PATH=/home/rick/linux_root
# Fish shell users:
# set -x INSTALL_MOD_PATH /home/rick/linux_root

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After that, &lt;code&gt;cd&lt;/code&gt; into the Linux source dir and run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# May require `sudo`:
make modules_install

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;After this step, you will find a multitude of &lt;code&gt;*.ko&lt;/code&gt; files installed in your &lt;code&gt;root_fs/&lt;/code&gt; directory.&lt;/p&gt;

&lt;h1&gt;
  
  
  Download BusyBox
&lt;/h1&gt;

&lt;p&gt;The modules are now installed in the root filesystem. Modules are not enough to run a Linux system, however. We need all of the usual tools found on a Linux system, like &lt;code&gt;ls&lt;/code&gt;, &lt;code&gt;cd&lt;/code&gt;, &lt;code&gt;cp&lt;/code&gt; and friends.&lt;/p&gt;

&lt;p&gt;Rather than compile each tool individually, we will statically cross-compile &lt;a href="https://BusyBox.net/"&gt;BusyBox&lt;/a&gt;. BusyBox touts itself as “The Swiss Army Knife of Embedded Linux”. It is a single executable that serves multiple functions, depending on how the executable is loaded. For instance, we can create a symbolic link from BusyBox to &lt;code&gt;/bin/echo&lt;/code&gt;. When we execute &lt;code&gt;/bin/echo&lt;/code&gt;, BusyBox will note the symbolic link name and run as expected for the &lt;code&gt;echo&lt;/code&gt; command. BusyBox implements all of the essential Linux command-line utilities like &lt;code&gt;cd&lt;/code&gt; and &lt;code&gt;ls&lt;/code&gt;. It also comes with added extras like a lightweight HTTP server and text editor.&lt;/p&gt;

&lt;p&gt;Let’s clone a local copy of BusyBox and checkout version 1.33.0:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;git clone git://busybox.net/busybox.git --branch=1_33_0 --depth=1
cd BusyBox

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h1&gt;
  
  
  Configure BusyBox
&lt;/h1&gt;

&lt;p&gt;Once we have the source on our host machine, we need to tweak some settings from within &lt;code&gt;menuconfig&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;make menuconfig

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Set the following options:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting Location&lt;/th&gt;
&lt;th&gt;Setting Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Settings -&amp;gt; Build static binary (no shared libraries)&lt;/td&gt;
&lt;td&gt;Enable&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settings -&amp;gt; Cross compiler prefix&lt;/td&gt;
&lt;td&gt;&lt;code&gt;arm-Linux-gnueabihf-&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Settings -&amp;gt; Destination path for ‘make install’&lt;/td&gt;
&lt;td&gt;Same as &lt;code&gt;INSTALL_MOD_PATH&lt;/code&gt; from kernel modules step&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h1&gt;
  
  
  Build BusyBox
&lt;/h1&gt;

&lt;p&gt;We’re ready to compile BusyBox.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Your -j value will be different.
# Typically, I use 1.5x the number of physical CPU cores.
make -j12
make install

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;BusyBox is now installed in &lt;code&gt;../root_fs&lt;/code&gt;. You should see many symbolic links within the &lt;code&gt;bin/&lt;/code&gt;, &lt;code&gt;sbin/&lt;/code&gt;, and &lt;code&gt;usr/&lt;/code&gt; directory of your root filesystem directory (&lt;code&gt;$INSTALL_MOD_PATH&lt;/code&gt;).&lt;/p&gt;

&lt;h1&gt;
  
  
  Root Filesystem, Part II
&lt;/h1&gt;

&lt;p&gt;BusyBox is not quite enough to boot a Linux system. We still need to add:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A place to mount &lt;a href="https://en.wikipedia.org/wiki/Procfs"&gt;procfs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A place to mount &lt;a href="https://en.wikipedia.org/wiki/Sysfs"&gt;sysfc&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;A place to mount &lt;a href="https://en.wikipedia.org/wiki/Device_file#DEVFS"&gt;devfs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tldp.org/LDP/sag/html/etc-fs.html"&gt;The &lt;code&gt;/etc&lt;/code&gt; directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.ghacks.net/2009/04/04/get-to-know-linux-the-etcinitd-directory/"&gt;The &lt;code&gt;/etc/init.d&lt;/code&gt; configuration directory&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;The &lt;a href="https://unix.stackexchange.com/questions/56075/why-is-rcs-required-after-file-system-is-mounted-by-the-kernel"&gt;&lt;code&gt;/etc/init.d/rcS&lt;/code&gt; file&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Run the following commands within &lt;code&gt;/root_fs&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Create directories to mount stuff:
mkdir proc
mkdir sys
mkdir dev
mkdir etc

# Create config directory:
mkdir etc/init.d

# Create an empty `rcS` file.
touch etc/init.d/rcS

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Make &lt;code&gt;rcS&lt;/code&gt; executable (Linux will execute this script at boot time):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;chmod +x etc/init.d/rcS

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Add the following entries to &lt;code&gt;etc/init.d/rcS&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/bin/sh
mount -t proc none /proc
mount -t sysfs none /sys

echo /sbin/mdev &amp;gt; /proc/sys/kernel/hotplug
mdev -s

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The entries above will mount sysfs and procfs at boot time.&lt;/p&gt;

&lt;h1&gt;
  
  
  Power On and Explore the Shell Prompt
&lt;/h1&gt;

&lt;p&gt;We’re ready to boot the system.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do not use a monitor- a USB TTL cable is required!&lt;/strong&gt; If you do not own such a cable, you can buy one for a few dollars on Amazon. It will change your life as a Raspberry Pi enthusiast, trust me.&lt;/p&gt;

&lt;p&gt;Once you power on, you should see some kernel messages scroll by and, eventually, a shell prompt.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# ... Shortened for clarity ...
[4.536592] usb 1-1.1: new high-speed USB device number 3 using dwc_otg
[4.666906] usb 1-1.1: New USB device found, idVendor=0424, idProduct=ec00, bcdDevice= 2.00
[4.680733] usb 1-1.1: New USB device strings: Mfr=0, Product=0, SerialNumber=0
[4.693829] smsc95xx v1.0.6
[4.791032] smsc95xx 1-1.1:1.0 eth0: register 'smsc95xx' at usb-3f980000.usb-1.1, smsc95xx USB 2.0 Ethernet, b8:27:eb:54:61:ef

Please press Enter to activate this console.

/ # echo "Hello, Linux world."
Hello, Linux world.

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;We now have a working Linux root partition and boot partition. Copy the &lt;code&gt;root_fs/&lt;/code&gt; directory to the SD card and attempt to boot the device.&lt;/p&gt;

&lt;h1&gt;
  
  
  Next Steps
&lt;/h1&gt;

&lt;p&gt;The Linux system presented in this article is not very useful, but hopefully, it gives you a better picture of how Linux distributions and embedded Linux systems are built. Feel free to reach out to me on Reddit or Lobste.rs with feedback.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Practices that Make Raspberry Pi Work Easier</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Thu, 21 Jan 2021 23:34:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/practices-that-make-raspberry-pi-work-easier-59e4</link>
      <guid>https://dev.to/rickcarlino/practices-that-make-raspberry-pi-work-easier-59e4</guid>
      <description>&lt;p&gt;I work on Raspberry Pi hardware daily as part of my job and for fun at my local makerspace. Below I’ve outlined some practices that have streamlined my Raspberry Pi workflow both at work and on hobby projects.&lt;/p&gt;

&lt;h1&gt;
  
  
  1. Use a Serial TTL Cable When Possible
&lt;/h1&gt;

&lt;p&gt;A traditional setup in new RPi projects is to attach a monitor, keyboard, mouse, and associated cables to configure the device and application. This is an adequate starting point for novices but can be a hassle for medium and large scale projects. It can also add a considerable amount of setup and teardown time to a weekend project, particularly in a shared environment like an office or makerspace.&lt;/p&gt;

&lt;p&gt;There’s a much better way to go about this, assuming you have already learned RPi and Linux basics. Instead of attaching your Pi project to a keyboard and monitor, you can use a compact serial TTL cable directly attached to your main laptop. You can then access the Linux shell prompt as a serial USB device.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---wOOcFer--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/usb_ttl_cable.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---wOOcFer--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/usb_ttl_cable.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once the cable is connected, you can operate from the device’s command line as usual. With a serial TTL cable, it’s simple to perform tasks such as viewing logs and updating code, all without the need for a monitor and with a setup that can fit into your bag.&lt;/p&gt;

&lt;p&gt;Although some developers prefer the convenience of SSH-over-WiFi, I still prefer a USB cable. It allows me to investigate problems before WiFi connectivity is available (for example, kernel panics). It also allows me to work on the device outside of the WiFi router’s range.&lt;/p&gt;

&lt;p&gt;Using a serial TTL cable instead of a graphical monitor is the single best workflow improvement you can make. Still, it might not seem so obvious on the surface. Every graphical tool on a Raspberry Pi has a command-line based alternative. It will take time to learn, but much less time in the long run than lugging around a monitor. You will also find that command-line tools are much more convenient after the initial learning investment has been made.&lt;/p&gt;

&lt;p&gt;Adafruit has written an in-depth tutorial &lt;a href="https://learn.adafruit.com/adafruits-raspberry-pi-lesson-5-using-a-console-cable"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  2. Replace &lt;code&gt;screen&lt;/code&gt; with &lt;code&gt;tio&lt;/code&gt;
&lt;/h1&gt;

&lt;p&gt;When accessing a Pi via USB, the common practice in Linux is to use &lt;code&gt;screen&lt;/code&gt; or &lt;code&gt;minicom&lt;/code&gt; on the host machine. Many of these options offer an OK experience. Nevertheless, I’ve found that the interfaces are not always obvious, and often the tools show their age.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IOuMAA8I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://rickcarlino.com/images/2021/tio.gif" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IOuMAA8I--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://rickcarlino.com/images/2021/tio.gif" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Recently I discovered &lt;a href="https://github.com/tio/tio"&gt;Tio&lt;/a&gt;, a modern alternative to Screen. It is &lt;em&gt;much&lt;/em&gt; easier to use than any other command-line terminal application while still having a handy command set.&lt;/p&gt;

&lt;p&gt;By default, Tio will auto-reconnect to a USB device, even if the device is unavailable. This is great if you move your project around a lot and need to constantly reconnect to the board. As soon as you re-attach the RPi, Tio will start printing logs to the screen by default.&lt;/p&gt;

&lt;p&gt;Tio is also very easy to learn, as all commands are viewable via &lt;code&gt;ctrl + t, ?&lt;/code&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  3. Use &lt;code&gt;micro&lt;/code&gt; Text Editor
&lt;/h1&gt;

&lt;p&gt;When editing text files from the command line, &lt;code&gt;vi&lt;/code&gt; offers a powerful interface for advanced users. Personally, I’d rather just use an editor that offers inferrable shortcuts. The common suggestion in these cases is to use Nano, and indeed, Nano is easy to learn and easy to install. However, there is a newer project available that reflects more modern usage.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--EloMF0kw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/micro.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--EloMF0kw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/micro.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://micro-editor.github.io/"&gt;Micro&lt;/a&gt; is a text editor built in the last 5 years. It is actively maintained and has a very ergonomic set of default keybindings. Configuration files are stored in plain JSON, though it requires almost no customization and works exceptionally well out of the box. The default key bindings will make sense to anyone that has used a computer in the last decade. You copy test with ctrl+c, move the cursor via arrow keys, and highlight text using the shift key. If you are working in a graphical environment, mouse support works out of the box.&lt;/p&gt;

&lt;p&gt;For these reasons, Micro is now my go-to text editor for command line work.&lt;/p&gt;

&lt;h1&gt;
  
  
  4. Use an HDMI Capture Device Instead of a Monitor
&lt;/h1&gt;

&lt;p&gt;If you’re building a project that requires a graphical display by design, such as a kiosk or media player, a USB TTL serial cable might not be an appropriate solution. That’s not to say you are required to park another computer monitor at your desk. In these situations, it is still possible to avoid hooking a second monitor up through an HDMI capture device. An HDMI capture device is an adapter that takes any HDMI source and turns it into a USB webcam on the PC side.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--RKv64CEe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/hdmi_capture.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--RKv64CEe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/hdmi_capture.png" alt="A USB HDMI capture device attached to a Raspberry Pi 3"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Once your HDMI capture device is attached, you can then view the stream as any other USB webcam. On Linux, I use &lt;a href="https://en.wikipedia.org/wiki/Cheese_(software)"&gt;Cheese&lt;/a&gt; for viewing the display. One additional advantage to this approach is that you can very easily take screenshots of your work.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hhUxh63O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/rpi_boot.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hhUxh63O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/rpi_boot.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Although some professional units used for video editing are expensive, most can be purchased cheaply, especially since the video quality is not a huge concern when debugging. At the time of writing, I was able to find several options on Amazon for under USD 20.&lt;/p&gt;

&lt;h1&gt;
  
  
  5. Use Ethernet-enabled USB Hubs
&lt;/h1&gt;

&lt;p&gt;Modern laptops with integrated Ethernet become harder to find every year. The integrated Ethernet port may have finally gone the way of the floppy drive.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IB-2Q21O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/usb_ethernet.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IB-2Q21O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2021/usb_ethernet.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The Raspberry Pi 0 does not have integrated Ethernet, either. In addition to the missing Ethernet port, the Raspberry Pi 0 only has one USB port available. The simple solution to this problem is to purchase a USB hub and attach a USB Ethernet adapter to an available slot.&lt;/p&gt;

&lt;p&gt;I’ve recently seen more USB hubs on sites like Amazon that contain an integrated Ethernet port. This is great because it frees up a USB slot and gives you Ethernet access for free. They are also extremely inexpensive, so I like to keep a few in my toolbox.&lt;/p&gt;

&lt;h1&gt;
  
  
  6. Something Else?
&lt;/h1&gt;

&lt;p&gt;Did I forget something? If you have a trick that has made life easier when developing on the Raspberry Pi, feel free to &lt;a href="https://www.reddit.com/user/rickcarlino"&gt;send me a message on Reddit&lt;/a&gt;- I will keep this list as up-to-date as possible.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Video Resources for Embedded Linux Learners</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sat, 12 Dec 2020 17:58:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/video-resources-for-embedded-linux-learners-565m</link>
      <guid>https://dev.to/rickcarlino/video-resources-for-embedded-linux-learners-565m</guid>
      <description>&lt;h1&gt;
  
  
  Core Concepts and Utilities
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=yIU92YySlW0&amp;amp;t=81s"&gt;&lt;code&gt;comm&lt;/code&gt;, &lt;code&gt;diff&lt;/code&gt;, and &lt;code&gt;patch&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=0XdjODvsRN8"&gt;Linux Sysadmin Basics – 6.3 The /proc Filesystem&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=A8ITr5ZpzvA"&gt;Mounting / loop devices&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=zxxt1UxNMBo"&gt;Mounting and unmounting filesystems&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=HbgzrKJvDRw"&gt;Root filesystem / Filesystem Hierarhy Standard (FHS)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://youtu.be/tOj8MSEIbfA?t=383"&gt;TFTP&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=oAREsnGT0rs"&gt;U-Boot from Scratch v2019.01 edition&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Hardware
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=sk8NvCF0WQg"&gt;Board support package&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=m_NyYEBxfn8"&gt;(long but high quality) Device Trees for Dummies&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5E0sdYkvq-Q"&gt;Porting U-Boot and Linux on New ARM Boards: A Step-by-Step Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=ejYImUgMXTI"&gt;Error Correction Code Implementations in Memory Controller Designs&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Filesystems, Data Storage
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=_h30HBYxtws"&gt;Explaining File Systems: NTFS, exFAT, FAT32, ext4 &amp;amp; More&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=6pp_krChw_A"&gt;How Do RAM Drives Work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=r2KaVfSH884"&gt;How does Flash Memory work?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=JTQaKDFIKL4"&gt;Introduction to MTD memory in Linux (flash)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=boxF9t29xZQ"&gt;Linux Kernel and Initrd Basics Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=DflWASw7JMU"&gt;mount, umount, fdisk, mkfs, Linux Commands mount, umount, fdisk &amp;amp; mkfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=-1fvUpFAbNM"&gt;RAMFS vs TMPFS&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=waU7U_7-mpk"&gt;What is DRAM? How is it Different From SRAM?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Rt6U2gG0ggw"&gt;Linux: and the SQUASHFS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  C, C++, Compilers, Development tools
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Pbt330zuNPc"&gt;Anatomy of Cross-Compilation Toolchains&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=_XXqrvEgb-0"&gt;Building Tool chain with Crosstool-NG&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=GV10eIuPs9k"&gt;Debugging with Core Dumps&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=2AmP7Pse4U0"&gt;Spying on Running Programs (strace, ltrace, system calls vs function calls)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=bWMIpHVRFUo"&gt;How to Inspect Compiled Binaries (binutils, objdump)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Sddn1UjzSAo"&gt;Finding memory errors with Valgrind&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=OYqX19lPb0A"&gt;POSIX message queues in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=g7Woz3YVgvQ"&gt;NCurses tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=3XO0d9Qyc34"&gt;How to use autotools (automake, autoconf, aclocal, autoheader)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=kONFFecp3R8"&gt;Cross Debugging with GDB: Embedded Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=O_Y-eQJGg9g"&gt;Use readelf to View Program Headers&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=OvAoag2MODo"&gt;C Programming in Linux Tutorial #071 - fsync() Function&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=CWihl19mJig"&gt;Build a Linux loadable kernel module that Rickrolls people&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=gLcO-tgi-mU"&gt;C Programming in Linux Tutorial #041 - Static Shared Libraries&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Booting, Boot loaders, Kernels
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=zIYkol851dU"&gt;BIOS and UEFI As Fast As Possible&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=sH5xt4qbJbk"&gt;Buildroot: building embedded Linux systems made easy!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=TxZ2jrO3GUo"&gt;Linux boot process / GRUB&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=KQjRnuwb7is"&gt;Linux initramfs for fun, and, uh…&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=fF0sRUW83vQ"&gt;Understanding the Initramfs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=yX6caxDOPu0"&gt;What is ACPI?&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=tDREcY5EzTQ"&gt;GRUB tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=bgydvZnEk5o"&gt;Syslinux bootloader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=WvmxRl0qCCc"&gt;modprobe, lsmod, rmmod, insmod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=rVaiLgXccSE"&gt;Introduction to U-Boot&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=nlKcXPUJGwA"&gt;CMake Tutorial EP 1 | Understanding The Basics&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  Init Systems
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=LTFLEXYY6jY"&gt;Init, Systemd, and Upstart&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5SoCOnU3J34"&gt;Linux Networking using NFS&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  System Administration, Services, Tools
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=6Z1FLdhPxRQ"&gt;Chrony Time Server Configuration and Understanding&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=qE77MbDnljA"&gt;RSync&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=qRY1Xu_s5VA"&gt;Udev in Linux&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=1AoKTorlEDc"&gt;Linux uname command summary with examples&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=QvvyroqxVi4"&gt;Basics of Busybox and how to run a Busybox HTTPD web server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=qtmod80oMxk"&gt;Using dmesg to read the kernel ring buffer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=5Tke_JD7-jk"&gt;ifconfig command&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=pjRA_06hBm8"&gt;Understanding sysfs, udev, dbus&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=mc9ujhrLs6A"&gt;OS hacking: mknod() syscall and /bin/mknod&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=MQr0uHX0MDA"&gt;How to Install and Configure Dropbear for Linux!&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=xH_y05pIDTo"&gt;Controlling USB devices with Python and libusb @siliconlabs&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=rNWhXBSncsI"&gt;creating archives with CPIO&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.youtube.com/watch?v=Q-ooZmO256A"&gt;uClibc Today: Still Makes Sense&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>RetroTS- Porting the RetroForth VM to Typescript</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sun, 11 Oct 2020 22:53:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/retrots-porting-the-retroforth-vm-to-typescript-508p</link>
      <guid>https://dev.to/rickcarlino/retrots-porting-the-retroforth-vm-to-typescript-508p</guid>
      <description>&lt;p&gt;This weekend I ported the &lt;a href="https://git.sr.ht/~crc_/retroforth/tree/master/vm/nga-js"&gt;Javascript version of RetroForth&lt;/a&gt; to Typescript, while also adding support for ES modules. The source code is available &lt;a href="https://github.com/RickCarlino/retro-ts"&gt;here&lt;/a&gt;. A live demo can be seen &lt;a href="http://rickcarlino.com/retrojs/"&gt;here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If time allows, I will update the editor to use &lt;a href="https://microsoft.github.io/monaco-editor/"&gt;Monaco&lt;/a&gt; and add more HTML5 canvas support.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Keeping an Offline Copy of StackOverflow with Kiwix</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sun, 09 Aug 2020 20:03:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/keeping-an-offline-copy-of-stackoverflow-with-kiwix-4cio</link>
      <guid>https://dev.to/rickcarlino/keeping-an-offline-copy-of-stackoverflow-with-kiwix-4cio</guid>
      <description>&lt;p&gt;For developers working in an offline environment such as public transit or rural dead zones, looking up information on sites like Wikipedia or StackOverflow might seem impossible.&lt;/p&gt;

&lt;p&gt;Lately, I’ve been using &lt;a href="https://www.kiwix.org/"&gt;Kiwix&lt;/a&gt; to keep offline copies of popular sites like Wikipedia and StackOverflow, aided by the availability of cheap USB mass storage devices. Kiwix is an offline web browser that uses a &lt;a href="https://en.wikipedia.org/wiki/ZIM_(file_format)"&gt;specialized archive file format&lt;/a&gt; to store copies of reference material. It was built to view Wikipedia articles but later expanded for other data sources like StackOverflow and Open Street Map.&lt;/p&gt;

&lt;p&gt;Keeping an offline copy is simple:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;a href="https://www.kiwix.org/en/downloads/kiwix-reader/"&gt;Download Kiwix Reader&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Find &lt;a href="https://wiki.kiwix.org/wiki/Content_in_all_languages"&gt;relevant ZIM packages&lt;/a&gt;, downloading them via BitTorrent. The files are large, often several hundred GB in size. A new USB drive may be helpful.&lt;/li&gt;
&lt;li&gt;Open the files using Kiwix.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The experience is like the web version but with a blazing fast load time and the ability to look things up when the internet cuts out.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TAPeNKkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2020/kiwix_wikipedia.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TAPeNKkn--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2020/kiwix_wikipedia.png" alt="Viewing Wiki articles on Kiwix"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Py-4-RKG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2020/kiwix_stackoverflow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Py-4-RKG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2020/kiwix_stackoverflow.png" alt="Viewing StackOverflow articles on Kiwix"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Software Tools for Hobby-Scale Projects</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sat, 02 Nov 2019 22:01:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/software-tools-for-hobby-scale-projects-3la2</link>
      <guid>https://dev.to/rickcarlino/software-tools-for-hobby-scale-projects-3la2</guid>
      <description>&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;You can do three things with a computer. You can try to make money, and that is unlikely. You can try to become famous, and that never happens. And you can have fun, and that always works.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;– Chuck Moore, creator of the Forth programming language&lt;/p&gt;

&lt;p&gt;In a low-stress hobby setting, computers offer a vehicle for personal enrichment rather than strictly a tool for business or research. Some noteworthy Open Source projects started as hobby projects, the most notable example being the original Linux Kernel written by Linus Torvalds. Many other well-known programmers have learned their skills as hobbyists pursuing an intellectual curiosity rather than explicitly seeking a career or a serious objective. A well-publicized example is the often quoted newsgroup post written by Linux Torvalds in the early 90s:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;em&gt;I’m doing a free operating system, just a hobby, won’t be big and professional like gnu for 386(486) AT clones.&lt;/em&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;You can find examples of hobby software on sites like &lt;a href="https://hackaday.com/"&gt;Hackaday&lt;/a&gt; or at your local &lt;a href="https://en.wikipedia.org/wiki/Hackerspace"&gt;Hackerspace&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Below is a list of useful tools I’ve come in contact with over the years. I share them with the hope that they bring you enjoyment in your next hobby project. If you would like anything added to this list or would like to share something you’ve built using the tools below, please contact me on &lt;a href="https://lobste.rs/u/rickcarlino"&gt;Lobste.rs&lt;/a&gt; or &lt;a href="https://www.reddit.com/user/rickcarlino"&gt;Reddit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used the following criteria to select the tools:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;They cost less than a coffee or are free.&lt;/li&gt;
&lt;li&gt;They are quickly learned.&lt;/li&gt;
&lt;li&gt;They allow you to accomplish a single task in a short amount of time (such as a Sunday afternoon)&lt;/li&gt;
&lt;li&gt;They are less focused on the needs of long-term projects (scalability, speed, etc.) and more focused on ease of use and prototyping speed.&lt;/li&gt;
&lt;/ul&gt;

&lt;h1&gt;
  
  
  MyJSON.com - Free Cloud Storage for JSON
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--zlT7Bf-X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/hobby_tools/my_json.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--zlT7Bf-X--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/hobby_tools/my_json.png" alt="A screenshot of myjson.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Static sites are easy and fun to build, but they can’t easily share persistent data between clients. Usually, this requires you to write a backend API or pay for a service like &lt;a href="https://firebase.google.com/"&gt;Firebase&lt;/a&gt;. That’s a lot of work, though, and the point of a hobby project is to have fun.&lt;/p&gt;

&lt;p&gt;When I need to store very small amounts of unstructured JSON for a toy app, I use the MyJSON API. You can download and edit JSON documents via their &lt;a href="http://myjson.com/api"&gt;CORS enabled REST API&lt;/a&gt; so that you don’t need to be bothered with provisioning a backend or paying hosting fees.&lt;/p&gt;

&lt;p&gt;The owner of MyJSON seems to be a hobbyist as well. If you find value in MyJSON, consider &lt;a href="https://twitter.com/lance_ramoth"&gt;thanking them on Twitter for their generosity&lt;/a&gt;.&lt;/p&gt;

&lt;h1&gt;
  
  
  REFL.ME - Simple Mobile Alerts
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--HdvbuYka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/hobby_tools/reflme.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--HdvbuYka--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/hobby_tools/reflme.png" alt="REFL.ME Screenshot, as seen on Official Website"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;REFL.ME is an Android app that performs HTTP polling on a JSON URL and sends push notifications to your phone when the data changes. When paired with a &lt;a href="https://en.wikipedia.org/wiki/Cron"&gt;Cron job&lt;/a&gt; and a JSON URL (see MyJSON section above), it offers a great way of creating mobile alerts without the hassle of authoring a full-blown Android app.&lt;/p&gt;

&lt;h1&gt;
  
  
  Vultr - Dirt Cheap VPS Hosting
&lt;/h1&gt;

&lt;p&gt;Since hobby projects rarely see high-volumes of traffic, the main concern is often cost rather than performance.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://www.vultr.com/products/cloud-compute/#pricing"&gt;Vultr&lt;/a&gt; is my go-to solution for cheap hosting. As of this writing, the cheapest plan they offer is $2.50 a month. Although their cheapest plan definitely won’t be able to fuel your next high-powered computing project, it is a great solution when you need to host small-scale tasks such as Cron jobs.&lt;/p&gt;

&lt;h1&gt;
  
  
  Dokku - A Self-hosted PaaS
&lt;/h1&gt;

&lt;p&gt;Dokku offers many of the features seen in “Platform-as-a-Service” offerings such as Heroku. Unlike many PaaS offerings, you can host it on a cheap VPS service (like Vultr).&lt;/p&gt;

&lt;p&gt;Although it is well suited for hobby projects, it’s important to note that &lt;strong&gt;Dokku also works wonderfully in production settings&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;With Dokku, you can self host a push-to-deploy mechanism for your hobby project and not waste time with server configs. There are lots of community plugins that handle the most common use-cases.&lt;/p&gt;

&lt;h1&gt;
  
  
  Free MQTT servers
&lt;/h1&gt;

&lt;p&gt;MQTT is a simple, easy-to-learn protocol for real-time communication. It’s most commonly seen in “Internet of Things” projects (Arduino, Raspberry Pi) but can also be used in web projects via WebSocket tunneling.&lt;/p&gt;

&lt;p&gt;Numerous freely available servers are listed on &lt;a href="https://github.com/mqtt/mqtt.github.io/wiki/public_brokers"&gt;MQTT Github Wiki&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;These servers are great for simple hobby apps that run on low-end devices like Arduinos, RaspberryPi, or the ESP16 WiFi device. Some servers offer WebSocket support, which allows a browser to talk directly to the device without the need for a backend.&lt;/p&gt;

&lt;h1&gt;
  
  
  NGrok - Free Firewall Tunnel
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PTfRQPRT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/hobby_tools/ngrok.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PTfRQPRT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/hobby_tools/ngrok.png" alt="A screenshot of myjson.com"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;If you are hosting a server on a home network with a dynamic IP address, it can be hard or impossible to accept incoming web requests. &lt;a href="https://ngrok.com/"&gt;NGrok&lt;/a&gt; provides local workstations with a &lt;code&gt;*.ngrok.io&lt;/code&gt; web address for exposing local servers to the Internet. It also provides HTTPS/TLS support, which is pretty cool!&lt;/p&gt;

&lt;p&gt;Ngrok is especially useful when you want to experiment with third-party APIs that use WebHooks.&lt;/p&gt;

&lt;h1&gt;
  
  
  Bookmarklets
&lt;/h1&gt;

&lt;p&gt;A &lt;a href="https://en.wikipedia.org/wiki/Bookmarklet"&gt;Bookmarklet&lt;/a&gt; is a specially formatted bookmark toolbar entry that allows your browser to execute arbitrary code on any webpage. Bookmarklets have unfortunately gone unnoticed in recent years. They are a great alternative to browser extensions when you need to perform simple personal tasks such as scraping a webpage. There are some great &lt;a href="https://code.tutsplus.com/tutorials/create-bookmarklets-the-right-way--net-18154"&gt;tutorials&lt;/a&gt; and &lt;a href="https://www.hongkiat.com/blog/100-useful-bookmarklets-for-better-productivity-ultimate-list/"&gt;examples&lt;/a&gt; out there.&lt;/p&gt;

&lt;h1&gt;
  
  
  Cron jobs
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://en.wikipedia.org/wiki/Cron"&gt;Cron jobs&lt;/a&gt; are a classic Unix automation tool and a powerful helper for many hobby projects. Although many in the Linux community are well aware of Cron, they deserve mention as a tool in any hobbyist’s toolkit.&lt;/p&gt;

&lt;p&gt;Cron jobs allow a Unix-like operating system to execute a script on a repeating timer. Cron jobs are useful for personal tools such as weather and stock market monitoring scripts.&lt;/p&gt;

&lt;h1&gt;
  
  
  CGI-scripting
&lt;/h1&gt;

&lt;p&gt;I’ve blogged about &lt;a href="https://rickcarlino.com/2019/07/20/what-were-cgi-scripts-html.html"&gt;the History of CGI Scripts&lt;/a&gt; in the past. Although it is almost unheard of to see new production systems deployed with CGI scripts in a professional setting, CGI scripts can provide a hobbyist with a cheap and simple solution for dynamic backend scripting. Many shared hosting providers (such as &lt;a href="https://my.hawkhost.com/aff.php?aff=5542"&gt;the one I host this blog on&lt;/a&gt;) provide CGI-script support at no additional cost.&lt;/p&gt;

&lt;h1&gt;
  
  
  (New) PatchBay.Pub - No-Signup Pub/Sub over HTTP
&lt;/h1&gt;

&lt;p&gt;I have yet to try &lt;a href="https://patchbay.pub/"&gt;PatchBay&lt;/a&gt;, though I thought it deserved an honorable mention.&lt;/p&gt;

&lt;p&gt;From PatchBay.Pub:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;patchbay.pub is a free web service you can use to implement things like static site hosting, file sharing, cross-platform notifications, webhooks handling, smart home event routing, IoT reporting, job queues, chat systems, bots, etc, all completely serverless and requiring no account creation or authentication. Most implementations need nothing but CURL and simple bash snippets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;PatchBay appears to offer a solution similar to MQTT publish/subscribe topics, but entirely over HTTP. It allows developers the ability to create MQTT-like streaming applications using simple tools like CURL.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://patchbay.pub/"&gt;Check out the PatchBay website for more information&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  (New) EasyDB.io - DB hosting, no registration
&lt;/h1&gt;

&lt;p&gt;EasyDB was recently featured on Lobste.rs. Like PatchBay, it looks like a great tool for hobby projects. I have not yet tried it for myself.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EasyDB is a one-click, hosted database provider. We give you a database for the programming language of your choice, you build something cool. It’s that simple.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;It’s worth noting that it is an “ephemeral” database provider:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;EasyDB is an ephemeral database provider. That means that after some time, your database will be removed. By default, databases will stick around for 24 hours. If you make an account with us, the database will last for 72 hours. If you really want to keep it longer, you can upgrade your database to a persistent database for $5/month.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Check the &lt;a href="https://easydb.io/"&gt;EasyDB website&lt;/a&gt; for more information.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>What were CGI scripts?</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sat, 20 Jul 2019 18:07:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/what-were-cgi-scripts-2l0</link>
      <guid>https://dev.to/rickcarlino/what-were-cgi-scripts-2l0</guid>
      <description>&lt;h1&gt;
  
  
  A Hypothetical Scenario
&lt;/h1&gt;

&lt;p&gt;It’s 1996. Ruby on Rails does not come out for another 10 years. Javascript is barely an idea yet and not all browsers support it.&lt;/p&gt;

&lt;p&gt;You run a personal website from the &lt;code&gt;public_www&lt;/code&gt; subdirectory of a &lt;a href="https://en.wikipedia.org/wiki/Shell_account"&gt;shell account&lt;/a&gt; provided to you by your local dialup internet service provider.&lt;/p&gt;

&lt;p&gt;Having a shell account affords you the ability to serve static HTML files, but during that era, if you wanted to generate dynamic content, like a &lt;a href="https://en.wikipedia.org/wiki/Web_counter"&gt;hit counter&lt;/a&gt; that records website visits or a guest book (the comments section of websites in worlds past), things were not so simple.&lt;/p&gt;

&lt;p&gt;In this article, we will take a look at CGI scripts, a technology of the early web that enabled software tinkerers to build simple (but useful) dynamic web apps.&lt;/p&gt;

&lt;h1&gt;
  
  
  CGI Scripts
&lt;/h1&gt;

&lt;p&gt;CGI stands for “Common Gateway Interface”. During the 90s, CGI scripts provided the most viable option for individuals wishing to host dynamically rendered server-side content. If you’ve never seen one in action before, take a look at this &lt;a href="http://rickcarlino.com/cgi-bin/hello.cgi"&gt;example script&lt;/a&gt; I wrote. It dynamically displays the current time and user agent to the visitor. The example script is written in Bash, although historically, most CGI scripts were written in Perl (&lt;a href="https://www.scriptarchive.com/"&gt;examples&lt;/a&gt;).&lt;/p&gt;

&lt;p&gt;The source code to my example script is below. If you’ve never written an HTTP request by hand, check out my article about &lt;a href="http://rickcarlino.com/2014/07/31/the-secret-lives-of-http-requests-html.html"&gt;HTTP request anatomy&lt;/a&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;#!/usr/bin/bash
echo "Content-type: text/html"
echo ""
echo '&amp;lt;html&amp;gt;'
echo ' &amp;lt;body&amp;gt;'
echo ' &amp;lt;p&amp;gt;The time is: '
# Prints current date/time to STDOUT:
date
echo ' &amp;lt;/p&amp;gt;'
echo ' &amp;lt;p&amp;gt;Your HTTP user agent is:'
# A CGI-enabled server will set this ENV var at runtime:
echo $HTTP_USER_AGENT
echo ' &amp;lt;/p&amp;gt;'
echo ' &amp;lt;/body&amp;gt;'
echo '&amp;lt;/html&amp;gt;'

exit 0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;As you can see in the example above, all writes to STDOUT were translated to an HTTP response. Some information (such as &lt;code&gt;$HTTP_USER_AGENT&lt;/code&gt; or &lt;code&gt;$QUERY_STRING&lt;/code&gt;) are provided by the server at runtime. By providing a simple means of input (ENV) and output (STDOUT), CGI scripts were a very powerful tool for early web developers, particularly hobbyists and small scale developers. All you needed was a programming language and a CGI-enabled web server.&lt;/p&gt;

&lt;p&gt;CGI scripts were often placed in a &lt;code&gt;cgi-bin&lt;/code&gt; directory. When the server received a request to a particular CGI script, it would &lt;em&gt;execute&lt;/em&gt; the script rather than serve its content.&lt;/p&gt;

&lt;p&gt;The practice was eventually formalized in &lt;a href="https://tools.ietf.org/html/rfc3875"&gt;RFC 3875&lt;/a&gt;. Many of the RFC’s collaborators were themselves authors of HTTP servers.&lt;/p&gt;

&lt;h1&gt;
  
  
  Like the Year 1996, All Things Come to Pass
&lt;/h1&gt;

&lt;p&gt;CGI scripting was undoubtedly useful and continues to be useful for small scale web applications, such as developer utilities, simple form data collection and local intranet tools.&lt;/p&gt;

&lt;p&gt;CGI scripts were not the right tool for every job and their obsolescence is the result of better alternatives. The “one process per request” model offered by CGI scripting suffered from a number of problems, most notably an I/O performance loss. A CGI application that uses a database must open a connection to the database once per request, which incurs connection overhead. Furthermore, a CGI script with 100 users will inevitably create 100 OS processes (possibly more if it is executing sub-commands).&lt;/p&gt;

&lt;p&gt;Another cause of CGI scripting’s demise was an inability to handle the complexity of large scale applications. Such problems were better handled by web development frameworks which arrived shortly after the CGI script.&lt;/p&gt;

&lt;p&gt;Additionally, since the server was directly executing the script, security issues could easily creep in (the script shares the permissions of the HTTP server).&lt;/p&gt;

&lt;p&gt;The inefficiencies of CGI scripts eventually led to the creation of more robust solutions such as &lt;a href="https://en.wikipedia.org/wiki/FastCGI"&gt;FCGI&lt;/a&gt;, &lt;a href="https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface"&gt;SCGI&lt;/a&gt;, numerous web frameworks and, more recently, “Function as a Service” platforms, which addressed many of the concerns listed while also adding additional features.&lt;/p&gt;

&lt;h1&gt;
  
  
  Links and Resources
&lt;/h1&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.oreilly.com/openbook/cgi/"&gt;CGI Programming on the World Wide Web, By Shishir Gundavaram, March 1996&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://tools.ietf.org/html/rfc3875"&gt;RFC 3875&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rickcarlino.com/2014/07/31/the-secret-lives-of-http-requests-html.html"&gt;HTTP Request Anatomy&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="http://rickcarlino.com/cgi-bin/hello.cgi"&gt;My Example Script (Above)&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Simple_Common_Gateway_Interface"&gt;Simple Gateway Common Interface&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.scriptarchive.com/"&gt;The Best CGI Script Archive Google Found&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Raspberry Pi Weather Station with Secure Scuttlebutt</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Sat, 06 Apr 2019 14:33:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/raspberry-pi-weather-station-with-secure-scuttlebutt-39f3</link>
      <guid>https://dev.to/rickcarlino/raspberry-pi-weather-station-with-secure-scuttlebutt-39f3</guid>
      <description>&lt;h1&gt;
  
  
  A Secure Scuttlebutt Weather Station
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://scuttlebot.io/more/protocols/secure-scuttlebutt.html"&gt;Secure Scuttlebutt&lt;/a&gt; is a replicating, peer-to-peer log database.&lt;/p&gt;

&lt;p&gt;It is unique because it is theoretically possible to create a mesh of replicating nodes that do not have internet access. Information is “gossiped” over local WiFi. When users move between wifi networks, the “gossip” moves with them, enabling friends (and friends-of-friends) to pass data along the social mesh. (See: &lt;a href="https://ssbc.github.io/scuttlebutt-protocol-guide/"&gt;SSB Protocol Guide&lt;/a&gt;)&lt;/p&gt;

&lt;p&gt;Currently, SSB is used for social apps that revolve around chat, microblogging and file sharing. The most popular apps are &lt;a href="https://github.com/ssbc/patchwork"&gt;Patchwork&lt;/a&gt; (desktop) and &lt;a href="https://www.manyver.se/"&gt;Manyverse&lt;/a&gt; (mobile), which can be thought of as peer-to-peer Twitter-analogs. SSB’s gossip makes it well suited for these types of apps.&lt;/p&gt;

&lt;p&gt;I have not yet seen SSB used for remote sensor networks, and I think it is a good use case for it, given the protocol’s delay tolerance and ability to store immutable log data.&lt;/p&gt;

&lt;p&gt;This month’s project creates a weather station that uses SSB as a replacement for internet connectivity. Weather logs are transmitted via data mule until they eventually find their way to a peer with internet connectivity, at which point the weather data reaches the global mesh of SSB users on the internet.&lt;/p&gt;

&lt;p&gt;To put that in more practical terms:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;An always-offline box in a remote location collects data.&lt;/li&gt;
&lt;li&gt;A data mule connects to the weather station’s internal wifi network while Manyverse (mobile SSB client) is open on the data mule’s mobile phone. The network is only a LAN- there is no internet access at the remote site.&lt;/li&gt;
&lt;li&gt;Within a few seconds, the weather station perform UDP peer discovery and exchange gossip.&lt;/li&gt;
&lt;li&gt;The data mule goes home.&lt;/li&gt;
&lt;li&gt;When the data mule connects to an internet-enabled wifi network at home, the data is gossiped to the wider SSB community (known as the “Scuttleverse”).&lt;/li&gt;
&lt;/ol&gt;

&lt;h1&gt;
  
  
  See It in Action
&lt;/h1&gt;

&lt;p&gt;If you want to see the weather logs for yourself, you can follow its identity on the Scuttlverse:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;@siAx0bQUNVIS3IH2d++o44atOzn8h7BuoULySDiKrHc=.ed25519

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MhPI8GGf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/weather_station/patchwork.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MhPI8GGf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/weather_station/patchwork.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ZqZaVU2P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/weather_station/enclosure.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ZqZaVU2P--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/weather_station/enclosure.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  How We Built It
&lt;/h1&gt;

&lt;p&gt;It’s a &lt;a href="https://github.com/FoxDotBuild/WeatherStation"&gt;custom NodeJS application&lt;/a&gt; with a few dependencies:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;node-dht-sensor&lt;/code&gt;: For reading an attached temperature sensor.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ssb-client&lt;/code&gt;: For writing to an append-only SSB feed.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The application reads the temperature once per day as well as at startup time. The reading is written to the machine’s SSB log so that it can be gossiped and replicated later.&lt;/p&gt;

&lt;h3&gt;
  
  
  Parts List
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Wooden case (custom built)&lt;/li&gt;
&lt;li&gt;DHT-22&lt;/li&gt;
&lt;li&gt;Realtime Clock&lt;/li&gt;
&lt;li&gt;Raspberry Pi 3 (the pi0 was too slow)&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/billz/raspap-webgui"&gt;RaspAP-GUI&lt;/a&gt; (to create a WiFi LAN for UDP peer discovery)&lt;/li&gt;
&lt;li&gt;USB battery pack&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Operation
&lt;/h3&gt;

&lt;p&gt;At startup, &lt;code&gt;systemd&lt;/code&gt; initiates two services:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;ssb-server&lt;/code&gt;, which provides an HTTP-based API for reading and writing to SSB feeds.&lt;/li&gt;
&lt;li&gt;The custom Node app detailed in the section above.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The services run in the background and poll for temperature updates at startup and once per 24 hour period.&lt;/p&gt;

&lt;p&gt;The full source code can be found &lt;a href="https://github.com/FoxDotBuild/WeatherStation"&gt;on Github&lt;/a&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Improvements
&lt;/h3&gt;

&lt;p&gt;This was a hobby project. Like all hobby projects, it is neither perfect nor optimized for real world conditions. If we were to spend more time on this project (we probably won’t), I would:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Use deep sleep to conserve battery&lt;/li&gt;
&lt;li&gt;Add a solar cell for better off-grid support (we placed it in a spot that had grid power)&lt;/li&gt;
&lt;li&gt;Automate the build process (currently, setup is a manual process)&lt;/li&gt;
&lt;li&gt;Build a viewer app instead of publishing messages as &lt;code&gt;"type": "post"&lt;/code&gt;. Some users view the weather reports as “noise” on Patchwork.&lt;/li&gt;
&lt;/ul&gt;

</description>
    </item>
    <item>
      <title>Vintage Computer Restoration, Part II</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Fri, 01 Mar 2019 14:00:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/vintage-computer-restoration-part-ii-2i4g</link>
      <guid>https://dev.to/rickcarlino/vintage-computer-restoration-part-ii-2i4g</guid>
      <description>&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QoDswaFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190216_161953.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QoDswaFC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190216_161953.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;In my last article, I set up serial file transfer between an ancient 386 desktop (running Windows 3.1) and a modern laptop running Xubuntu 18. Part I is &lt;a href="///2019/01/01/vintage-computer-restoration-part-i-html.html"&gt;available here&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once my 386 was &lt;a href="///2019/01/01/vintage-computer-restoration-part-i-html.html"&gt;accepting files from a host laptop&lt;/a&gt; I was ready to move forward with my goal of accessing the web.&lt;/p&gt;

&lt;p&gt;After installing the correct software packages (thanks, Internet Archive) I ran some network-based experiments on the machine. I ultimately met my goal of connecting to a public-facing server (HTTP and Telnet) while also learning a lot in the process. This was my first deep dive into the world of retro computing, and I had lots of fun!&lt;/p&gt;

&lt;p&gt;Below I will documents how I connected my 386 to a network.&lt;/p&gt;

&lt;h1&gt;
  
  
  Experiment I: Telnet/TCP
&lt;/h1&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JyVzgg_S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20181007_154127.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JyVzgg_S--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20181007_154127.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;When I started the project, I assumed that TCP network setup on older machines would be a challenge. To try things out quickly, I decided to pursue a less ambitious goal of piping a single TCP socket over a serial line. This would essentially turn my machine into a &lt;a href="https://en.wikipedia.org/wiki/Computer_terminal"&gt;terminal emulator&lt;/a&gt; and avoid the issue of Windows 3.x networking altogether.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3UQy3FUV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/serial.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3UQy3FUV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/serial.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;My setup was simple: on one end of a serial-to-USB cable, I had a modern Linux laptop. My 386 machine would sit on the other end of the cable and use the modern laptop as a proxy (mostly to avoid native TCP setup in Windows 3.x).&lt;/p&gt;

&lt;p&gt;To facilitate data transfer between the two machines, I used the popular &lt;a href="https://github.com/FozzTexx/tcpser"&gt;TCPSer&lt;/a&gt; application, which acts as a bridge between a TCP socket (Telnet) and a serial port.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--i44u135_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20181007_153053_HDR.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--i44u135_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20181007_153053_HDR.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The process was even simpler than I had anticipated. In the course of one afternoon, I was able to access several &lt;a href="https://en.wikipedia.org/wiki/Bulletin_board_system"&gt;BBS systems&lt;/a&gt; and even the &lt;a href="https://meta.wikimedia.org/wiki/Telnet_gateway"&gt;Telnet edition of Wikipedia&lt;/a&gt;. A thriving community of retro enthusiasts keep the BBS tradition alive and well, even in 2019.&lt;/p&gt;

&lt;p&gt;I won’t say too much more about the setup process, since there are plenty of good tutorials that already cover this topic.&lt;/p&gt;

&lt;h1&gt;
  
  
  Experiment II: A Serial-to-WiFi Adapter
&lt;/h1&gt;

&lt;p&gt;Another experiment I tried was connecting the serial port of my 386 to an &lt;a href="https://www.sparkfun.com/products/13678"&gt;ESP-8266&lt;/a&gt; microcontroller. This is essentially the same result as using TCPSer, but with a compact microcontroller instead of a full Linux desktop.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hc-8SqlN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190120_184006.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hc-8SqlN--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190120_184006.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The factory default ESP firmware has a number of &lt;a href="https://en.wikipedia.org/wiki/Hayes_command_set"&gt;Hayes compatible&lt;/a&gt; AT commands that allow users to open arbitrary TCP sockets and then read them over a TTL pin. By soldering a &lt;a href="https://www.amazon.com/NulSom-Inc-Ultra-Compact-Converter/dp/B00OPU2QJ4/ref=sr_1_1?keywords=max3232&amp;amp;qid=1551407183&amp;amp;s=gateway&amp;amp;sr=8-1"&gt;MAX-3232 board&lt;/a&gt; to an ESP, I was able to convert TTL signals to RS-232 and plug the ESP directly into the 386’s serial port, thereby eliminating the need for the host laptop mentioned in experiment I.&lt;/p&gt;

&lt;p&gt;The module quickly connected to my home WiFi and I was able to use the &lt;a href="https://room-15.github.io/blog/2015/03/26/esp8266-at-command-reference/"&gt;default ESP commands&lt;/a&gt; to open connections. I thought this process would be more involved, but it really was as simple as soldering a MAX-3232 to an ESP.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uJ2Z1Nxx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190302_175320.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uJ2Z1Nxx--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190302_175320.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fun fact:&lt;/strong&gt; I am fairly certain that the modem has better specs in terms of CPU, storage and memory than the desktop it is connected to.&lt;/p&gt;

&lt;h1&gt;
  
  
  Experiment III: A Full TCP Stack
&lt;/h1&gt;

&lt;p&gt;After connecting to BBSes and Telnet services over two different channels, I was ready for a more challenging task. My goal was to get a full-blown TCP stack running on Windows 3.1 so that I could do more than just BBSing. To do this, I made various attempts to “trick” my 386 into thinking the modern laptop on the other end of the serial cable was a modem.&lt;/p&gt;

&lt;p&gt;I found an interesting article within the &lt;a href="https://www.dreamcast-talk.com/forum/app.php/page/ryochanpart1"&gt;Sega Dreamcast&lt;/a&gt; community and even tinkered with the idea of writing a &lt;a href="https://github.com/RickCarlino/Dialup-Modem-Tools"&gt;custom script&lt;/a&gt; that could emulate a modem and dialup ISP. This turned out to be as difficult as anticipated. Due to a meager 4 megabyte memory limit, many of the browsers of the era would simply not load on the machine, citing a lack of memory. After failed attempts to load Netscape and Opera, I was ultimately able to install Internet Explorer 5. This came as a surprise to me, given the history of the three browsers.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BZkPTlfJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190302_171425.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BZkPTlfJ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190302_171425.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;After &lt;a href="https://retrocomputing.stackexchange.com/questions/9018/tcp-over-rs-232-with-windows-3-1-and-internet-explorer-5-dialer"&gt;consulting with the Internet&lt;/a&gt;, I installed Trumpet Winsock on the target and began the configuration process on the host machine (a modern laptop running Xubuntu 18). Trumpet Winsock is a popular software package that is used on Windows 3.1/Windows 95 machines.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the Host: SLIP and Serial
&lt;/h2&gt;

&lt;p&gt;As mentioned in &lt;a href="///2019/01/01/vintage-computer-restoration-part-i-html.html"&gt;part I&lt;/a&gt;, the physical layer between the two machines was a USB-to-serial adapter. Nothing new there.&lt;/p&gt;

&lt;p&gt;For the data link layer, I chose &lt;a href="https://en.wikipedia.org/wiki/Serial_Line_Internet_Protocol"&gt;SLIP&lt;/a&gt;, because I did not have the patience to deal with the more advanced &lt;a href="https://en.wikipedia.org/wiki/Point-to-Point_Protocol"&gt;PPP&lt;/a&gt; protocol. Although not as elegant as PPP, it proved to be easier to manage and was well supported by Trumpet.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--TtqMiYfm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190214_204425.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--TtqMiYfm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190214_204425.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;To create a link between the two machines, I used &lt;a href="https://linux.die.net/man/8/slattach"&gt;slattach&lt;/a&gt; on the Linux side of the link. &lt;code&gt;slattach&lt;/code&gt; is a tool that puts a standard serial line into “network mode” (SLIP, in my case):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;slattach -s 19200 -p slip -d /dev/ttyUSB0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The flags were as follows:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Flag&lt;/th&gt;
&lt;th&gt;Meaning&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-s 19200&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Speed / baud rate (my machine could not handle data faster than 19200 baud)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-p slip&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Sets the line protocol to &lt;code&gt;slip&lt;/code&gt;, as opposed to &lt;code&gt;cslip&lt;/code&gt; or &lt;code&gt;ppp&lt;/code&gt;.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;-d&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Enable debug output.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;With my serial line configured for SLIP, I was ready to move up the network stack and begin IP configuration.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the Host: IP Tables
&lt;/h2&gt;

&lt;p&gt;Once &lt;code&gt;slattach&lt;/code&gt; is called, you can verify connectivity by running &lt;code&gt;ifconfig sl0&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;
sl0: flags=4240&amp;lt;POINTOPOINT,NOARP,MULTICAST&amp;gt; mtu 296
        slip txqueuelen 10 (Serial Line IP)
        RX packets 0 bytes 0 (0.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;slattach&lt;/code&gt; has created the appropriate network interface, but we still need to configure the network interface and bring it up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo ifconfig sl0 192.168.5.1 netmask 255.255.255.0 up

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;In my case, &lt;code&gt;192.168.5.1&lt;/code&gt; was not in use. Your local network may differ.&lt;/p&gt;

&lt;p&gt;To verify that everything worked, I ran &lt;code&gt;ifconfig sl0&lt;/code&gt; again:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sl0: flags=4305&amp;lt;UP,POINTOPOINT,RUNNING,NOARP,MULTICAST&amp;gt; mtu 296
        inet 192.168.5.1 netmask 255.255.255.0 destination 192.168.5.1
        slip txqueuelen 10 (Serial Line IP)
        RX packets 0 bytes 0 (0.0 B)
        RX errors 0 dropped 0 overruns 0 frame 0
        TX packets 0 bytes 0 (0.0 B)
        TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;My Linux laptop could now transfer IP packets over the serial line.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring Trumpet
&lt;/h2&gt;

&lt;p&gt;Now that the host laptop has SLIP and network interfaces configured, I needed to setup Trumpet.&lt;/p&gt;

&lt;p&gt;Trumpet is a popular shareware TCP stack for Windows in the mid 90s. Be advised that if you plan on using this software for more than thirty days, you must &lt;a href="http://www.trumpet.com.au/"&gt;purchase a license from the author&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;I used the following configuration values:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Setting&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;IP Address&lt;/td&gt;
&lt;td&gt;I used &lt;code&gt;192.168.5.2&lt;/code&gt;, but your IP address availability may differ&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Netmask&lt;/td&gt;
&lt;td&gt;&lt;code&gt;255.255.255.0&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nameserver&lt;/td&gt;
&lt;td&gt;You can use &lt;code&gt;8.8.8.8&lt;/code&gt; if you are unsure. I noticed increased latency compared to my ISPs nameserver.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;It is also important to &lt;strong&gt;ensure you are not using PPP&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;Once properly configured, you should be able to run &lt;code&gt;ping&lt;/code&gt; on either end of the network and get a response. Just for fun, I ran a small HTTP server to see if IE5 would load it (it did):&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hUobdc8K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190216_163441.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hUobdc8K--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190216_163441.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;At this point, I am able to send TCP packets between the two machines, but I do not have access to the internet. To contact the outside world, I need to set up &lt;a href="https://en.wikipedia.org/wiki/Network_address_translation"&gt;network address translation&lt;/a&gt;, which is how the 386 packets will travel to the outside world with my laptop acting as an intermediary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Configuring the Host (Again)
&lt;/h2&gt;

&lt;p&gt;Before proceeding, be sure to enable kernel level IP forwarding on the host:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;sudo bash -c "echo 1 &amp;gt; /proc/sys/net/ipv4/ip_forward"

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You will need to run the command above on every boot.&lt;/p&gt;

&lt;p&gt;After that, you will need to run &lt;code&gt;iptables&lt;/code&gt; to route outbound traffic. In my case, the outbound network interface was &lt;code&gt;wlp1s0&lt;/code&gt;, but yours may be different (especially if you use ethernet instead of WiFi).&lt;/p&gt;

&lt;p&gt;You can determine your outbound network interface by running &lt;code&gt;ifconfig&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Change the value of `wlp1s0` to the correct interface!!
sudo iptables --table nat --append POSTROUTING --out-interface wlp1s0 -j MASQUERADE
sudo iptables --append FORWARD --in-interface sl0 -j ACCEPT

&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I could now surf the web!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s---Ll5XDOD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190302_183131.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s---Ll5XDOD--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386_ii/20190302_183131.jpg" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  What I Learned
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Fun fact:&lt;/strong&gt; Although the SLIP protocol does not have a formal IETF standard, it &lt;em&gt;does&lt;/em&gt; have &lt;a href="https://tools.ietf.org/html/rfc1055"&gt;a formal nonstandard&lt;/a&gt; that is comprised of a few lines of C code.&lt;/p&gt;

&lt;p&gt;Although I did not have time to meet my stretch goal of running a web server on the target device, I did have fun revisiting the technology of my childhood. I was able to refresh my memory on many topics that I don’t see day-to-day (such as &lt;code&gt;SLIP&lt;/code&gt;, &lt;code&gt;iptables&lt;/code&gt;, &lt;code&gt;xmodem&lt;/code&gt; and layers 1 and 2 of the OSI model). I also saw an exaggerated perspective of bloat on the modern web. Popular websites such as Google were nearly unusable. Uncompressed images that load quickly on modern devices could take up to 10 minutes to load on a constrained device.&lt;/p&gt;

&lt;p&gt;On the flip side of the spectrum, there are still some websites out there (such as &lt;a href="///2018/07/11/fabulous-text-only-websites-2018-edition-html.html"&gt;these&lt;/a&gt;) that performed surprisingly well. &lt;a href="http://tldp.org/"&gt;TLDP.org&lt;/a&gt; loaded quickly and rendered in a nearly identical fashion to the modern host machine.&lt;/p&gt;

</description>
    </item>
    <item>
      <title>Vintage Computer Restoration, Part I</title>
      <dc:creator>Rick Carlino</dc:creator>
      <pubDate>Tue, 01 Jan 2019 14:00:00 +0000</pubDate>
      <link>https://dev.to/rickcarlino/vintage-computer-restoration-part-i-4ndf</link>
      <guid>https://dev.to/rickcarlino/vintage-computer-restoration-part-i-4ndf</guid>
      <description>&lt;center&gt;
&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JaaX0p3G--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_66%2Cw_880/https://rickcarlino.com/images/2019/386/collage.gif" alt=""&gt;&lt;br&gt;
&lt;/center&gt;

&lt;p&gt;I attended &lt;a href="http://vcfmw.org/"&gt;Vintage Computer Festival Midwest&lt;/a&gt; late last year. I purchased a functioning &lt;a href="https://en.wikipedia.org/wiki/Intel_80386"&gt;386-based&lt;/a&gt; workstation running Windows 3.1 for $80 USD. The blog articles that follow will document my attempts to get it back on the internet.&lt;/p&gt;

&lt;p&gt;Windows 3.1 has a special place in my heart. It was my first operating system. As a child in the mid 90s, it was also my first means of accessing the internet (via &lt;a href="https://en.wikipedia.org/wiki/CompuServe"&gt;Compuserve&lt;/a&gt; and later, AOL).&lt;/p&gt;

&lt;p&gt;Judging by filesystem dates, the computer operated from 1994 to 1997.&lt;/p&gt;

&lt;h2&gt;
  
  
  Specs and Hardware
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Intel i386 @ 25 Mhz&lt;/li&gt;
&lt;li&gt;4 Megabytes of &lt;a href="https://en.wikipedia.org/wiki/SIPP_memory"&gt;SIPP Memory&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;120 MB hard drive&lt;/li&gt;
&lt;li&gt;VGA Monitor complete with gigantic video card&lt;/li&gt;
&lt;li&gt;Serial Mouse (predates &lt;a href="https://en.wikipedia.org/wiki/PS/2_port"&gt;PS/2&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/IBM_PC_keyboard"&gt;AT Keyboard&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://en.wikipedia.org/wiki/Floppy_disk"&gt;3.5 Inch Floppy&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The device is constrained. In 2019, even some microcontrollers are able to out perform this machine.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0NYiJoly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/specs.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0NYiJoly--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/specs.png" alt=""&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h1&gt;
  
  
  Project Goals
&lt;/h1&gt;

&lt;p&gt;My intent for this project is to “make a 386 do things” and document my progress in a way that helps other retrocomputing enthusiasts. Here are some of the things I hope to accomplish:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal 1 (DONE):&lt;/strong&gt; Get file transfer with my (modern) laptop via any means. This probably means via USB Floppy drive, or serial cable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal 2 (DONE):&lt;/strong&gt; Get it talking to a public-facing network.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Goal 3 (IN PROGRESS):&lt;/strong&gt; Get it online and browse the &lt;a href="http://rickcarlino.com/2018/07/11/fabulous-text-only-websites-2018-edition-html.html"&gt;text-based Web&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stretch Goal:&lt;/strong&gt; Run a public facing server on it for comedic effect. HTTP would be fun, although I may settle for an easier target (such as telnet) if the task turns out to be too ambitious.&lt;/p&gt;


&lt;center&gt;
&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--NgEYEM6n--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/fiddling.png" alt="Cleaning the case and reseting the BIOS with Michael Christenson"&gt;&lt;br&gt;
&lt;/center&gt;
&lt;h1&gt;
  
  
  Why?
&lt;/h1&gt;

&lt;p&gt;Why not?&lt;/p&gt;

&lt;h1&gt;
  
  
  Data Transfer Attempt I: Sneakernet
&lt;/h1&gt;


&lt;center&gt;
&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yfvT42Xq--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/floppy.jpg" alt=""&gt;&lt;br&gt;
&lt;/center&gt;

&lt;p&gt;Despite the excitement of Windows 3.1 classics like Solitaire and Minesweeper, I can’t accomplish much on a clean install of Windows 3.1. I need to get software on it somehow. I had a USB floppy drive and a case of floppies I found from a local thrift store.&lt;/p&gt;

&lt;p&gt;This seemed like the easiest way to make progress. I could download classic Windows software from &lt;a href="https://archive.org/details/software"&gt;The Internet Archive Software Collection&lt;/a&gt;, store them to disk via USB floppy drive (on my laptop) and then manually load them on to the Windows 3.1 machine.&lt;/p&gt;

&lt;p&gt;The sneakernet approach presented challenges, however:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Many titles required more than 1.44 MB of storage space and the machine does not have a CD-ROM drive (yet).&lt;/li&gt;
&lt;li&gt;My floppy disk collection had data integrity issues. Some files appeared to write to disk fine, but were unreadable afterward.&lt;/li&gt;
&lt;li&gt;Linux support for USB floppy drives in 2019 is not great. I would hit strange issues, such as drives refusing to mount, endlessly spinning discs and botched system shutdowns whenever the drive was attached. Such errors happened sporadically without warning.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;I was able to get a few notable titles (like &lt;a href="https://classicreload.com/win3x-skifree.html"&gt;SkiFree&lt;/a&gt;) loaded but it proved to be inconvenient. Although I probably could have split files on my laptop and then reassemble them on the host via &lt;code&gt;pkzip&lt;/code&gt; or similar tools, I decided to search for more convenient file transfer methods.&lt;/p&gt;

&lt;h1&gt;
  
  
  Data Transfer Attempt II: Serial Line Transfer
&lt;/h1&gt;

&lt;p&gt;In the bad old days of home computing, when wide area networks were less ubiquitous and &lt;code&gt;&amp;lt;font/&amp;gt;&lt;/code&gt; tags roamed free, users could transfer data between computers via &lt;a href="https://en.wikipedia.org/wiki/RS-232"&gt;RS-232&lt;/a&gt; lines. Simple transfer protocols such as &lt;a href="https://en.wikipedia.org/wiki/XMODEM"&gt;XMODEM&lt;/a&gt; made such transfers possible. The process was as simple as plugging two computers together with a serial cable. Despite their simplicity, the protocols and transport layers were incredibly slow.&lt;/p&gt;


&lt;center&gt;
&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3UQy3FUV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://rickcarlino.com/images/2019/386/serial.jpg" alt=""&gt;&lt;br&gt;
&lt;/center&gt;

&lt;p&gt;The first problem to tackle was purchasing an RS-232-to-USB adapter, since my laptop (and pretty much every computer sold during this millennium) does not come with an RS-232 port.&lt;/p&gt;

&lt;p&gt;After purchasing an adapter on Amazon, I realized that many of the models sold require a male-to-female USB extender, which required a second set of online purchases.&lt;/p&gt;

&lt;p&gt;Another inconvenience was that the machine had a single serial port. This meant I could use a mouse or perform data transfers, but not simultaneously. Since serial mice are not hot swappable on Windows 3.1, switching from “mouse mode” to “file transfer mode” required a full reboot of my machine. Not to be deterred, I spent some time re-learning Windows 3.1 keyboard shortcuts and was ready to configure a software toolchain for data transfers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;File Transfer Incantation&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Now that I had all the required cables and adapters, I was ready to configure the software. The main tools I used were:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;GNU &lt;code&gt;screen&lt;/code&gt;: Opens a serial port on the Linux side.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sx&lt;/code&gt;: “Send XModem”. A *nix tool for doing XModem transfers&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;terminal.exe&lt;/code&gt;: Used for opening serial (COM) ports on Windows 3.1 (&lt;a href="https://guidebookgallery.org/screenshots/win31"&gt;screenshot&lt;/a&gt;).&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;To open a serial port and begin a serial transfer, I performed the following incantation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;code&gt;screen /dev/ttyUSB0 9600&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;ctrl + a&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Type &lt;code&gt;:&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Enter &lt;code&gt;sx -b FILE_RELATIVE_PATH_GOES_HERE&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Click &lt;code&gt;Transfers =&amp;gt; Begin Binary Tranfer&lt;/code&gt; in Windows 3.1 &lt;code&gt;terminal.exe&lt;/code&gt;
&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This quickly became a tedious task. I ultimately &lt;a href="https://github.com/RickCarlino/Dialup-Modem-Tools#x-modem"&gt;wrote a custom Ruby script to automate the process&lt;/a&gt; and reduce the number of steps from 5 to 1.&lt;/p&gt;

&lt;h1&gt;
  
  
  What’s Next?
&lt;/h1&gt;

&lt;p&gt;My Windows 3.1 machine is healthy, happy and transferring files from the Internet Archive to disk.&lt;/p&gt;

&lt;p&gt;In my next post, I will talk about opening TCP sockets for fun things like viewing the &lt;a href="https://meta.wikimedia.org/wiki/Telnet_gateway"&gt;Wikipedia Telnet Gateway&lt;/a&gt; and my ongoing struggles to get HTTP access on Internet Explorer 5.&lt;/p&gt;

&lt;p&gt;If you were a computer user during this era and wish to share advice with me, please contact me via Reddit or Lobste.rs.&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
