/*
Yún Shield Disk Space Expander
Requirements:
* Arduino Board
* Dragino Yun Shield
* USB Stick
* internet connection
This sketch configure the USB Stick to expand the disk space
of the Yún Shield. Upload, open the Console Monitor and follow
the interactive procedure.
Warning: your USB Stick will be formatted and you will lose
the files it contains. Be sure you have backed it up before
using it for expanding Yún’s Shield disk space.
created Apr 2014
by Federico Fissore & Federico Vanzati
>> modded by HandyFreak Okt 2014 for DraginoYun Shield
This code without any responsibility of damages or errors, successfully tested by me with Mega 2560.
*/
#include <Process.h>
#include <Console.h> //Console class provide the interactive between IDE and Yun Shield
#define DEBUG 0
#define SUCCESSFUL_EXIT_CODE 0
void setup() {
Bridge.begin();
Console.begin();
while (!Console);
Console.print(F("This sketch will format your USB Stick and use it as additional disk space for your Arduino Yun.\nPlease ensure you have ONLY one USB-Stick plugged in: no other drives, hard drives or whatever.\nDo you wish to proceed (yes/no)?"));
expectYesBeforeProceeding();
Console.println(F("\nStarting Bridge..."));
haltIfSDAlreadyOnOverlay();
haltIfInternalFlashIsFull();
haltIfSDCardIsNotPresent();
installSoftware();
partitionAndFormatSDCard();
createArduinoFolder();
copySystemFilesFromYunToSD();
enableExtRoot();
Console.print(F("\nWe are done! Yeah! Now reconnect to power to apply the changes."));
}
void loop() {
// This turns the sketch into a YunSerialTerminal
if (Console.available()) {
char c = (char)Console.read();
Serial1.write(c);
}
if (Serial1.available()) {
char c = (char)Serial1.read();
Console.write(c);
}
}
void halt() {
Console.flush();
while (true);
}
void expectYesBeforeProceeding() {
Console.flush();
while (!Console.available());
String answer = Console.readStringUntil('\n');
Console.print(F(" "));
Console.println(answer);
if (answer != "yes") {
Console.println(F("\nGoodbye"));
halt();
}
}
int readPartitionSize() {
int partitionSize = 0;
while (!partitionSize)
{
Console.print(F("Enter the size of the data partition in MB: "));
while (Console.available() == 0);
String answer = Console.readStringUntil('\n');
partitionSize = answer.toInt();
Console.println(partitionSize);
if (!partitionSize)
Console.println(F("Invalid input, retry"));
}
return partitionSize;
}
void debugProcess(Process p) {
#if DEBUG == 1
while (p.running());
while (p.available() > 0) {
char c = p.read();
Console.print(c);
}
Console.flush();
#endif
}
void haltIfSDAlreadyOnOverlay() {
Process grep;
grep.runShellCommand(F("mount | grep ^/dev/sda | grep 'on /overlay'"));
String output = grep.readString();
if (output != "") {
Console.println(F("\nMicro SD card is already used as additional Arduino Yun disk space. Nothing to do."));
halt();
}
}
void haltIfSDCardIsNotPresent() {
Process ls;
int exitCode = ls.runShellCommand("ls /mnt/sda1");
if (exitCode != 0) {
Console.println(F("\nThe USB Stick is not available"));
halt();
}
}
void haltIfInternalFlashIsFull() {
Process awk;
awk.runShellCommand(F("df / | awk '/rootfs/ {print $4}'"));
int output = awk.parseInt();
if (output < 1000) {
Console.println(F("\nYou don't have enough disk space to install the utility software. You need to free at least 1MB of Flash memory.\nRetry!"));
halt();
}
}
void installSoftware() {
Console.print(F("\nReady to install utility software. Please ensure your Arduino Yun is connected to internet.\nReady to proceed (yes/no)?"));
expectYesBeforeProceeding();
Console.println(F("Updating software list..."));
Process opkg;
// update the packages list
int exitCode = opkg.runShellCommand("opkg update");
// if the exitCode of the process is OK the package has been installed correctly
if (exitCode != SUCCESSFUL_EXIT_CODE) {
Console.println(F("err. with opkg, check internet connection"));
debugProcess(opkg);
halt();
}
Console.println(F("Software list updated. Installing software (this will take a while)..."));
// install the utility to format in EXT4
exitCode = opkg.runShellCommand(F("opkg install e2fsprogs mkdosfs fdisk rsync"));
if (exitCode != SUCCESSFUL_EXIT_CODE) {
Console.println(F("err. installing e2fsprogs mkdosfs fdisk"));
debugProcess(opkg);
halt();
}
Console.println(F("e2fsprogs mkdosfs fdisk rsync installed"));
}
void partitionAndFormatSDCard() {
Console.print(F("\nProceed with partitioning USB Stick (yes/no)?"));
expectYesBeforeProceeding();
unmount();
Process format;
//clears partition table
format.runShellCommand("dd if=/dev/zero of=/dev/sda bs=4096 count=10");
debugProcess(format);
// create the first partition
int dataPartitionSize = readPartitionSize();
Console.println(F("Partitioning (this will take a while)..."));
String firstPartition = "(echo n; echo p; echo 1; echo; echo +";
firstPartition += dataPartitionSize;
firstPartition += "M; echo w) | fdisk /dev/sda";
format.runShellCommand(firstPartition);
debugProcess(format);
unmount();
// create the second partition
format.runShellCommand(F("(echo n; echo p; echo 2; echo; echo; echo w) | fdisk /dev/sda"));
debugProcess(format);
unmount();
// specify first partition is FAT32
format.runShellCommand(F("(echo t; echo 1; echo c; echo w) | fdisk /dev/sda"));
unmount();
delay(5000);
unmount();
// format the first partition to FAT32
int exitCode = format.runShellCommand(F("mkfs.vfat /dev/sda1"));
debugProcess(format);
if (exitCode != SUCCESSFUL_EXIT_CODE) {
Console.println(F("\nerr. formatting to FAT32"));
halt();
}
delay(100);
// format the second partition to Linux EXT4
exitCode = format.runShellCommand(F("mkfs.ext4 /dev/sda2"));
debugProcess(format);
if (exitCode != SUCCESSFUL_EXIT_CODE) {
Console.println(F("\nerr. formatting to EXT4"));
halt();
}
Console.println(F("USB Stick correctly partitioned"));
}
void createArduinoFolder() {
Console.print(F("\nCreating 'arduino' folder structure..."));
Process folder;
folder.runShellCommand(F("mkdir -p /mnt/sda1"));
folder.runShellCommand(F("mount /dev/sda1 /mnt/sda1"));
folder.runShellCommand(F("mkdir -p /mnt/sda1/arduino/www"));
unmount();
}
void copySystemFilesFromYunToSD() {
Console.print(F("\nCopying files from Arduino Yun flash to USB Stick..."));
Process copy;
copy.runShellCommand(F("mkdir -p /mnt/sda2"));
copy.runShellCommand(F("mount /dev/sda2 /mnt/sda2"));
copy.runShellCommand(F("rsync -a --exclude=/mnt/ --exclude=/www/sd /overlay/ /mnt/sda2/"));
unmount();
}
void unmount() {
Process format;
format.runShellCommand(F("umount /dev/sda?"));
debugProcess(format);
format.runShellCommand(F("rm -rf /mnt/sda?"));
debugProcess(format);
}
void enableExtRoot() {
Console.print(F("\nEnabling USB Stick as additional disk space... "));
Process fstab;
fstab.runShellCommand(F("uci add fstab mount"));
fstab.runShellCommand(F("uci set fstab.@mount[0].target=/overlay"));
fstab.runShellCommand(F("uci set fstab.@mount[0].device=/dev/sda2"));
fstab.runShellCommand(F("uci set fstab.@mount[0].fstype=ext4"));
fstab.runShellCommand(F("uci set fstab.@mount[0].enabled=1"));
fstab.runShellCommand(F("uci set fstab.@mount[0].enabled_fsck=0"));
fstab.runShellCommand(F("uci set fstab.@mount[0].options=rw,sync,noatime,nodiratime"));
fstab.runShellCommand(F("uci commit"));
Console.println(F("enabled"));
}
I tried this with the Dragino Yun shield that I have. It did not work correctly. The partitions were created and the files copied. However, upon the restart, the flash drive was not mounted. It appears the flash drive (/dev/sda) was not detected and mounted. I have the latest version of the Dragino OpenWrt. I am using version Dragino-V2 common-1.3.5 of OpenWrt. I suspect the problem is related to the version.
I just wanted to say, thank you very much for this tutorial. I now have three Yun Shields running well with expanded memory.
I would like to share one issue that I ran into, not with the tutorial, but with SanDisk Cruzer Fit Flash Drives.
I got the memory expanded on first of my Yun Shields working great on a 16BG SanDisk Cruzer Fit. Then I started on the second Yun Shield and never could get the YunShieldDiskExpander sketch to recognize another 16GB SanDisk drive. The two disks were the same as far as I could tell, but I kept getting the error "The USB Stick is not available." What I eventually did was ssh into the Yun Shield and look at /etc/mcat to see how the SanDisk drive was mounted. I discovered that it was not mounted even though it was in the USB slot. So haltIfSDCardIsNotPresent() could not get a positive comeback on 'ls /mnt/sda1.'
I then mounted it in one of my debian boxes and discovered that it mounted as /dev/sde2. not /dev/sde1. What I eventually discovered was that there was some type of Novel file system installed on the sde1 partition. I had to dd zeros to the SanDisk drive to get rid of the Novel garbage and the first partition. Once I zeroed it, I could build a new partition and format it Fat32. Then it mounted properly on the YunShield and everything went smoothly for expanding memory.
The third Yun Shield and another 16GB SanDisk worked perfectly with no embedded Novel partition.
Just thought I would pass on my experience and solution.
I'm getting these errors (shown below) after running the code provided by handyfreak. I saved the file inside Documents/Arduino/libraries before attempting to upload. Also using Mega 2560 and Yun Shield. Can someone please help me...
Arduino: 1.6.5 (Windows 8.1), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"
avr-gcc: error: C:\Users\Nyasha\AppData\Local\Temp\build2142350526624292970.tmp/core.a: No such file or directory
Error compiling.
This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
zeeHacker:
I'm getting these errors (shown below) after running the code provided by handyfreak. I saved the file inside Documents/Arduino/libraries before attempting to upload. Also using Mega 2560 and Yun Shield. Can someone please help me...
Arduino: 1.6.5 (Windows 8.1), Board: "Arduino/Genuino Mega or Mega 2560, ATmega2560 (Mega 2560)"
avr-gcc: error: C:\Users\Nyasha\AppData\Local\Temp\build2142350526624292970.tmp/core.a: No such file or directory
Error compiling.
This report would have more information with
"Show verbose output during compilation"
enabled in File > Preferences.
So I finally managed to fix that issue... what I did was, I navigated to the Temp directory and found out that the .tmp file was not there. Was running IDE 1.6.5 so I uninstalled it and installed the latest 1.6.8. After that I tried uploading again and what do u know...it worked!
But... After upgrading to the latest OpenWRT firmware using instructions from the link below, I found out that my memory had shrank back to the original hardware size. After redoing the steps again I get interesting messages from the serial monitor (says unable to connect blah blah blah). See image attachment below. Please help. http://twilioinc.wpengine.com/2015/02/arduino-wifi-getting-started-arduino-yun.html
It worked perfectly for me, although I hacked the original sketch my way. I also bricked an UNO by sccidentally loading a YUN bootlader into it but I think I can recover it later by flashing the correct one
Anyway thanks again for taking the time to publish this.